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