1 | /* |
2 | * Copyright 2013-present Facebook, Inc. |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at |
7 | * |
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | * |
10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. |
15 | */ |
16 | |
17 | #include <folly/File.h> |
18 | |
19 | #include <folly/String.h> |
20 | #include <folly/portability/Fcntl.h> |
21 | #include <folly/portability/GTest.h> |
22 | |
23 | using namespace folly; |
24 | |
25 | namespace { |
26 | void expectWouldBlock(ssize_t r) { |
27 | int savedErrno = errno; |
28 | EXPECT_EQ(-1, r); |
29 | EXPECT_EQ(EAGAIN, savedErrno) << errnoStr(savedErrno); |
30 | } |
31 | void expectOK(ssize_t r) { |
32 | int savedErrno = errno; |
33 | EXPECT_LE(0, r) << ": errno=" << errnoStr(savedErrno); |
34 | } |
35 | } // namespace |
36 | |
37 | TEST(File, Simple) { |
38 | // Open a file, ensure it's indeed open for reading |
39 | char buf = 'x'; |
40 | { |
41 | File f("/etc/hosts" ); |
42 | EXPECT_NE(-1, f.fd()); |
43 | EXPECT_EQ(1, ::read(f.fd(), &buf, 1)); |
44 | f.close(); |
45 | EXPECT_EQ(-1, f.fd()); |
46 | } |
47 | } |
48 | |
49 | TEST(File, SimpleStringPiece) { |
50 | char buf = 'x'; |
51 | File f(StringPiece("/etc/hosts" )); |
52 | EXPECT_NE(-1, f.fd()); |
53 | EXPECT_EQ(1, ::read(f.fd(), &buf, 1)); |
54 | f.close(); |
55 | EXPECT_EQ(-1, f.fd()); |
56 | } |
57 | |
58 | TEST(File, OwnsFd) { |
59 | // Wrap a file descriptor, make sure that ownsFd works |
60 | // We'll test that the file descriptor is closed by closing the writing |
61 | // end of a pipe and making sure that a non-blocking read from the reading |
62 | // end returns 0. |
63 | |
64 | char buf = 'x'; |
65 | int p[2]; |
66 | expectOK(::pipe(p)); |
67 | int flags = ::fcntl(p[0], F_GETFL); |
68 | expectOK(flags); |
69 | expectOK(::fcntl(p[0], F_SETFL, flags | O_NONBLOCK)); |
70 | expectWouldBlock(::read(p[0], &buf, 1)); |
71 | { |
72 | File f(p[1]); |
73 | EXPECT_EQ(p[1], f.fd()); |
74 | } |
75 | // Ensure that moving the file doesn't close it |
76 | { |
77 | File f(p[1]); |
78 | EXPECT_EQ(p[1], f.fd()); |
79 | File f1(std::move(f)); |
80 | EXPECT_EQ(-1, f.fd()); |
81 | EXPECT_EQ(p[1], f1.fd()); |
82 | } |
83 | expectWouldBlock(::read(p[0], &buf, 1)); // not closed |
84 | { |
85 | File f(p[1], true); |
86 | EXPECT_EQ(p[1], f.fd()); |
87 | } |
88 | ssize_t r = ::read(p[0], &buf, 1); // eof |
89 | expectOK(r); |
90 | EXPECT_EQ(0, r); |
91 | ::close(p[0]); |
92 | } |
93 | |
94 | TEST(File, Release) { |
95 | File in(STDOUT_FILENO, false); |
96 | CHECK_EQ(STDOUT_FILENO, in.release()); |
97 | CHECK_EQ(-1, in.release()); |
98 | } |
99 | |
100 | #define EXPECT_CONTAINS(haystack, needle) \ |
101 | EXPECT_NE(::std::string::npos, ::folly::StringPiece(haystack).find(needle)) \ |
102 | << "Haystack: '" << haystack << "'\nNeedle: '" << needle << "'"; |
103 | |
104 | TEST(File, UsefulError) { |
105 | try { |
106 | File("does_not_exist.txt" , 0, 0666); |
107 | } catch (const std::runtime_error& e) { |
108 | EXPECT_CONTAINS(e.what(), "does_not_exist.txt" ); |
109 | EXPECT_CONTAINS(e.what(), "0666" ); |
110 | } |
111 | } |
112 | |
113 | TEST(File, Truthy) { |
114 | File temp = File::temporary(); |
115 | |
116 | EXPECT_TRUE(bool(temp)); |
117 | |
118 | if (temp) { |
119 | ; |
120 | } else { |
121 | ADD_FAILURE(); |
122 | } |
123 | |
124 | if (File file = File::temporary()) { |
125 | ; |
126 | } else { |
127 | ADD_FAILURE(); |
128 | } |
129 | |
130 | EXPECT_FALSE(bool(File())); |
131 | if (File()) { |
132 | ADD_FAILURE(); |
133 | } |
134 | if (File notOpened = File()) { |
135 | ADD_FAILURE(); |
136 | } |
137 | } |
138 | |
139 | TEST(File, HelperCtor) { |
140 | File::makeFile(StringPiece("/etc/hosts" )).then([](File&& f) { |
141 | char buf = 'x'; |
142 | EXPECT_NE(-1, f.fd()); |
143 | EXPECT_EQ(1, ::read(f.fd(), &buf, 1)); |
144 | f.close(); |
145 | EXPECT_EQ(-1, f.fd()); |
146 | }); |
147 | } |
148 | |