Split up experimental/TestUtil
[folly.git] / folly / experimental / test / TestUtilTest.cpp
1 /*
2  * Copyright 2017 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
29 using namespace folly;
30 using namespace folly::test;
31
32 TEST(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
56 TEST(TemporaryFile, Prefix) {
57   TemporaryFile f("Foo");
58   EXPECT_TRUE(f.path().is_absolute());
59   EXPECT_TRUE(boost::algorithm::starts_with(f.path().filename().native(),
60                                             "Foo"));
61 }
62
63 TEST(TemporaryFile, PathPrefix) {
64   TemporaryFile f("Foo", ".");
65   EXPECT_EQ(fs::path("."), f.path().parent_path());
66   EXPECT_TRUE(boost::algorithm::starts_with(f.path().filename().native(),
67                                             "Foo"));
68 }
69
70 TEST(TemporaryFile, NoSuchPath) {
71   EXPECT_THROW({TemporaryFile f("", "/no/such/path");},
72                std::system_error);
73 }
74
75 void testTemporaryDirectory(TemporaryDirectory::Scope scope) {
76   fs::path path;
77   {
78     TemporaryDirectory d("", "", scope);
79     path = d.path();
80     EXPECT_FALSE(path.empty());
81     EXPECT_TRUE(path.is_absolute());
82     EXPECT_TRUE(fs::exists(path));
83     EXPECT_TRUE(fs::is_directory(path));
84
85     fs::path fp = path / "bar";
86     int fd = open(fp.string().c_str(), O_RDWR | O_CREAT | O_TRUNC, 0666);
87     EXPECT_NE(fd, -1);
88     close(fd);
89
90     TemporaryFile f("Foo", d.path());
91     EXPECT_EQ(d.path(), f.path().parent_path());
92   }
93   bool exists = (scope == TemporaryDirectory::Scope::PERMANENT);
94   EXPECT_EQ(exists, fs::exists(path));
95 }
96
97 TEST(TemporaryDirectory, Permanent) {
98   testTemporaryDirectory(TemporaryDirectory::Scope::PERMANENT);
99 }
100
101 TEST(TemporaryDirectory, DeleteOnDestruction) {
102   testTemporaryDirectory(TemporaryDirectory::Scope::DELETE_ON_DESTRUCTION);
103 }
104
105 void expectTempdirExists(const TemporaryDirectory& d) {
106   EXPECT_FALSE(d.path().empty());
107   EXPECT_TRUE(fs::exists(d.path()));
108   EXPECT_TRUE(fs::is_directory(d.path()));
109 }
110
111 TEST(TemporaryDirectory, SafelyMove) {
112   std::unique_ptr<TemporaryDirectory> dir;
113   TemporaryDirectory dir2;
114   {
115     auto scope = TemporaryDirectory::Scope::DELETE_ON_DESTRUCTION;
116     TemporaryDirectory d("", "", scope);
117     TemporaryDirectory d2("", "", scope);
118     expectTempdirExists(d);
119     expectTempdirExists(d2);
120
121     dir = folly::make_unique<TemporaryDirectory>(std::move(d));
122     dir2 = std::move(d2);
123   }
124
125   expectTempdirExists(*dir);
126   expectTempdirExists(dir2);
127 }
128
129 TEST(ChangeToTempDir, ChangeDir) {
130   auto pwd1 = fs::current_path();
131   {
132     ChangeToTempDir d;
133     EXPECT_NE(pwd1, fs::current_path());
134   }
135   EXPECT_EQ(pwd1, fs::current_path());
136 }
137
138 TEST(PCREPatternMatch, Simple) {
139   EXPECT_PCRE_MATCH(".*a.c.*", "gabca");
140   EXPECT_NO_PCRE_MATCH("a.c", "gabca");
141   EXPECT_NO_PCRE_MATCH(".*ac.*", "gabca");
142 }
143
144 TEST(CaptureFD, GlogPatterns) {
145   CaptureFD err(fileno(stderr));
146   LOG(INFO) << "All is well";
147   EXPECT_NO_PCRE_MATCH(glogErrOrWarnPattern(), err.readIncremental());
148   {
149     LOG(ERROR) << "Uh-oh";
150     auto s = err.readIncremental();
151     EXPECT_PCRE_MATCH(glogErrorPattern(), s);
152     EXPECT_NO_PCRE_MATCH(glogWarningPattern(), s);
153     EXPECT_PCRE_MATCH(glogErrOrWarnPattern(), s);
154   }
155   {
156     LOG(WARNING) << "Oops";
157     auto s = err.readIncremental();
158     EXPECT_NO_PCRE_MATCH(glogErrorPattern(), s);
159     EXPECT_PCRE_MATCH(glogWarningPattern(), s);
160     EXPECT_PCRE_MATCH(glogErrOrWarnPattern(), s);
161   }
162 }
163
164 TEST(CaptureFD, ChunkCob) {
165   std::vector<std::string> chunks;
166   {
167     CaptureFD err(fileno(stderr), [&](StringPiece p) {
168       chunks.emplace_back(p.str());
169       switch (chunks.size()) {
170         case 1:
171           EXPECT_PCRE_MATCH(".*foo.*bar.*", p);
172           break;
173         case 2:
174           EXPECT_PCRE_MATCH("[^\n]*baz.*", p);
175           break;
176         default:
177           FAIL() << "Got too many chunks: " << chunks.size();
178       }
179     });
180     LOG(INFO) << "foo";
181     LOG(INFO) << "bar";
182     EXPECT_PCRE_MATCH(".*foo.*bar.*", err.read());
183     auto chunk = err.readIncremental();
184     EXPECT_EQ(chunks.at(0), chunk);
185     LOG(INFO) << "baz";
186     EXPECT_PCRE_MATCH(".*foo.*bar.*baz.*", err.read());
187   }
188   EXPECT_EQ(2, chunks.size());
189 }