2 * Copyright 2017 Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
22 #include <folly/Range.h>
23 #include <folly/ScopeGuard.h>
24 #include <folly/experimental/io/FsUtil.h>
32 * By default, the file is created in a system-specific location (the value
33 * of the TMPDIR environment variable, or /tmp), but you can override that
34 * with a different (non-empty) directory passed to the constructor.
36 * By default, the file is closed and deleted when the TemporaryFile object
37 * is destroyed, but both these behaviors can be overridden with arguments
47 explicit TemporaryFile(StringPiece namePrefix = StringPiece(),
48 fs::path dir = fs::path(),
49 Scope scope = Scope::UNLINK_ON_DESTRUCTION,
50 bool closeOnDestruction = true);
53 // Movable, but not copyable
54 TemporaryFile(TemporaryFile&& other) noexcept {
59 TemporaryFile& operator=(TemporaryFile&& other) {
68 int fd() const { return fd_; }
69 const fs::path& path() const;
74 bool closeOnDestruction_;
78 void assign(TemporaryFile& other) {
79 scope_ = other.scope_;
80 closeOnDestruction_ = other.closeOnDestruction_;
81 fd_ = std::exchange(other.fd_, -1);
87 * Temporary directory.
89 * By default, the temporary directory is created in a system-specific
90 * location (the value of the TMPDIR environment variable, or /tmp), but you
91 * can override that with a non-empty directory passed to the constructor.
93 * By default, the directory is recursively deleted when the TemporaryDirectory
94 * object is destroyed, but that can be overridden with an argument
98 class TemporaryDirectory {
102 DELETE_ON_DESTRUCTION
104 explicit TemporaryDirectory(StringPiece namePrefix = StringPiece(),
105 fs::path dir = fs::path(),
106 Scope scope = Scope::DELETE_ON_DESTRUCTION);
107 ~TemporaryDirectory();
109 // Movable, but not copiable
110 TemporaryDirectory(TemporaryDirectory&&) = default;
111 TemporaryDirectory& operator=(TemporaryDirectory&&) = default;
113 const fs::path& path() const {
119 std::unique_ptr<fs::path> path_;
123 * Changes into a temporary directory, and deletes it with all its contents
124 * upon destruction, also changing back to the original working directory.
126 class ChangeToTempDir {
131 // Movable, but not copiable
132 ChangeToTempDir(ChangeToTempDir&&) = default;
133 ChangeToTempDir& operator=(ChangeToTempDir&&) = default;
135 const fs::path& path() const { return dir_.path(); }
138 fs::path initialPath_;
139 TemporaryDirectory dir_;
144 void* previousThreadLocalHandler;
145 int previousCrtReportMode;
147 SavedState disableInvalidParameters();
148 void enableInvalidParameters(SavedState state);
149 } // namespace detail
151 // Ok, so fun fact: The CRT on windows will actually abort
152 // on certain failed parameter validation checks in debug
153 // mode rather than simply returning -1 as it does in release
154 // mode. We can however, ensure consistent behavior by
155 // registering our own thread-local invalid parameter handler
156 // for the duration of the call, and just have that handler
157 // immediately return. We also have to disable CRT asertion
158 // alerts for the duration of the call, otherwise we get
159 // the abort-retry-ignore window.
160 template <typename Func>
161 auto msvcSuppressAbortOnInvalidParams(Func func) -> decltype(func()) {
162 auto savedState = detail::disableInvalidParameters();
164 detail::enableInvalidParameters(savedState);
170 * Easy PCRE regex matching. Note that pattern must match the ENTIRE target,
171 * so use .* at the start and end of the pattern, as appropriate. See
172 * http://regex101.com/ for a PCRE simulator.
174 #define EXPECT_PCRE_MATCH(pattern_stringpiece, target_stringpiece) \
176 ::folly::test::detail::hasPCREPatternMatch, \
177 pattern_stringpiece, \
180 #define EXPECT_NO_PCRE_MATCH(pattern_stringpiece, target_stringpiece) \
182 ::folly::test::detail::hasNoPCREPatternMatch, \
183 pattern_stringpiece, \
188 bool hasPCREPatternMatch(StringPiece pattern, StringPiece target);
189 bool hasNoPCREPatternMatch(StringPiece pattern, StringPiece target);
190 } // namespace detail
193 * Use these patterns together with CaptureFD and EXPECT_PCRE_MATCH() to
194 * test for the presence (or absence) of log lines at a particular level:
196 * CaptureFD stderr(2);
197 * LOG(INFO) << "All is well";
198 * EXPECT_NO_PCRE_MATCH(glogErrOrWarnPattern(), stderr.readIncremental());
199 * LOG(ERROR) << "Uh-oh";
200 * EXPECT_PCRE_MATCH(glogErrorPattern(), stderr.readIncremental());
202 inline std::string glogErrorPattern() { return ".*(^|\n)E[0-9].*"; }
203 inline std::string glogWarningPattern() { return ".*(^|\n)W[0-9].*"; }
205 inline std::string glogErrOrWarnPattern() { return ".*(^|\n)[EW][0-9].*"; }
208 * Temporarily capture a file descriptor by redirecting it into a file.
209 * You can consume its entire output thus far via read(), incrementally
210 * via readIncremental(), or via callback using chunk_cob.
211 * Great for testing logging (see also glog*Pattern()).
215 struct NoOpChunkCob { void operator()(StringPiece) {} };
218 using ChunkCob = std::function<void(folly::StringPiece)>;
221 * chunk_cob is is guaranteed to consume all the captured output. It is
222 * invoked on each readIncremental(), and also on FD release to capture
223 * as-yet unread lines. Chunks can be empty.
225 explicit CaptureFD(int fd, ChunkCob chunk_cob = NoOpChunkCob());
229 * Restore the captured FD to its original state. It can be useful to do
230 * this before the destructor so that you can read() the captured data and
231 * log about it to the formerly captured stderr or stdout.
236 * Reads the whole file into a string, but does not remove the redirect.
238 std::string read() const;
241 * Read any bytes that were appended to the file since the last
242 * readIncremental. Great for testing line-by-line output.
244 std::string readIncremental();
251 int oldFDCopy_; // equal to fd_ after restore()
253 off_t readOffset_; // for incremental reading