31 struct DiskInterfaceTest :
public testing::Test {
32 virtual void SetUp() {
34 temp_dir_.CreateAndEnter(
"Ninja-DiskInterfaceTest");
37 virtual void TearDown() {
41 bool Touch(
const char* path) {
42 FILE *f = fopen(path,
"w");
45 return fclose(f) == 0;
52 TEST_F(DiskInterfaceTest, StatMissingFile) {
54 EXPECT_EQ(0, disk_.Stat(
"nosuchfile", &err));
59 EXPECT_EQ(0, disk_.Stat(
"nosuchdir/nosuchfile", &err));
64 ASSERT_TRUE(Touch(
"notadir"));
65 EXPECT_EQ(0, disk_.Stat(
"notadir/nosuchfile", &err));
69 TEST_F(DiskInterfaceTest, StatMissingFileWithCache) {
70 disk_.AllowStatCache(
true);
75 ASSERT_TRUE(Touch(
"notadir"));
76 EXPECT_EQ(0, disk_.Stat(
"notadir/nosuchfile", &err));
80 TEST_F(DiskInterfaceTest, StatBadPath) {
83 string bad_path(
"cc:\\foo");
84 EXPECT_EQ(-1, disk_.Stat(bad_path, &err));
87 string too_long_name(512,
'x');
88 EXPECT_EQ(-1, disk_.Stat(too_long_name, &err));
93 TEST_F(DiskInterfaceTest, StatExistingFile) {
95 ASSERT_TRUE(Touch(
"file"));
96 EXPECT_GT(disk_.Stat(
"file", &err), 1);
101 TEST_F(DiskInterfaceTest, StatExistingFileWithLongPath) {
103 char currentdir[32767];
104 _getcwd(currentdir,
sizeof(currentdir));
105 const string filename = string(currentdir) +
106 "\\filename_with_256_characters_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\
107 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\
108 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\
109 xxxxxxxxxxxxxxxxxxxxx";
110 const string prefixed =
"\\\\?\\" + filename;
111 ASSERT_TRUE(Touch(prefixed.c_str()));
112 EXPECT_GT(disk_.Stat(disk_.AreLongPathsEnabled() ?
113 filename : prefixed, &err), 1);
118 TEST_F(DiskInterfaceTest, StatExistingDir) {
120 ASSERT_TRUE(disk_.MakeDir(
"subdir"));
121 ASSERT_TRUE(disk_.MakeDir(
"subdir/subsubdir"));
122 EXPECT_GT(disk_.Stat(
"..", &err), 1);
124 EXPECT_GT(disk_.Stat(
".", &err), 1);
126 EXPECT_GT(disk_.Stat(
"subdir", &err), 1);
128 EXPECT_GT(disk_.Stat(
"subdir/subsubdir", &err), 1);
131 EXPECT_EQ(disk_.Stat(
"subdir", &err),
132 disk_.Stat(
"subdir/.", &err));
133 EXPECT_EQ(disk_.Stat(
"subdir", &err),
134 disk_.Stat(
"subdir/subsubdir/..", &err));
135 EXPECT_EQ(disk_.Stat(
"subdir/subsubdir", &err),
136 disk_.Stat(
"subdir/subsubdir/.", &err));
140 TEST_F(DiskInterfaceTest, StatCache) {
143 ASSERT_TRUE(Touch(
"file1"));
144 ASSERT_TRUE(Touch(
"fiLE2"));
145 ASSERT_TRUE(disk_.MakeDir(
"subdir"));
146 ASSERT_TRUE(disk_.MakeDir(
"subdir/subsubdir"));
147 ASSERT_TRUE(Touch(
"subdir\\subfile1"));
148 ASSERT_TRUE(Touch(
"subdir\\SUBFILE2"));
149 ASSERT_TRUE(Touch(
"subdir\\SUBFILE3"));
151 disk_.AllowStatCache(
false);
152 TimeStamp parent_stat_uncached = disk_.Stat(
"..", &err);
153 disk_.AllowStatCache(
true);
155 EXPECT_GT(disk_.Stat(
"FIle1", &err), 1);
157 EXPECT_GT(disk_.Stat(
"file1", &err), 1);
160 EXPECT_GT(disk_.Stat(
"subdir/subfile2", &err), 1);
162 EXPECT_GT(disk_.Stat(
"sUbdir\\suBFile1", &err), 1);
165 EXPECT_GT(disk_.Stat(
"..", &err), 1);
167 EXPECT_GT(disk_.Stat(
".", &err), 1);
169 EXPECT_GT(disk_.Stat(
"subdir", &err), 1);
171 EXPECT_GT(disk_.Stat(
"subdir/subsubdir", &err), 1);
175 EXPECT_EQ(disk_.Stat(
"subdir", &err),
176 disk_.Stat(
"subdir/.", &err));
178 EXPECT_EQ(disk_.Stat(
"subdir", &err),
179 disk_.Stat(
"subdir/subsubdir/..", &err));
182 EXPECT_EQ(disk_.Stat(
"..", &err), parent_stat_uncached);
184 EXPECT_EQ(disk_.Stat(
"subdir/subsubdir", &err),
185 disk_.Stat(
"subdir/subsubdir/.", &err));
189 string bad_path(
"cc:\\foo");
190 EXPECT_EQ(-1, disk_.Stat(bad_path, &err));
191 EXPECT_NE(
"", err); err.clear();
192 EXPECT_EQ(-1, disk_.Stat(bad_path, &err));
193 EXPECT_NE(
"", err); err.clear();
194 EXPECT_EQ(0, disk_.Stat(
"nosuchfile", &err));
196 EXPECT_EQ(0, disk_.Stat(
"nosuchdir/nosuchfile", &err));
205 disk_.ReadFile(
"foobar", &content, &err));
206 EXPECT_EQ(
"", content);
210 const char* kTestFile =
"testfile";
211 FILE* f = fopen(kTestFile,
"wb");
213 const char* kTestContent =
"test content\nok";
214 fprintf(f,
"%s", kTestContent);
215 ASSERT_EQ(0, fclose(f));
218 disk_.ReadFile(kTestFile, &content, &err));
219 EXPECT_EQ(kTestContent, content);
223 TEST_F(DiskInterfaceTest, MakeDirs) {
224 string path =
"path/with/double//slash/";
225 EXPECT_TRUE(disk_.MakeDirs(path));
226 FILE* f = fopen((path +
"a_file").c_str(),
"w");
228 EXPECT_EQ(0, fclose(f));
230 string path2 =
"another\\with\\back\\\\slashes\\";
231 EXPECT_TRUE(disk_.MakeDirs(path2));
232 FILE* f2 = fopen((path2 +
"a_file").c_str(),
"w");
234 EXPECT_EQ(0, fclose(f2));
238 TEST_F(DiskInterfaceTest, RemoveFile) {
239 const char* kFileName =
"file-to-remove";
240 ASSERT_TRUE(Touch(kFileName));
241 EXPECT_EQ(0, disk_.RemoveFile(kFileName));
242 EXPECT_EQ(1, disk_.RemoveFile(kFileName));
243 EXPECT_EQ(1, disk_.RemoveFile(
"does not exist"));
245 ASSERT_TRUE(Touch(kFileName));
246 EXPECT_EQ(0, system((std::string(
"attrib +R ") + kFileName).c_str()));
247 EXPECT_EQ(0, disk_.RemoveFile(kFileName));
248 EXPECT_EQ(1, disk_.RemoveFile(kFileName));
252 TEST_F(DiskInterfaceTest, RemoveDirectory) {
253 const char* kDirectoryName =
"directory-to-remove";
254 EXPECT_TRUE(disk_.MakeDir(kDirectoryName));
255 EXPECT_EQ(0, disk_.RemoveFile(kDirectoryName));
256 EXPECT_EQ(1, disk_.RemoveFile(kDirectoryName));
257 EXPECT_EQ(1, disk_.RemoveFile(
"does not exist"));
262 StatTest() : scan_(&state_, NULL, NULL, this, NULL, NULL) {}
265 TimeStamp Stat(
const string& path,
string* err)
const override;
266 bool WriteFile(
const string& path,
const string& contents,
271 bool MakeDir(
const string& path)
override {
275 Status ReadFile(
const string& path,
string* contents,
string* err)
override {
279 int RemoveFile(
const string& path)
override {
285 map<string, TimeStamp> mtimes_;
286 mutable vector<string> stats_;
289 TimeStamp StatTest::Stat(
const string& path,
string* err)
const {
290 stats_.push_back(path);
291 map<string, TimeStamp>::const_iterator i = mtimes_.find(path);
292 if (i == mtimes_.end())
297 TEST_F(StatTest, Simple) {
299 "build out: cat in\n"));
301 Node* out = GetNode(
"out");
303 EXPECT_TRUE(out->
Stat(
this, &err));
305 ASSERT_EQ(1u, stats_.size());
306 scan_.RecomputeDirty(out, NULL, NULL);
307 ASSERT_EQ(2u, stats_.size());
308 ASSERT_EQ(
"out", stats_[0]);
309 ASSERT_EQ(
"in", stats_[1]);
312 TEST_F(StatTest, TwoStep) {
314 "build out: cat mid\n"
315 "build mid: cat in\n"));
317 Node* out = GetNode(
"out");
319 EXPECT_TRUE(out->
Stat(
this, &err));
321 ASSERT_EQ(1u, stats_.size());
322 scan_.RecomputeDirty(out, NULL, NULL);
323 ASSERT_EQ(3u, stats_.size());
324 ASSERT_EQ(
"out", stats_[0]);
325 ASSERT_TRUE(GetNode(
"out")->dirty());
326 ASSERT_EQ(
"mid", stats_[1]);
327 ASSERT_TRUE(GetNode(
"mid")->dirty());
328 ASSERT_EQ(
"in", stats_[2]);
333 "build out: cat mid1 mid2\n"
334 "build mid1: cat in11 in12\n"
335 "build mid2: cat in21 in22\n"));
337 Node* out = GetNode(
"out");
339 EXPECT_TRUE(out->
Stat(
this, &err));
341 ASSERT_EQ(1u, stats_.size());
342 scan_.RecomputeDirty(out, NULL, NULL);
343 ASSERT_EQ(1u + 6u, stats_.size());
344 ASSERT_EQ(
"mid1", stats_[1]);
345 ASSERT_TRUE(GetNode(
"mid1")->dirty());
346 ASSERT_EQ(
"in11", stats_[2]);
349 TEST_F(StatTest, Middle) {
351 "build out: cat mid\n"
352 "build mid: cat in\n"));
358 Node* out = GetNode(
"out");
360 EXPECT_TRUE(out->
Stat(
this, &err));
362 ASSERT_EQ(1u, stats_.size());
363 scan_.RecomputeDirty(out, NULL, NULL);
364 ASSERT_FALSE(GetNode(
"in")->dirty());
365 ASSERT_TRUE(GetNode(
"mid")->dirty());
366 ASSERT_TRUE(GetNode(
"out")->dirty());
DependencyScan manages the process of scanning the files in a graph and updating the dirty/outputs_re...
Interface for accessing the disk.
Information about a node in the dependency graph: the file, whether it's dirty, mtime,...
bool Stat(DiskInterface *disk_interface, std::string *err)
Return false on error.
Implementation of DiskInterface that actually hits the disk.
A base test fixture that includes a State object with a builtin "cat" rule.
Abstract interface to object that tracks the status of a build: completion fraction,...
void AssertParse(State *state, const char *input, ManifestParserOptions opts)
int ReadFile(const string &path, string *contents, string *err)