095489e48968ae70d6c00c5163cc60f84b042eda
[folly.git] / folly / experimental / TestUtil.cpp
1 /*
2  * Copyright 2014 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 "folly/Conv.h"
24 #include "folly/Exception.h"
25
26 namespace folly {
27 namespace test {
28
29 namespace {
30
31 fs::path generateUniquePath(fs::path path, StringPiece namePrefix) {
32   if (path.empty()) {
33     path = fs::temp_directory_path();
34   }
35   if (namePrefix.empty()) {
36     path /= fs::unique_path();
37   } else {
38     path /= fs::unique_path(
39         to<std::string>(namePrefix, ".%%%%-%%%%-%%%%-%%%%"));
40   }
41   return path;
42 }
43
44 }  // namespce
45
46 TemporaryFile::TemporaryFile(StringPiece namePrefix,
47                              fs::path dir,
48                              Scope scope,
49                              bool closeOnDestruction)
50   : scope_(scope),
51     closeOnDestruction_(closeOnDestruction),
52     fd_(-1),
53     path_(generateUniquePath(std::move(dir), namePrefix)) {
54   fd_ = open(path_.c_str(), O_RDWR | O_CREAT | O_EXCL, 0666);
55   checkUnixError(fd_, "open failed");
56
57   if (scope_ == Scope::UNLINK_IMMEDIATELY) {
58     boost::system::error_code ec;
59     fs::remove(path_, ec);
60     if (ec) {
61       LOG(WARNING) << "unlink on construction failed: " << ec;
62     } else {
63       path_.clear();
64     }
65   }
66 }
67
68 const fs::path& TemporaryFile::path() const {
69   CHECK(scope_ != Scope::UNLINK_IMMEDIATELY);
70   DCHECK(!path_.empty());
71   return path_;
72 }
73
74 TemporaryFile::~TemporaryFile() {
75   if (fd_ != -1 && closeOnDestruction_) {
76     if (close(fd_) == -1) {
77       PLOG(ERROR) << "close failed";
78     }
79   }
80
81   // If we previously failed to unlink() (UNLINK_IMMEDIATELY), we'll
82   // try again here.
83   if (scope_ != Scope::PERMANENT && !path_.empty()) {
84     boost::system::error_code ec;
85     fs::remove(path_, ec);
86     if (ec) {
87       LOG(WARNING) << "unlink on destruction failed: " << ec;
88     }
89   }
90 }
91
92 TemporaryDirectory::TemporaryDirectory(StringPiece namePrefix,
93                                        fs::path dir,
94                                        Scope scope)
95   : scope_(scope),
96     path_(generateUniquePath(std::move(dir), namePrefix)) {
97   fs::create_directory(path_);
98 }
99
100 TemporaryDirectory::~TemporaryDirectory() {
101   if (scope_ == Scope::DELETE_ON_DESTRUCTION) {
102     boost::system::error_code ec;
103     fs::remove_all(path_, ec);
104     if (ec) {
105       LOG(WARNING) << "recursive delete on destruction failed: " << ec;
106     }
107   }
108 }
109
110 }  // namespace test
111 }  // namespace folly