Ninja
|
00001 // Copyright 2011 Google Inc. All Rights Reserved. 00002 // 00003 // Licensed under the Apache License, Version 2.0 (the "License"); 00004 // you may not use this file except in compliance with the License. 00005 // You may obtain a copy of the License at 00006 // 00007 // http://www.apache.org/licenses/LICENSE-2.0 00008 // 00009 // Unless required by applicable law or agreed to in writing, software 00010 // distributed under the License is distributed on an "AS IS" BASIS, 00011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00012 // See the License for the specific language governing permissions and 00013 // limitations under the License. 00014 00015 #include <gtest/gtest.h> 00016 00017 #ifdef _WIN32 00018 #include <io.h> 00019 #include <windows.h> 00020 #endif 00021 00022 #include "disk_interface.h" 00023 #include "graph.h" 00024 #include "test.h" 00025 00026 namespace { 00027 00028 struct DiskInterfaceTest : public testing::Test { 00029 virtual void SetUp() { 00030 // These tests do real disk accesses, so create a temp dir. 00031 temp_dir_.CreateAndEnter("Ninja-DiskInterfaceTest"); 00032 } 00033 00034 virtual void TearDown() { 00035 temp_dir_.Cleanup(); 00036 } 00037 00038 bool Touch(const char* path) { 00039 FILE *f = fopen(path, "w"); 00040 if (!f) 00041 return false; 00042 return fclose(f) == 0; 00043 } 00044 00045 ScopedTempDir temp_dir_; 00046 RealDiskInterface disk_; 00047 }; 00048 00049 TEST_F(DiskInterfaceTest, StatMissingFile) { 00050 EXPECT_EQ(0, disk_.Stat("nosuchfile")); 00051 00052 // On Windows, the errno for a file in a nonexistent directory 00053 // is different. 00054 EXPECT_EQ(0, disk_.Stat("nosuchdir/nosuchfile")); 00055 00056 // On POSIX systems, the errno is different if a component of the 00057 // path prefix is not a directory. 00058 ASSERT_TRUE(Touch("notadir")); 00059 EXPECT_EQ(0, disk_.Stat("notadir/nosuchfile")); 00060 } 00061 00062 TEST_F(DiskInterfaceTest, StatBadPath) { 00063 disk_.quiet_ = true; 00064 #ifdef _WIN32 00065 string bad_path("cc:\\foo"); 00066 EXPECT_EQ(-1, disk_.Stat(bad_path)); 00067 #else 00068 string too_long_name(512, 'x'); 00069 EXPECT_EQ(-1, disk_.Stat(too_long_name)); 00070 #endif 00071 disk_.quiet_ = false; 00072 } 00073 00074 TEST_F(DiskInterfaceTest, StatExistingFile) { 00075 ASSERT_TRUE(Touch("file")); 00076 EXPECT_GT(disk_.Stat("file"), 1); 00077 } 00078 00079 TEST_F(DiskInterfaceTest, ReadFile) { 00080 string err; 00081 EXPECT_EQ("", disk_.ReadFile("foobar", &err)); 00082 EXPECT_EQ("", err); 00083 00084 const char* kTestFile = "testfile"; 00085 FILE* f = fopen(kTestFile, "wb"); 00086 ASSERT_TRUE(f); 00087 const char* kTestContent = "test content\nok"; 00088 fprintf(f, "%s", kTestContent); 00089 ASSERT_EQ(0, fclose(f)); 00090 00091 EXPECT_EQ(kTestContent, disk_.ReadFile(kTestFile, &err)); 00092 EXPECT_EQ("", err); 00093 } 00094 00095 TEST_F(DiskInterfaceTest, MakeDirs) { 00096 EXPECT_TRUE(disk_.MakeDirs("path/with/double//slash/")); 00097 } 00098 00099 TEST_F(DiskInterfaceTest, RemoveFile) { 00100 const char* kFileName = "file-to-remove"; 00101 ASSERT_TRUE(Touch(kFileName)); 00102 EXPECT_EQ(0, disk_.RemoveFile(kFileName)); 00103 EXPECT_EQ(1, disk_.RemoveFile(kFileName)); 00104 EXPECT_EQ(1, disk_.RemoveFile("does not exist")); 00105 } 00106 00107 struct StatTest : public StateTestWithBuiltinRules, 00108 public DiskInterface { 00109 StatTest() : scan_(&state_, NULL, NULL, this) {} 00110 00111 // DiskInterface implementation. 00112 virtual TimeStamp Stat(const string& path); 00113 virtual bool WriteFile(const string& path, const string& contents) { 00114 assert(false); 00115 return true; 00116 } 00117 virtual bool MakeDir(const string& path) { 00118 assert(false); 00119 return false; 00120 } 00121 virtual string ReadFile(const string& path, string* err) { 00122 assert(false); 00123 return ""; 00124 } 00125 virtual int RemoveFile(const string& path) { 00126 assert(false); 00127 return 0; 00128 } 00129 00130 DependencyScan scan_; 00131 map<string, TimeStamp> mtimes_; 00132 vector<string> stats_; 00133 }; 00134 00135 TimeStamp StatTest::Stat(const string& path) { 00136 stats_.push_back(path); 00137 map<string, TimeStamp>::iterator i = mtimes_.find(path); 00138 if (i == mtimes_.end()) 00139 return 0; // File not found. 00140 return i->second; 00141 } 00142 00143 TEST_F(StatTest, Simple) { 00144 ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, 00145 "build out: cat in\n")); 00146 00147 Node* out = GetNode("out"); 00148 out->Stat(this); 00149 ASSERT_EQ(1u, stats_.size()); 00150 scan_.RecomputeDirty(out->in_edge(), NULL); 00151 ASSERT_EQ(2u, stats_.size()); 00152 ASSERT_EQ("out", stats_[0]); 00153 ASSERT_EQ("in", stats_[1]); 00154 } 00155 00156 TEST_F(StatTest, TwoStep) { 00157 ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, 00158 "build out: cat mid\n" 00159 "build mid: cat in\n")); 00160 00161 Node* out = GetNode("out"); 00162 out->Stat(this); 00163 ASSERT_EQ(1u, stats_.size()); 00164 scan_.RecomputeDirty(out->in_edge(), NULL); 00165 ASSERT_EQ(3u, stats_.size()); 00166 ASSERT_EQ("out", stats_[0]); 00167 ASSERT_TRUE(GetNode("out")->dirty()); 00168 ASSERT_EQ("mid", stats_[1]); 00169 ASSERT_TRUE(GetNode("mid")->dirty()); 00170 ASSERT_EQ("in", stats_[2]); 00171 } 00172 00173 TEST_F(StatTest, Tree) { 00174 ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, 00175 "build out: cat mid1 mid2\n" 00176 "build mid1: cat in11 in12\n" 00177 "build mid2: cat in21 in22\n")); 00178 00179 Node* out = GetNode("out"); 00180 out->Stat(this); 00181 ASSERT_EQ(1u, stats_.size()); 00182 scan_.RecomputeDirty(out->in_edge(), NULL); 00183 ASSERT_EQ(1u + 6u, stats_.size()); 00184 ASSERT_EQ("mid1", stats_[1]); 00185 ASSERT_TRUE(GetNode("mid1")->dirty()); 00186 ASSERT_EQ("in11", stats_[2]); 00187 } 00188 00189 TEST_F(StatTest, Middle) { 00190 ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, 00191 "build out: cat mid\n" 00192 "build mid: cat in\n")); 00193 00194 mtimes_["in"] = 1; 00195 mtimes_["mid"] = 0; // missing 00196 mtimes_["out"] = 1; 00197 00198 Node* out = GetNode("out"); 00199 out->Stat(this); 00200 ASSERT_EQ(1u, stats_.size()); 00201 scan_.RecomputeDirty(out->in_edge(), NULL); 00202 ASSERT_FALSE(GetNode("in")->dirty()); 00203 ASSERT_TRUE(GetNode("mid")->dirty()); 00204 ASSERT_TRUE(GetNode("out")->dirty()); 00205 } 00206 00207 } // namespace