1/*
2 * Copyright 2012-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/experimental/TestUtil.h>
18
19#include <system_error>
20
21#include <boost/algorithm/string.hpp>
22#include <glog/logging.h>
23
24#include <folly/Memory.h>
25#include <folly/portability/Fcntl.h>
26#include <folly/portability/GTest.h>
27#include <folly/portability/Stdlib.h>
28
29using namespace folly;
30using namespace folly::test;
31
32TEST(TemporaryFile, Simple) {
33 int fd = -1;
34 char c = 'x';
35 {
36 TemporaryFile f;
37 EXPECT_FALSE(f.path().empty());
38 EXPECT_TRUE(f.path().is_absolute());
39 fd = f.fd();
40 EXPECT_LE(0, fd);
41 ssize_t r = write(fd, &c, 1);
42 EXPECT_EQ(1, r);
43 }
44
45 msvcSuppressAbortOnInvalidParams([&] {
46 // The file must have been closed. This assumes that no other thread
47 // has opened another file in the meanwhile, which is a sane assumption
48 // to make in this test.
49 ssize_t r = write(fd, &c, 1);
50 int savedErrno = errno;
51 EXPECT_EQ(-1, r);
52 EXPECT_EQ(EBADF, savedErrno);
53 });
54}
55
56TEST(TemporaryFile, EarlyClose) {
57 fs::path p;
58 {
59 TemporaryFile f;
60 p = f.path();
61 EXPECT_TRUE(fs::exists(p));
62 f.close();
63 EXPECT_EQ(-1, f.fd());
64 EXPECT_TRUE(fs::exists(p));
65 }
66 EXPECT_FALSE(fs::exists(p));
67}
68
69TEST(TemporaryFile, Prefix) {
70 TemporaryFile f("Foo");
71 EXPECT_TRUE(f.path().is_absolute());
72 EXPECT_TRUE(
73 boost::algorithm::starts_with(f.path().filename().native(), "Foo"));
74}
75
76TEST(TemporaryFile, PathPrefix) {
77 TemporaryFile f("Foo", ".");
78 EXPECT_EQ(fs::path("."), f.path().parent_path());
79 EXPECT_TRUE(
80 boost::algorithm::starts_with(f.path().filename().native(), "Foo"));
81}
82
83TEST(TemporaryFile, NoSuchPath) {
84 EXPECT_THROW({ TemporaryFile f("", "/no/such/path"); }, std::system_error);
85}
86
87TEST(TemporaryFile, moveAssignment) {
88 TemporaryFile f;
89 int fd;
90
91 EXPECT_TRUE(f.path().is_absolute());
92 {
93 TemporaryFile g("Foo", ".");
94 EXPECT_NE(g.fd(), -1);
95 fd = g.fd();
96 f = std::move(g);
97 }
98 EXPECT_EQ(fs::path("."), f.path().parent_path());
99 EXPECT_EQ(f.fd(), fd);
100
101 TemporaryFile h = TemporaryFile("FooBar", ".");
102 EXPECT_NE(h.fd(), -1);
103}
104
105TEST(TemporaryFile, moveCtor) {
106 struct FooBar {
107 TemporaryFile f_;
108 explicit FooBar(TemporaryFile&& f) : f_(std::move(f)) {}
109 };
110 TemporaryFile g("Foo");
111 FooBar fb(std::move(g));
112 EXPECT_EQ(g.fd(), -1);
113 EXPECT_NE(fb.f_.fd(), -1);
114}
115
116void testTemporaryDirectory(TemporaryDirectory::Scope scope) {
117 fs::path path;
118 {
119 TemporaryDirectory d("", "", scope);
120 path = d.path();
121 EXPECT_FALSE(path.empty());
122 EXPECT_TRUE(path.is_absolute());
123 EXPECT_TRUE(fs::exists(path));
124 EXPECT_TRUE(fs::is_directory(path));
125
126 fs::path fp = path / "bar";
127 int fd = open(fp.string().c_str(), O_RDWR | O_CREAT | O_TRUNC, 0666);
128 EXPECT_NE(fd, -1);
129 close(fd);
130
131 TemporaryFile f("Foo", d.path());
132 EXPECT_EQ(d.path(), f.path().parent_path());
133 }
134 bool exists = (scope == TemporaryDirectory::Scope::PERMANENT);
135 EXPECT_EQ(exists, fs::exists(path));
136}
137
138TEST(TemporaryDirectory, Permanent) {
139 testTemporaryDirectory(TemporaryDirectory::Scope::PERMANENT);
140}
141
142TEST(TemporaryDirectory, DeleteOnDestruction) {
143 testTemporaryDirectory(TemporaryDirectory::Scope::DELETE_ON_DESTRUCTION);
144}
145
146void expectTempdirExists(const TemporaryDirectory& d) {
147 EXPECT_FALSE(d.path().empty());
148 EXPECT_TRUE(fs::exists(d.path()));
149 EXPECT_TRUE(fs::is_directory(d.path()));
150}
151
152TEST(TemporaryDirectory, SafelyMove) {
153 std::unique_ptr<TemporaryDirectory> dir;
154 TemporaryDirectory dir2;
155 {
156 auto scope = TemporaryDirectory::Scope::DELETE_ON_DESTRUCTION;
157 TemporaryDirectory d("", "", scope);
158 TemporaryDirectory d2("", "", scope);
159 expectTempdirExists(d);
160 expectTempdirExists(d2);
161
162 dir = std::make_unique<TemporaryDirectory>(std::move(d));
163 dir2 = std::move(d2);
164 }
165
166 expectTempdirExists(*dir);
167 expectTempdirExists(dir2);
168}
169
170TEST(ChangeToTempDir, ChangeDir) {
171 auto pwd1 = fs::current_path();
172 {
173 ChangeToTempDir d;
174 EXPECT_NE(pwd1, fs::current_path());
175 }
176 EXPECT_EQ(pwd1, fs::current_path());
177}
178
179TEST(PCREPatternMatch, Simple) {
180 EXPECT_PCRE_MATCH(".*a.c.*", "gabca");
181 EXPECT_NO_PCRE_MATCH("a.c", "gabca");
182 EXPECT_NO_PCRE_MATCH(".*ac.*", "gabca");
183}
184
185TEST(CaptureFD, GlogPatterns) {
186 CaptureFD err(fileno(stderr));
187 LOG(INFO) << "All is well";
188 EXPECT_NO_PCRE_MATCH(glogErrOrWarnPattern(), err.readIncremental());
189 {
190 LOG(ERROR) << "Uh-oh";
191 auto s = err.readIncremental();
192 EXPECT_PCRE_MATCH(glogErrorPattern(), s);
193 EXPECT_NO_PCRE_MATCH(glogWarningPattern(), s);
194 EXPECT_PCRE_MATCH(glogErrOrWarnPattern(), s);
195 }
196 {
197 LOG(WARNING) << "Oops";
198 auto s = err.readIncremental();
199 EXPECT_NO_PCRE_MATCH(glogErrorPattern(), s);
200 EXPECT_PCRE_MATCH(glogWarningPattern(), s);
201 EXPECT_PCRE_MATCH(glogErrOrWarnPattern(), s);
202 }
203}
204
205TEST(CaptureFD, ChunkCob) {
206 std::vector<std::string> chunks;
207 {
208 CaptureFD err(fileno(stderr), [&](StringPiece p) {
209 chunks.emplace_back(p.str());
210 switch (chunks.size()) {
211 case 1:
212 EXPECT_PCRE_MATCH(".*foo.*bar.*", p);
213 break;
214 case 2:
215 EXPECT_PCRE_MATCH("[^\n]*baz.*", p);
216 break;
217 default:
218 FAIL() << "Got too many chunks: " << chunks.size();
219 }
220 });
221 LOG(INFO) << "foo";
222 LOG(INFO) << "bar";
223 EXPECT_PCRE_MATCH(".*foo.*bar.*", err.read());
224 auto chunk = err.readIncremental();
225 EXPECT_EQ(chunks.at(0), chunk);
226 LOG(INFO) << "baz";
227 EXPECT_PCRE_MATCH(".*foo.*bar.*baz.*", err.read());
228 }
229 EXPECT_EQ(2, chunks.size());
230}
231