diff options
Diffstat (limited to 'src/ninja_test.cc')
-rw-r--r-- | src/ninja_test.cc | 235 |
1 files changed, 235 insertions, 0 deletions
diff --git a/src/ninja_test.cc b/src/ninja_test.cc new file mode 100644 index 0000000..12ba93c --- /dev/null +++ b/src/ninja_test.cc @@ -0,0 +1,235 @@ +#include "ninja.h" + +#include <gtest/gtest.h> + +#include "build.h" +#include "parsers.h" +#include "test.h" + +void AssertParse(State* state, const char* input) { + ManifestParser parser(state, NULL); + string err; + ASSERT_TRUE(parser.Parse(input, &err)) << err; + ASSERT_EQ("", err); +} + +StateTestWithBuiltinRules::StateTestWithBuiltinRules() { + AssertParse(&state_, +"rule cat\n" +" command = cat $in > $out\n"); +} + +Node* StateTestWithBuiltinRules::GetNode(const string& path) { + return state_.GetNode(path); +} + +TEST(State, Basic) { + State state; + Rule* rule = new Rule("cat"); + string err; + EXPECT_TRUE(rule->ParseCommand("cat $in > $out", &err)); + ASSERT_EQ("", err); + state.AddRule(rule); + Edge* edge = state.AddEdge(rule); + state.AddInOut(edge, Edge::IN, "in1"); + state.AddInOut(edge, Edge::IN, "in2"); + state.AddInOut(edge, Edge::OUT, "out"); + + EXPECT_EQ("cat in1 in2 > out", edge->EvaluateCommand()); + + EXPECT_FALSE(state.GetNode("in1")->dirty()); + EXPECT_FALSE(state.GetNode("in2")->dirty()); + EXPECT_FALSE(state.GetNode("out")->dirty()); + + state.stat_cache()->GetFile("in1")->Touch(1); + EXPECT_TRUE(state.GetNode("in1")->dirty()); + EXPECT_FALSE(state.GetNode("in2")->dirty()); + EXPECT_TRUE(state.GetNode("out")->dirty()); +} + +struct TestEnv : public Env { + virtual string LookupVariable(const string& var) { + return vars[var]; + } + map<string, string> vars; +}; +TEST(EvalString, PlainText) { + EvalString str; + string err; + EXPECT_TRUE(str.Parse("plain text", &err)); + EXPECT_EQ("", err); + EXPECT_EQ("plain text", str.Evaluate(NULL)); +} +TEST(EvalString, OneVariable) { + EvalString str; + string err; + EXPECT_TRUE(str.Parse("hi $var", &err)); + EXPECT_EQ("", err); + EXPECT_EQ("hi $var", str.unparsed()); + TestEnv env; + EXPECT_EQ("hi ", str.Evaluate(&env)); + env.vars["var"] = "there"; + EXPECT_EQ("hi there", str.Evaluate(&env)); +} +TEST(EvalString, Error) { + EvalString str; + string err; + EXPECT_FALSE(str.Parse("bad $", &err)); + EXPECT_EQ("expected variable after $", err); +} +TEST(EvalString, Curlies) { + EvalString str; + string err; + EXPECT_TRUE(str.Parse("foo ${var}baz", &err)); + EXPECT_EQ("", err); + TestEnv env; + EXPECT_EQ("foo baz", str.Evaluate(&env)); + env.vars["var"] = "barbar"; + EXPECT_EQ("foo barbarbaz", str.Evaluate(&env)); +} + +struct StatTest : public StateTestWithBuiltinRules, + public DiskInterface { + // DiskInterface implementation. + virtual int Stat(const string& path); + virtual bool MakeDir(const string& path) { + assert(false); + return false; + } + virtual string ReadFile(const string& path, string* err) { + assert(false); + return ""; + } + + map<string, time_t> mtimes_; + vector<string> stats_; +}; + +int StatTest::Stat(const string& path) { + stats_.push_back(path); + map<string, time_t>::iterator i = mtimes_.find(path); + if (i == mtimes_.end()) + return 0; // File not found. + return i->second; +} + +TEST_F(StatTest, Simple) { + ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, +"build out: cat in\n")); + + Node* out = GetNode("out"); + out->file_->Stat(this); + ASSERT_EQ(1, stats_.size()); + Edge* edge = out->in_edge_; + edge->RecomputeDirty(NULL, this, NULL); + ASSERT_EQ(2, stats_.size()); + ASSERT_EQ("out", stats_[0]); + ASSERT_EQ("in", stats_[1]); +} + +TEST_F(StatTest, TwoStep) { + ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, +"build out: cat mid\n" +"build mid: cat in\n")); + + Node* out = GetNode("out"); + out->file_->Stat(this); + ASSERT_EQ(1, stats_.size()); + Edge* edge = out->in_edge_; + edge->RecomputeDirty(NULL, this, NULL); + ASSERT_EQ(3, stats_.size()); + ASSERT_EQ("out", stats_[0]); + ASSERT_TRUE(GetNode("out")->dirty_); + ASSERT_EQ("mid", stats_[1]); + ASSERT_TRUE(GetNode("mid")->dirty_); + ASSERT_EQ("in", stats_[2]); +} + +TEST_F(StatTest, Tree) { + ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, +"build out: cat mid1 mid2\n" +"build mid1: cat in11 in12\n" +"build mid2: cat in21 in22\n")); + + Node* out = GetNode("out"); + out->file_->Stat(this); + ASSERT_EQ(1, stats_.size()); + Edge* edge = out->in_edge_; + edge->RecomputeDirty(NULL, this, NULL); + ASSERT_EQ(1 + 6, stats_.size()); + ASSERT_EQ("mid1", stats_[1]); + ASSERT_TRUE(GetNode("mid1")->dirty_); + ASSERT_EQ("in11", stats_[2]); +} + +TEST_F(StatTest, Middle) { + ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, +"build out: cat mid\n" +"build mid: cat in\n")); + + mtimes_["in"] = 1; + mtimes_["mid"] = 0; // missing + mtimes_["out"] = 1; + + Node* out = GetNode("out"); + out->file_->Stat(this); + ASSERT_EQ(1, stats_.size()); + Edge* edge = out->in_edge_; + edge->RecomputeDirty(NULL, this, NULL); + ASSERT_FALSE(GetNode("in")->dirty_); + ASSERT_TRUE(GetNode("mid")->dirty_); + ASSERT_TRUE(GetNode("out")->dirty_); +} + +class DiskInterfaceTest : public testing::Test { +public: + virtual void SetUp() { + char buf[4 << 10]; + ASSERT_TRUE(getcwd(buf, sizeof(buf))); + start_dir_ = buf; + + char name_template[] = "DiskInterfaceTest-XXXXXX"; + char* name = mkdtemp(name_template); + temp_dir_name_ = name; + ASSERT_TRUE(name); + ASSERT_EQ(0, chdir(name)); + } + virtual void TearDown() { + ASSERT_EQ(0, chdir(start_dir_.c_str())); + ASSERT_EQ(0, system(("rm -rf " + temp_dir_name_).c_str())); + } + + string start_dir_; + string temp_dir_name_; + RealDiskInterface disk_; +}; + +TEST_F(DiskInterfaceTest, Stat) { + EXPECT_EQ(0, disk_.Stat("nosuchfile")); + + string too_long_name(512, 'x'); + EXPECT_EQ(-1, disk_.Stat(too_long_name)); + + ASSERT_EQ(0, system("touch file")); + EXPECT_GT(disk_.Stat("file"), 1); +} + +TEST_F(DiskInterfaceTest, ReadFile) { + string err; + EXPECT_EQ("", disk_.ReadFile("foobar", &err)); + EXPECT_EQ("", err); + + const char* kTestFile = "testfile"; + FILE* f = fopen(kTestFile, "wb"); + ASSERT_TRUE(f); + const char* kTestContent = "test content\nok"; + fprintf(f, "%s", kTestContent); + ASSERT_EQ(0, fclose(f)); + + EXPECT_EQ(kTestContent, disk_.ReadFile(kTestFile, &err)); + EXPECT_EQ("", err); +} + +TEST_F(DiskInterfaceTest, MakeDirs) { + EXPECT_TRUE(disk_.MakeDirs("path/with/double//slash/")); +} |