Imported Upstream version 1.7.1
[platform/upstream/ninja.git] / src / disk_interface_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 #include <assert.h>
16 #include <stdio.h>
17 #ifdef _WIN32
18 #include <io.h>
19 #include <windows.h>
20 #endif
21
22 #include "disk_interface.h"
23 #include "graph.h"
24 #include "test.h"
25
26 namespace {
27
28 struct DiskInterfaceTest : public testing::Test {
29   virtual void SetUp() {
30     // These tests do real disk accesses, so create a temp dir.
31     temp_dir_.CreateAndEnter("Ninja-DiskInterfaceTest");
32   }
33
34   virtual void TearDown() {
35     temp_dir_.Cleanup();
36   }
37
38   bool Touch(const char* path) {
39     FILE *f = fopen(path, "w");
40     if (!f)
41       return false;
42     return fclose(f) == 0;
43   }
44
45   ScopedTempDir temp_dir_;
46   RealDiskInterface disk_;
47 };
48
49 TEST_F(DiskInterfaceTest, StatMissingFile) {
50   string err;
51   EXPECT_EQ(0, disk_.Stat("nosuchfile", &err));
52   EXPECT_EQ("", err);
53
54   // On Windows, the errno for a file in a nonexistent directory
55   // is different.
56   EXPECT_EQ(0, disk_.Stat("nosuchdir/nosuchfile", &err));
57   EXPECT_EQ("", err);
58
59   // On POSIX systems, the errno is different if a component of the
60   // path prefix is not a directory.
61   ASSERT_TRUE(Touch("notadir"));
62   EXPECT_EQ(0, disk_.Stat("notadir/nosuchfile", &err));
63   EXPECT_EQ("", err);
64 }
65
66 TEST_F(DiskInterfaceTest, StatBadPath) {
67   string err;
68 #ifdef _WIN32
69   string bad_path("cc:\\foo");
70   EXPECT_EQ(-1, disk_.Stat(bad_path, &err));
71   EXPECT_NE("", err);
72 #else
73   string too_long_name(512, 'x');
74   EXPECT_EQ(-1, disk_.Stat(too_long_name, &err));
75   EXPECT_NE("", err);
76 #endif
77 }
78
79 TEST_F(DiskInterfaceTest, StatExistingFile) {
80   string err;
81   ASSERT_TRUE(Touch("file"));
82   EXPECT_GT(disk_.Stat("file", &err), 1);
83   EXPECT_EQ("", err);
84 }
85
86 TEST_F(DiskInterfaceTest, StatExistingDir) {
87   string err;
88   ASSERT_TRUE(disk_.MakeDir("subdir"));
89   ASSERT_TRUE(disk_.MakeDir("subdir/subsubdir"));
90   EXPECT_GT(disk_.Stat(".", &err), 1);
91   EXPECT_EQ("", err);
92   EXPECT_GT(disk_.Stat("subdir", &err), 1);
93   EXPECT_EQ("", err);
94   EXPECT_GT(disk_.Stat("subdir/subsubdir", &err), 1);
95   EXPECT_EQ("", err);
96
97   EXPECT_EQ(disk_.Stat("subdir", &err),
98             disk_.Stat("subdir/.", &err));
99   EXPECT_EQ(disk_.Stat("subdir", &err),
100             disk_.Stat("subdir/subsubdir/..", &err));
101   EXPECT_EQ(disk_.Stat("subdir/subsubdir", &err),
102             disk_.Stat("subdir/subsubdir/.", &err));
103 }
104
105 #ifdef _WIN32
106 TEST_F(DiskInterfaceTest, StatCache) {
107   string err;
108   disk_.AllowStatCache(true);
109
110   ASSERT_TRUE(Touch("file1"));
111   ASSERT_TRUE(Touch("fiLE2"));
112   ASSERT_TRUE(disk_.MakeDir("subdir"));
113   ASSERT_TRUE(disk_.MakeDir("subdir/subsubdir"));
114   ASSERT_TRUE(Touch("subdir\\subfile1"));
115   ASSERT_TRUE(Touch("subdir\\SUBFILE2"));
116   ASSERT_TRUE(Touch("subdir\\SUBFILE3"));
117
118   EXPECT_GT(disk_.Stat("FIle1", &err), 1);
119   EXPECT_EQ("", err);
120   EXPECT_GT(disk_.Stat("file1", &err), 1);
121   EXPECT_EQ("", err);
122
123   EXPECT_GT(disk_.Stat("subdir/subfile2", &err), 1);
124   EXPECT_EQ("", err);
125   EXPECT_GT(disk_.Stat("sUbdir\\suBFile1", &err), 1);
126   EXPECT_EQ("", err);
127
128   EXPECT_GT(disk_.Stat(".", &err), 1);
129   EXPECT_EQ("", err);
130   EXPECT_GT(disk_.Stat("subdir", &err), 1);
131   EXPECT_EQ("", err);
132   EXPECT_GT(disk_.Stat("subdir/subsubdir", &err), 1);
133   EXPECT_EQ("", err);
134
135   EXPECT_EQ(disk_.Stat("subdir", &err),
136             disk_.Stat("subdir/.", &err));
137   EXPECT_EQ("", err);
138   EXPECT_EQ(disk_.Stat("subdir", &err),
139             disk_.Stat("subdir/subsubdir/..", &err));
140   EXPECT_EQ("", err);
141   EXPECT_EQ(disk_.Stat("subdir/subsubdir", &err),
142             disk_.Stat("subdir/subsubdir/.", &err));
143   EXPECT_EQ("", err);
144
145   // Test error cases.
146   string bad_path("cc:\\foo");
147   EXPECT_EQ(-1, disk_.Stat(bad_path, &err));
148   EXPECT_NE("", err); err.clear();
149   EXPECT_EQ(-1, disk_.Stat(bad_path, &err));
150   EXPECT_NE("", err); err.clear();
151   EXPECT_EQ(0, disk_.Stat("nosuchfile", &err));
152   EXPECT_EQ("", err);
153   EXPECT_EQ(0, disk_.Stat("nosuchdir/nosuchfile", &err));
154   EXPECT_EQ("", err);
155 }
156 #endif
157
158 TEST_F(DiskInterfaceTest, ReadFile) {
159   string err;
160   std::string content;
161   ASSERT_EQ(DiskInterface::NotFound,
162             disk_.ReadFile("foobar", &content, &err));
163   EXPECT_EQ("", content);
164   EXPECT_NE("", err); // actual value is platform-specific
165   err.clear();
166
167   const char* kTestFile = "testfile";
168   FILE* f = fopen(kTestFile, "wb");
169   ASSERT_TRUE(f);
170   const char* kTestContent = "test content\nok";
171   fprintf(f, "%s", kTestContent);
172   ASSERT_EQ(0, fclose(f));
173
174   ASSERT_EQ(DiskInterface::Okay,
175             disk_.ReadFile(kTestFile, &content, &err));
176   EXPECT_EQ(kTestContent, content);
177   EXPECT_EQ("", err);
178 }
179
180 TEST_F(DiskInterfaceTest, MakeDirs) {
181   string path = "path/with/double//slash/";
182   EXPECT_TRUE(disk_.MakeDirs(path.c_str()));
183   FILE* f = fopen((path + "a_file").c_str(), "w");
184   EXPECT_TRUE(f);
185   EXPECT_EQ(0, fclose(f));
186 #ifdef _WIN32
187   string path2 = "another\\with\\back\\\\slashes\\";
188   EXPECT_TRUE(disk_.MakeDirs(path2.c_str()));
189   FILE* f2 = fopen((path2 + "a_file").c_str(), "w");
190   EXPECT_TRUE(f2);
191   EXPECT_EQ(0, fclose(f2));
192 #endif
193 }
194
195 TEST_F(DiskInterfaceTest, RemoveFile) {
196   const char* kFileName = "file-to-remove";
197   ASSERT_TRUE(Touch(kFileName));
198   EXPECT_EQ(0, disk_.RemoveFile(kFileName));
199   EXPECT_EQ(1, disk_.RemoveFile(kFileName));
200   EXPECT_EQ(1, disk_.RemoveFile("does not exist"));
201 }
202
203 struct StatTest : public StateTestWithBuiltinRules,
204                   public DiskInterface {
205   StatTest() : scan_(&state_, NULL, NULL, this) {}
206
207   // DiskInterface implementation.
208   virtual TimeStamp Stat(const string& path, string* err) const;
209   virtual bool WriteFile(const string& path, const string& contents) {
210     assert(false);
211     return true;
212   }
213   virtual bool MakeDir(const string& path) {
214     assert(false);
215     return false;
216   }
217   virtual Status ReadFile(const string& path, string* contents, string* err) {
218     assert(false);
219     return NotFound;
220   }
221   virtual int RemoveFile(const string& path) {
222     assert(false);
223     return 0;
224   }
225
226   DependencyScan scan_;
227   map<string, TimeStamp> mtimes_;
228   mutable vector<string> stats_;
229 };
230
231 TimeStamp StatTest::Stat(const string& path, string* err) const {
232   stats_.push_back(path);
233   map<string, TimeStamp>::const_iterator i = mtimes_.find(path);
234   if (i == mtimes_.end())
235     return 0;  // File not found.
236   return i->second;
237 }
238
239 TEST_F(StatTest, Simple) {
240   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
241 "build out: cat in\n"));
242
243   Node* out = GetNode("out");
244   string err;
245   EXPECT_TRUE(out->Stat(this, &err));
246   EXPECT_EQ("", err);
247   ASSERT_EQ(1u, stats_.size());
248   scan_.RecomputeDirty(out->in_edge(), NULL);
249   ASSERT_EQ(2u, stats_.size());
250   ASSERT_EQ("out", stats_[0]);
251   ASSERT_EQ("in",  stats_[1]);
252 }
253
254 TEST_F(StatTest, TwoStep) {
255   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
256 "build out: cat mid\n"
257 "build mid: cat in\n"));
258
259   Node* out = GetNode("out");
260   string err;
261   EXPECT_TRUE(out->Stat(this, &err));
262   EXPECT_EQ("", err);
263   ASSERT_EQ(1u, stats_.size());
264   scan_.RecomputeDirty(out->in_edge(), NULL);
265   ASSERT_EQ(3u, stats_.size());
266   ASSERT_EQ("out", stats_[0]);
267   ASSERT_TRUE(GetNode("out")->dirty());
268   ASSERT_EQ("mid",  stats_[1]);
269   ASSERT_TRUE(GetNode("mid")->dirty());
270   ASSERT_EQ("in",  stats_[2]);
271 }
272
273 TEST_F(StatTest, Tree) {
274   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
275 "build out: cat mid1 mid2\n"
276 "build mid1: cat in11 in12\n"
277 "build mid2: cat in21 in22\n"));
278
279   Node* out = GetNode("out");
280   string err;
281   EXPECT_TRUE(out->Stat(this, &err));
282   EXPECT_EQ("", err);
283   ASSERT_EQ(1u, stats_.size());
284   scan_.RecomputeDirty(out->in_edge(), NULL);
285   ASSERT_EQ(1u + 6u, stats_.size());
286   ASSERT_EQ("mid1", stats_[1]);
287   ASSERT_TRUE(GetNode("mid1")->dirty());
288   ASSERT_EQ("in11", stats_[2]);
289 }
290
291 TEST_F(StatTest, Middle) {
292   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
293 "build out: cat mid\n"
294 "build mid: cat in\n"));
295
296   mtimes_["in"] = 1;
297   mtimes_["mid"] = 0;  // missing
298   mtimes_["out"] = 1;
299
300   Node* out = GetNode("out");
301   string err;
302   EXPECT_TRUE(out->Stat(this, &err));
303   EXPECT_EQ("", err);
304   ASSERT_EQ(1u, stats_.size());
305   scan_.RecomputeDirty(out->in_edge(), NULL);
306   ASSERT_FALSE(GetNode("in")->dirty());
307   ASSERT_TRUE(GetNode("mid")->dirty());
308   ASSERT_TRUE(GetNode("out")->dirty());
309 }
310
311 }  // namespace