Add EXPECT_{NO_,}_PCRE_MATCH macros
[folly.git] / folly / experimental / TestUtil.cpp
1 /*
2  * Copyright 2015 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 #include <sys/stat.h>
21 #include <fcntl.h>
22
23 #include <boost/regex.hpp>
24 #include <folly/Conv.h>
25 #include <folly/Exception.h>
26
27 namespace folly {
28 namespace test {
29
30 namespace {
31
32 fs::path generateUniquePath(fs::path path, StringPiece namePrefix) {
33   if (path.empty()) {
34     path = fs::temp_directory_path();
35   }
36   if (namePrefix.empty()) {
37     path /= fs::unique_path();
38   } else {
39     path /= fs::unique_path(
40         to<std::string>(namePrefix, ".%%%%-%%%%-%%%%-%%%%"));
41   }
42   return path;
43 }
44
45 }  // namespace
46
47 TemporaryFile::TemporaryFile(StringPiece namePrefix,
48                              fs::path dir,
49                              Scope scope,
50                              bool closeOnDestruction)
51   : scope_(scope),
52     closeOnDestruction_(closeOnDestruction),
53     fd_(-1),
54     path_(generateUniquePath(std::move(dir), namePrefix)) {
55   fd_ = open(path_.c_str(), O_RDWR | O_CREAT | O_EXCL, 0666);
56   checkUnixError(fd_, "open failed");
57
58   if (scope_ == Scope::UNLINK_IMMEDIATELY) {
59     boost::system::error_code ec;
60     fs::remove(path_, ec);
61     if (ec) {
62       LOG(WARNING) << "unlink on construction failed: " << ec;
63     } else {
64       path_.clear();
65     }
66   }
67 }
68
69 const fs::path& TemporaryFile::path() const {
70   CHECK(scope_ != Scope::UNLINK_IMMEDIATELY);
71   DCHECK(!path_.empty());
72   return path_;
73 }
74
75 TemporaryFile::~TemporaryFile() {
76   if (fd_ != -1 && closeOnDestruction_) {
77     if (close(fd_) == -1) {
78       PLOG(ERROR) << "close failed";
79     }
80   }
81
82   // If we previously failed to unlink() (UNLINK_IMMEDIATELY), we'll
83   // try again here.
84   if (scope_ != Scope::PERMANENT && !path_.empty()) {
85     boost::system::error_code ec;
86     fs::remove(path_, ec);
87     if (ec) {
88       LOG(WARNING) << "unlink on destruction failed: " << ec;
89     }
90   }
91 }
92
93 TemporaryDirectory::TemporaryDirectory(StringPiece namePrefix,
94                                        fs::path dir,
95                                        Scope scope)
96   : scope_(scope),
97     path_(generateUniquePath(std::move(dir), namePrefix)) {
98   fs::create_directory(path_);
99 }
100
101 TemporaryDirectory::~TemporaryDirectory() {
102   if (scope_ == Scope::DELETE_ON_DESTRUCTION) {
103     boost::system::error_code ec;
104     fs::remove_all(path_, ec);
105     if (ec) {
106       LOG(WARNING) << "recursive delete on destruction failed: " << ec;
107     }
108   }
109 }
110
111 ChangeToTempDir::ChangeToTempDir() : initialPath_(fs::current_path()) {
112   std::string p = dir_.path().native();
113   ::chdir(p.c_str());
114 }
115
116 ChangeToTempDir::~ChangeToTempDir() {
117   std::string p = initialPath_.native();
118   ::chdir(p.c_str());
119 }
120
121 namespace detail {
122
123 bool hasPCREPatternMatch(StringPiece pattern, StringPiece target) {
124   return boost::regex_match(
125     target.begin(),
126     target.end(),
127     boost::regex(pattern.begin(), pattern.end())
128   );
129 }
130
131 bool hasNoPCREPatternMatch(StringPiece pattern, StringPiece target) {
132   return !hasPCREPatternMatch(pattern, target);
133 }
134
135 }  // namespace detail
136
137 }  // namespace test
138 }  // namespace folly