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