X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fgraph_test.cc;h=723e8ead4881c97a9546b42a969086e378fd9471;hb=cc39240a10fb040fca80bf3669245f2f2d5736c5;hp=382d352defef218328407d49dbf63a6bca7f29f1;hpb=6aa1b4b6d3d2d3efa55f91649271ed253ef5cab7;p=platform%2Fupstream%2Fninja.git diff --git a/src/graph_test.cc b/src/graph_test.cc index 382d352..723e8ea 100644 --- a/src/graph_test.cc +++ b/src/graph_test.cc @@ -105,6 +105,50 @@ TEST_F(GraphTest, ExplicitImplicit) { EXPECT_TRUE(GetNode("out.o")->dirty()); } +TEST_F(GraphTest, ImplicitOutputParse) { + ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, +"build out | out.imp: cat in\n")); + + Edge* edge = GetNode("out")->in_edge(); + EXPECT_EQ(2, edge->outputs_.size()); + EXPECT_EQ("out", edge->outputs_[0]->path()); + EXPECT_EQ("out.imp", edge->outputs_[1]->path()); + EXPECT_EQ(1, edge->implicit_outs_); + EXPECT_EQ(edge, GetNode("out.imp")->in_edge()); +} + +TEST_F(GraphTest, ImplicitOutputMissing) { + ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, +"build out | out.imp: cat in\n")); + fs_.Create("in", ""); + fs_.Create("out", ""); + + Edge* edge = GetNode("out")->in_edge(); + string err; + EXPECT_TRUE(scan_.RecomputeDirty(edge, &err)); + ASSERT_EQ("", err); + + EXPECT_TRUE(GetNode("out")->dirty()); + EXPECT_TRUE(GetNode("out.imp")->dirty()); +} + +TEST_F(GraphTest, ImplicitOutputOutOfDate) { + ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, +"build out | out.imp: cat in\n")); + fs_.Create("out.imp", ""); + fs_.Tick(); + fs_.Create("in", ""); + fs_.Create("out", ""); + + Edge* edge = GetNode("out")->in_edge(); + string err; + EXPECT_TRUE(scan_.RecomputeDirty(edge, &err)); + ASSERT_EQ("", err); + + EXPECT_TRUE(GetNode("out")->dirty()); + EXPECT_TRUE(GetNode("out.imp")->dirty()); +} + TEST_F(GraphTest, PathWithCurrentDirectory) { ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, "rule catdep\n" @@ -153,7 +197,7 @@ TEST_F(GraphTest, VarInOutPathEscaping) { #endif } -// Regression test for https://github.com/martine/ninja/issues/380 +// Regression test for https://github.com/ninja-build/ninja/issues/380 TEST_F(GraphTest, DepfileWithCanonicalizablePath) { ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, "rule catdep\n" @@ -172,7 +216,7 @@ TEST_F(GraphTest, DepfileWithCanonicalizablePath) { EXPECT_FALSE(GetNode("out.o")->dirty()); } -// Regression test for https://github.com/martine/ninja/issues/404 +// Regression test for https://github.com/ninja-build/ninja/issues/404 TEST_F(GraphTest, DepfileRemoved) { ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, "rule catdep\n" @@ -252,6 +296,81 @@ TEST_F(GraphTest, NestedPhonyPrintsDone) { ASSERT_FALSE(plan_.more_to_do()); } +// Verify that cycles in graphs with multiple outputs are handled correctly +// in RecomputeDirty() and don't cause deps to be loaded multiple times. +TEST_F(GraphTest, CycleWithLengthZeroFromDepfile) { + AssertParse(&state_, +"rule deprule\n" +" depfile = dep.d\n" +" command = unused\n" +"build a b: deprule\n" + ); + fs_.Create("dep.d", "a: b\n"); + + string err; + Edge* edge = GetNode("a")->in_edge(); + EXPECT_TRUE(scan_.RecomputeDirty(edge, &err)); + ASSERT_EQ("", err); + + // Despite the depfile causing edge to be a cycle (it has outputs a and b, + // but the depfile also adds b as an input), the deps should have been loaded + // only once: + EXPECT_EQ(1, edge->inputs_.size()); + EXPECT_EQ("b", edge->inputs_[0]->path()); +} + +// Like CycleWithLengthZeroFromDepfile but with a higher cycle length. +TEST_F(GraphTest, CycleWithLengthOneFromDepfile) { + AssertParse(&state_, +"rule deprule\n" +" depfile = dep.d\n" +" command = unused\n" +"rule r\n" +" command = unused\n" +"build a b: deprule\n" +"build c: r b\n" + ); + fs_.Create("dep.d", "a: c\n"); + + string err; + Edge* edge = GetNode("a")->in_edge(); + EXPECT_TRUE(scan_.RecomputeDirty(edge, &err)); + ASSERT_EQ("", err); + + // Despite the depfile causing edge to be a cycle (|edge| has outputs a and b, + // but c's in_edge has b as input but the depfile also adds |edge| as + // output)), the deps should have been loaded only once: + EXPECT_EQ(1, edge->inputs_.size()); + EXPECT_EQ("c", edge->inputs_[0]->path()); +} + +// Like CycleWithLengthOneFromDepfile but building a node one hop away from +// the cycle. +TEST_F(GraphTest, CycleWithLengthOneFromDepfileOneHopAway) { + AssertParse(&state_, +"rule deprule\n" +" depfile = dep.d\n" +" command = unused\n" +"rule r\n" +" command = unused\n" +"build a b: deprule\n" +"build c: r b\n" +"build d: r a\n" + ); + fs_.Create("dep.d", "a: c\n"); + + string err; + EXPECT_TRUE(scan_.RecomputeDirty(GetNode("d")->in_edge(), &err)); + ASSERT_EQ("", err); + + // Despite the depfile causing edge to be a cycle (|edge| has outputs a and b, + // but c's in_edge has b as input but the depfile also adds |edge| as + // output)), the deps should have been loaded only once: + Edge* edge = GetNode("a")->in_edge(); + EXPECT_EQ(1, edge->inputs_.size()); + EXPECT_EQ("c", edge->inputs_[0]->path()); +} + #ifdef _WIN32 TEST_F(GraphTest, Decanonicalize) { ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,