15 #include <gtest/gtest.h>
28 struct DiskInterfaceTest :
public testing::Test {
29 virtual void SetUp() {
31 temp_dir_.CreateAndEnter(
"Ninja-DiskInterfaceTest");
34 virtual void TearDown() {
38 bool Touch(
const char* path) {
39 FILE *f = fopen(path,
"w");
42 return fclose(f) == 0;
49 TEST_F(DiskInterfaceTest, StatMissingFile) {
50 EXPECT_EQ(0, disk_.Stat(
"nosuchfile"));
54 EXPECT_EQ(0, disk_.Stat(
"nosuchdir/nosuchfile"));
58 ASSERT_TRUE(Touch(
"notadir"));
59 EXPECT_EQ(0, disk_.Stat(
"notadir/nosuchfile"));
62 TEST_F(DiskInterfaceTest, StatBadPath) {
65 string bad_path(
"cc:\\foo");
66 EXPECT_EQ(-1, disk_.Stat(bad_path));
68 string too_long_name(512,
'x');
69 EXPECT_EQ(-1, disk_.Stat(too_long_name));
74 TEST_F(DiskInterfaceTest, StatExistingFile) {
75 ASSERT_TRUE(Touch(
"file"));
76 EXPECT_GT(disk_.Stat(
"file"), 1);
79 TEST_F(DiskInterfaceTest, StatExistingDir) {
80 ASSERT_TRUE(disk_.MakeDir(
"subdir"));
81 ASSERT_TRUE(disk_.MakeDir(
"subdir/subsubdir"));
82 EXPECT_GT(disk_.Stat(
"."), 1);
83 EXPECT_GT(disk_.Stat(
"subdir"), 1);
84 EXPECT_GT(disk_.Stat(
"subdir/subsubdir"), 1);
86 EXPECT_EQ(disk_.Stat(
"subdir"), disk_.Stat(
"subdir/."));
87 EXPECT_EQ(disk_.Stat(
"subdir"), disk_.Stat(
"subdir/subsubdir/.."));
88 EXPECT_EQ(disk_.Stat(
"subdir/subsubdir"), disk_.Stat(
"subdir/subsubdir/."));
92 TEST_F(DiskInterfaceTest, StatCache) {
93 disk_.AllowStatCache(
true);
95 ASSERT_TRUE(Touch(
"file1"));
96 ASSERT_TRUE(Touch(
"fiLE2"));
97 ASSERT_TRUE(disk_.MakeDir(
"subdir"));
98 ASSERT_TRUE(disk_.MakeDir(
"subdir/subsubdir"));
99 ASSERT_TRUE(Touch(
"subdir\\subfile1"));
100 ASSERT_TRUE(Touch(
"subdir\\SUBFILE2"));
101 ASSERT_TRUE(Touch(
"subdir\\SUBFILE3"));
103 EXPECT_GT(disk_.Stat(
"FIle1"), 1);
104 EXPECT_GT(disk_.Stat(
"file1"), 1);
106 EXPECT_GT(disk_.Stat(
"subdir/subfile2"), 1);
107 EXPECT_GT(disk_.Stat(
"sUbdir\\suBFile1"), 1);
109 EXPECT_GT(disk_.Stat(
"."), 1);
110 EXPECT_GT(disk_.Stat(
"subdir"), 1);
111 EXPECT_GT(disk_.Stat(
"subdir/subsubdir"), 1);
113 EXPECT_EQ(disk_.Stat(
"subdir"), disk_.Stat(
"subdir/."));
114 EXPECT_EQ(disk_.Stat(
"subdir"), disk_.Stat(
"subdir/subsubdir/.."));
115 EXPECT_EQ(disk_.Stat(
"subdir/subsubdir"), disk_.Stat(
"subdir/subsubdir/."));
119 string bad_path(
"cc:\\foo");
120 EXPECT_EQ(-1, disk_.Stat(bad_path));
121 EXPECT_EQ(-1, disk_.Stat(bad_path));
122 EXPECT_EQ(0, disk_.Stat(
"nosuchfile"));
123 EXPECT_EQ(0, disk_.Stat(
"nosuchdir/nosuchfile"));
129 EXPECT_EQ(
"", disk_.ReadFile(
"foobar", &err));
132 const char* kTestFile =
"testfile";
133 FILE* f = fopen(kTestFile,
"wb");
135 const char* kTestContent =
"test content\nok";
136 fprintf(f,
"%s", kTestContent);
137 ASSERT_EQ(0, fclose(f));
139 EXPECT_EQ(kTestContent, disk_.ReadFile(kTestFile, &err));
143 TEST_F(DiskInterfaceTest, MakeDirs) {
144 string path =
"path/with/double//slash/";
145 EXPECT_TRUE(disk_.MakeDirs(path.c_str()));
146 FILE* f = fopen((path +
"a_file").c_str(),
"w");
148 EXPECT_EQ(0, fclose(f));
150 string path2 =
"another\\with\\back\\\\slashes\\";
151 EXPECT_TRUE(disk_.MakeDirs(path2.c_str()));
152 FILE* f2 = fopen((path2 +
"a_file").c_str(),
"w");
154 EXPECT_EQ(0, fclose(f2));
158 TEST_F(DiskInterfaceTest, RemoveFile) {
159 const char* kFileName =
"file-to-remove";
160 ASSERT_TRUE(Touch(kFileName));
161 EXPECT_EQ(0, disk_.RemoveFile(kFileName));
162 EXPECT_EQ(1, disk_.RemoveFile(kFileName));
163 EXPECT_EQ(1, disk_.RemoveFile(
"does not exist"));
168 StatTest() : scan_(&state_, NULL, NULL, this) {}
172 virtual bool WriteFile(
const string& path,
const string& contents) {
176 virtual bool MakeDir(
const string& path) {
180 virtual string ReadFile(
const string& path,
string* err) {
190 map<string, TimeStamp> mtimes_;
191 mutable vector<string> stats_;
194 TimeStamp StatTest::Stat(
const string& path)
const {
195 stats_.push_back(path);
196 map<string, TimeStamp>::const_iterator i = mtimes_.find(path);
197 if (i == mtimes_.end())
202 TEST_F(StatTest, Simple) {
204 "build out: cat in\n"));
206 Node* out = GetNode(
"out");
208 ASSERT_EQ(1u, stats_.size());
209 scan_.RecomputeDirty(out->
in_edge(), NULL);
210 ASSERT_EQ(2u, stats_.size());
211 ASSERT_EQ(
"out", stats_[0]);
212 ASSERT_EQ(
"in", stats_[1]);
215 TEST_F(StatTest, TwoStep) {
217 "build out: cat mid\n"
218 "build mid: cat in\n"));
220 Node* out = GetNode(
"out");
222 ASSERT_EQ(1u, stats_.size());
223 scan_.RecomputeDirty(out->
in_edge(), NULL);
224 ASSERT_EQ(3u, stats_.size());
225 ASSERT_EQ(
"out", stats_[0]);
226 ASSERT_TRUE(GetNode(
"out")->dirty());
227 ASSERT_EQ(
"mid", stats_[1]);
228 ASSERT_TRUE(GetNode(
"mid")->dirty());
229 ASSERT_EQ(
"in", stats_[2]);
234 "build out: cat mid1 mid2\n"
235 "build mid1: cat in11 in12\n"
236 "build mid2: cat in21 in22\n"));
238 Node* out = GetNode(
"out");
240 ASSERT_EQ(1u, stats_.size());
241 scan_.RecomputeDirty(out->
in_edge(), NULL);
242 ASSERT_EQ(1u + 6u, stats_.size());
243 ASSERT_EQ(
"mid1", stats_[1]);
244 ASSERT_TRUE(GetNode(
"mid1")->dirty());
245 ASSERT_EQ(
"in11", stats_[2]);
248 TEST_F(StatTest, Middle) {
250 "build out: cat mid\n"
251 "build mid: cat in\n"));
257 Node* out = GetNode(
"out");
259 ASSERT_EQ(1u, stats_.size());
260 scan_.RecomputeDirty(out->
in_edge(), NULL);
261 ASSERT_FALSE(GetNode(
"in")->dirty());
262 ASSERT_TRUE(GetNode(
"mid")->dirty());
263 ASSERT_TRUE(GetNode(
"out")->dirty());
virtual string ReadFile(const string &path, string *err)=0
Read a file to a string. Fill in |err| on error.
Information about a node in the dependency graph: the file, whether it's dirty, mtime, etc.
Interface for accessing the disk.
void AssertParse(State *state, const char *input)
A base test fixture that includes a State object with a builtin "cat" rule.
bool Stat(DiskInterface *disk_interface)
Return true if the file exists (mtime_ got a value).
virtual bool WriteFile(const string &path, const string &contents)=0
Create a file, with the specified name and contents Returns true on success, false on failure...
Implementation of DiskInterface that actually hits the disk.
int ReadFile(const string &path, string *contents, string *err)
Read a file to a string (in text mode: with CRLF conversion on Windows).
DependencyScan manages the process of scanning the files in a graph and updating the dirty/outputs_re...
virtual int RemoveFile(const string &path)=0
Remove the file named path.
virtual TimeStamp Stat(const string &path) const =0
stat() a file, returning the mtime, or 0 if missing and -1 on other errors.
virtual bool MakeDir(const string &path)=0
Create a directory, returning false on failure.