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
23using namespace folly;
24
25namespace {
26void expectWouldBlock(ssize_t r) {
27 int savedErrno = errno;
28 EXPECT_EQ(-1, r);
29 EXPECT_EQ(EAGAIN, savedErrno) << errnoStr(savedErrno);
30}
31void expectOK(ssize_t r) {
32 int savedErrno = errno;
33 EXPECT_LE(0, r) << ": errno=" << errnoStr(savedErrno);
34}
35} // namespace
36
37TEST(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
49TEST(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
58TEST(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
94TEST(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
104TEST(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
113TEST(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
139TEST(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