53bfc48790030c7219965eb9d210d5a4beefad09
[platform/upstream/ninja.git] / src / test.cc
1 // Copyright 2011 Google Inc. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #ifdef _WIN32
16 #include <direct.h>  // Has to be before util.h is included.
17 #endif
18
19 #include "test.h"
20
21 #include <algorithm>
22
23 #include <errno.h>
24 #ifdef _WIN32
25 #include <windows.h>
26 #else
27 #include <unistd.h>
28 #endif
29
30 #include "build_log.h"
31 #include "graph.h"
32 #include "manifest_parser.h"
33 #include "util.h"
34
35 namespace {
36
37 #ifdef _WIN32
38 #ifndef _mktemp_s
39 /// mingw has no mktemp.  Implement one with the same type as the one
40 /// found in the Windows API.
41 int _mktemp_s(char* templ) {
42   char* ofs = strchr(templ, 'X');
43   sprintf(ofs, "%d", rand() % 1000000);
44   return 0;
45 }
46 #endif
47
48 /// Windows has no mkdtemp.  Implement it in terms of _mktemp_s.
49 char* mkdtemp(char* name_template) {
50   int err = _mktemp_s(name_template);
51   if (err < 0) {
52     perror("_mktemp_s");
53     return NULL;
54   }
55
56   err = _mkdir(name_template);
57   if (err < 0) {
58     perror("mkdir");
59     return NULL;
60   }
61
62   return name_template;
63 }
64 #endif  // _WIN32
65
66 string GetSystemTempDir() {
67 #ifdef _WIN32
68   char buf[1024];
69   if (!GetTempPath(sizeof(buf), buf))
70     return "";
71   return buf;
72 #else
73   const char* tempdir = getenv("TMPDIR");
74   if (tempdir)
75     return tempdir;
76   return "/tmp";
77 #endif
78 }
79
80 }  // anonymous namespace
81
82 StateTestWithBuiltinRules::StateTestWithBuiltinRules() {
83   AddCatRule(&state_);
84 }
85
86 void StateTestWithBuiltinRules::AddCatRule(State* state) {
87   AssertParse(state,
88 "rule cat\n"
89 "  command = cat $in > $out\n");
90 }
91
92 Node* StateTestWithBuiltinRules::GetNode(const string& path) {
93   EXPECT_FALSE(strpbrk(path.c_str(), "/\\"));
94   return state_.GetNode(path, 0);
95 }
96
97 void AssertParse(State* state, const char* input) {
98   ManifestParser parser(state, NULL, kDupeEdgeActionWarn);
99   string err;
100   EXPECT_TRUE(parser.ParseTest(input, &err));
101   ASSERT_EQ("", err);
102   VerifyGraph(*state);
103 }
104
105 void AssertHash(const char* expected, uint64_t actual) {
106   ASSERT_EQ(BuildLog::LogEntry::HashCommand(expected), actual);
107 }
108
109 void VerifyGraph(const State& state) {
110   for (vector<Edge*>::const_iterator e = state.edges_.begin();
111        e != state.edges_.end(); ++e) {
112     // All edges need at least one output.
113     EXPECT_FALSE((*e)->outputs_.empty());
114     // Check that the edge's inputs have the edge as out-edge.
115     for (vector<Node*>::const_iterator in_node = (*e)->inputs_.begin();
116          in_node != (*e)->inputs_.end(); ++in_node) {
117       const vector<Edge*>& out_edges = (*in_node)->out_edges();
118       EXPECT_NE(find(out_edges.begin(), out_edges.end(), *e),
119                 out_edges.end());
120     }
121     // Check that the edge's outputs have the edge as in-edge.
122     for (vector<Node*>::const_iterator out_node = (*e)->outputs_.begin();
123          out_node != (*e)->outputs_.end(); ++out_node) {
124       EXPECT_EQ((*out_node)->in_edge(), *e);
125     }
126   }
127
128   // The union of all in- and out-edges of each nodes should be exactly edges_.
129   set<const Edge*> node_edge_set;
130   for (State::Paths::const_iterator p = state.paths_.begin();
131        p != state.paths_.end(); ++p) {
132     const Node* n = p->second;
133     if (n->in_edge())
134       node_edge_set.insert(n->in_edge());
135     node_edge_set.insert(n->out_edges().begin(), n->out_edges().end());
136   }
137   set<const Edge*> edge_set(state.edges_.begin(), state.edges_.end());
138   EXPECT_EQ(node_edge_set, edge_set);
139 }
140
141 void VirtualFileSystem::Create(const string& path,
142                                const string& contents) {
143   files_[path].mtime = now_;
144   files_[path].contents = contents;
145   files_created_.insert(path);
146 }
147
148 TimeStamp VirtualFileSystem::Stat(const string& path, string* err) const {
149   FileMap::const_iterator i = files_.find(path);
150   if (i != files_.end()) {
151     *err = i->second.stat_error;
152     return i->second.mtime;
153   }
154   return 0;
155 }
156
157 bool VirtualFileSystem::WriteFile(const string& path, const string& contents) {
158   Create(path, contents);
159   return true;
160 }
161
162 bool VirtualFileSystem::MakeDir(const string& path) {
163   directories_made_.push_back(path);
164   return true;  // success
165 }
166
167 FileReader::Status VirtualFileSystem::ReadFile(const string& path,
168                                                string* contents,
169                                                string* err) {
170   files_read_.push_back(path);
171   FileMap::iterator i = files_.find(path);
172   if (i != files_.end()) {
173     *contents = i->second.contents;
174     return Okay;
175   }
176   *err = strerror(ENOENT);
177   return NotFound;
178 }
179
180 int VirtualFileSystem::RemoveFile(const string& path) {
181   if (find(directories_made_.begin(), directories_made_.end(), path)
182       != directories_made_.end())
183     return -1;
184   FileMap::iterator i = files_.find(path);
185   if (i != files_.end()) {
186     files_.erase(i);
187     files_removed_.insert(path);
188     return 0;
189   } else {
190     return 1;
191   }
192 }
193
194 void ScopedTempDir::CreateAndEnter(const string& name) {
195   // First change into the system temp dir and save it for cleanup.
196   start_dir_ = GetSystemTempDir();
197   if (start_dir_.empty())
198     Fatal("couldn't get system temp dir");
199   if (chdir(start_dir_.c_str()) < 0)
200     Fatal("chdir: %s", strerror(errno));
201
202   // Create a temporary subdirectory of that.
203   char name_template[1024];
204   strcpy(name_template, name.c_str());
205   strcat(name_template, "-XXXXXX");
206   char* tempname = mkdtemp(name_template);
207   if (!tempname)
208     Fatal("mkdtemp: %s", strerror(errno));
209   temp_dir_name_ = tempname;
210
211   // chdir into the new temporary directory.
212   if (chdir(temp_dir_name_.c_str()) < 0)
213     Fatal("chdir: %s", strerror(errno));
214 }
215
216 void ScopedTempDir::Cleanup() {
217   if (temp_dir_name_.empty())
218     return;  // Something went wrong earlier.
219
220   // Move out of the directory we're about to clobber.
221   if (chdir(start_dir_.c_str()) < 0)
222     Fatal("chdir: %s", strerror(errno));
223
224 #ifdef _WIN32
225   string command = "rmdir /s /q " + temp_dir_name_;
226 #else
227   string command = "rm -rf " + temp_dir_name_;
228 #endif
229   if (system(command.c_str()) < 0)
230     Fatal("system: %s", strerror(errno));
231
232   temp_dir_name_.clear();
233 }