Ninja
graph_test.cc
Go to the documentation of this file.
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 "graph.h"
00016 #include "build.h"
00017 
00018 #include "test.h"
00019 
00020 struct GraphTest : public StateTestWithBuiltinRules {
00021   GraphTest() : scan_(&state_, NULL, NULL, &fs_) {}
00022 
00023   VirtualFileSystem fs_;
00024   DependencyScan scan_;
00025 };
00026 
00027 TEST_F(GraphTest, MissingImplicit) {
00028   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
00029 "build out: cat in | implicit\n"));
00030   fs_.Create("in", "");
00031   fs_.Create("out", "");
00032 
00033   Edge* edge = GetNode("out")->in_edge();
00034   string err;
00035   EXPECT_TRUE(scan_.RecomputeDirty(edge, &err));
00036   ASSERT_EQ("", err);
00037 
00038   // A missing implicit dep *should* make the output dirty.
00039   // (In fact, a build will fail.)
00040   // This is a change from prior semantics of ninja.
00041   EXPECT_TRUE(GetNode("out")->dirty());
00042 }
00043 
00044 TEST_F(GraphTest, ModifiedImplicit) {
00045   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
00046 "build out: cat in | implicit\n"));
00047   fs_.Create("in", "");
00048   fs_.Create("out", "");
00049   fs_.Tick();
00050   fs_.Create("implicit", "");
00051 
00052   Edge* edge = GetNode("out")->in_edge();
00053   string err;
00054   EXPECT_TRUE(scan_.RecomputeDirty(edge, &err));
00055   ASSERT_EQ("", err);
00056 
00057   // A modified implicit dep should make the output dirty.
00058   EXPECT_TRUE(GetNode("out")->dirty());
00059 }
00060 
00061 TEST_F(GraphTest, FunkyMakefilePath) {
00062   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
00063 "rule catdep\n"
00064 "  depfile = $out.d\n"
00065 "  command = cat $in > $out\n"
00066 "build out.o: catdep foo.cc\n"));
00067   fs_.Create("foo.cc",  "");
00068   fs_.Create("out.o.d", "out.o: ./foo/../implicit.h\n");
00069   fs_.Create("out.o", "");
00070   fs_.Tick();
00071   fs_.Create("implicit.h", "");
00072 
00073   Edge* edge = GetNode("out.o")->in_edge();
00074   string err;
00075   EXPECT_TRUE(scan_.RecomputeDirty(edge, &err));
00076   ASSERT_EQ("", err);
00077 
00078   // implicit.h has changed, though our depfile refers to it with a
00079   // non-canonical path; we should still find it.
00080   EXPECT_TRUE(GetNode("out.o")->dirty());
00081 }
00082 
00083 TEST_F(GraphTest, ExplicitImplicit) {
00084   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
00085 "rule catdep\n"
00086 "  depfile = $out.d\n"
00087 "  command = cat $in > $out\n"
00088 "build implicit.h: cat data\n"
00089 "build out.o: catdep foo.cc || implicit.h\n"));
00090   fs_.Create("implicit.h", "");
00091   fs_.Create("foo.cc", "");
00092   fs_.Create("out.o.d", "out.o: implicit.h\n");
00093   fs_.Create("out.o", "");
00094   fs_.Tick();
00095   fs_.Create("data", "");
00096 
00097   Edge* edge = GetNode("out.o")->in_edge();
00098   string err;
00099   EXPECT_TRUE(scan_.RecomputeDirty(edge, &err));
00100   ASSERT_EQ("", err);
00101 
00102   // We have both an implicit and an explicit dep on implicit.h.
00103   // The implicit dep should "win" (in the sense that it should cause
00104   // the output to be dirty).
00105   EXPECT_TRUE(GetNode("out.o")->dirty());
00106 }
00107 
00108 TEST_F(GraphTest, PathWithCurrentDirectory) {
00109   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
00110 "rule catdep\n"
00111 "  depfile = $out.d\n"
00112 "  command = cat $in > $out\n"
00113 "build ./out.o: catdep ./foo.cc\n"));
00114   fs_.Create("foo.cc", "");
00115   fs_.Create("out.o.d", "out.o: foo.cc\n");
00116   fs_.Create("out.o", "");
00117 
00118   Edge* edge = GetNode("out.o")->in_edge();
00119   string err;
00120   EXPECT_TRUE(scan_.RecomputeDirty(edge, &err));
00121   ASSERT_EQ("", err);
00122 
00123   EXPECT_FALSE(GetNode("out.o")->dirty());
00124 }
00125 
00126 TEST_F(GraphTest, RootNodes) {
00127   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
00128 "build out1: cat in1\n"
00129 "build mid1: cat in1\n"
00130 "build out2: cat mid1\n"
00131 "build out3 out4: cat mid1\n"));
00132 
00133   string err;
00134   vector<Node*> root_nodes = state_.RootNodes(&err);
00135   EXPECT_EQ(4u, root_nodes.size());
00136   for (size_t i = 0; i < root_nodes.size(); ++i) {
00137     string name = root_nodes[i]->path();
00138     EXPECT_EQ("out", name.substr(0, 3));
00139   }
00140 }
00141 
00142 TEST_F(GraphTest, VarInOutPathEscaping) {
00143   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
00144 "build a$ b: cat no'space with$ space$$ no\"space2\n"));
00145 
00146   Edge* edge = GetNode("a b")->in_edge();
00147 #if _WIN32
00148   EXPECT_EQ("cat no'space \"with space$\" \"no\\\"space2\" > \"a b\"",
00149       edge->EvaluateCommand());
00150 #else
00151   EXPECT_EQ("cat 'no'\\''space' 'with space$' 'no\"space2' > 'a b'",
00152       edge->EvaluateCommand());
00153 #endif
00154 }
00155 
00156 // Regression test for https://github.com/martine/ninja/issues/380
00157 TEST_F(GraphTest, DepfileWithCanonicalizablePath) {
00158   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
00159 "rule catdep\n"
00160 "  depfile = $out.d\n"
00161 "  command = cat $in > $out\n"
00162 "build ./out.o: catdep ./foo.cc\n"));
00163   fs_.Create("foo.cc", "");
00164   fs_.Create("out.o.d", "out.o: bar/../foo.cc\n");
00165   fs_.Create("out.o", "");
00166 
00167   Edge* edge = GetNode("out.o")->in_edge();
00168   string err;
00169   EXPECT_TRUE(scan_.RecomputeDirty(edge, &err));
00170   ASSERT_EQ("", err);
00171 
00172   EXPECT_FALSE(GetNode("out.o")->dirty());
00173 }
00174 
00175 // Regression test for https://github.com/martine/ninja/issues/404
00176 TEST_F(GraphTest, DepfileRemoved) {
00177   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
00178 "rule catdep\n"
00179 "  depfile = $out.d\n"
00180 "  command = cat $in > $out\n"
00181 "build ./out.o: catdep ./foo.cc\n"));
00182   fs_.Create("foo.h", "");
00183   fs_.Create("foo.cc", "");
00184   fs_.Tick();
00185   fs_.Create("out.o.d", "out.o: foo.h\n");
00186   fs_.Create("out.o", "");
00187 
00188   Edge* edge = GetNode("out.o")->in_edge();
00189   string err;
00190   EXPECT_TRUE(scan_.RecomputeDirty(edge, &err));
00191   ASSERT_EQ("", err);
00192   EXPECT_FALSE(GetNode("out.o")->dirty());
00193 
00194   state_.Reset();
00195   fs_.RemoveFile("out.o.d");
00196   EXPECT_TRUE(scan_.RecomputeDirty(edge, &err));
00197   ASSERT_EQ("", err);
00198   EXPECT_TRUE(GetNode("out.o")->dirty());
00199 }
00200 
00201 // Check that rule-level variables are in scope for eval.
00202 TEST_F(GraphTest, RuleVariablesInScope) {
00203   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
00204 "rule r\n"
00205 "  depfile = x\n"
00206 "  command = depfile is $depfile\n"
00207 "build out: r in\n"));
00208   Edge* edge = GetNode("out")->in_edge();
00209   EXPECT_EQ("depfile is x", edge->EvaluateCommand());
00210 }
00211 
00212 // Check that build statements can override rule builtins like depfile.
00213 TEST_F(GraphTest, DepfileOverride) {
00214   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
00215 "rule r\n"
00216 "  depfile = x\n"
00217 "  command = unused\n"
00218 "build out: r in\n"
00219 "  depfile = y\n"));
00220   Edge* edge = GetNode("out")->in_edge();
00221   EXPECT_EQ("y", edge->GetBinding("depfile"));
00222 }
00223 
00224 // Check that overridden values show up in expansion of rule-level bindings.
00225 TEST_F(GraphTest, DepfileOverrideParent) {
00226   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
00227 "rule r\n"
00228 "  depfile = x\n"
00229 "  command = depfile is $depfile\n"
00230 "build out: r in\n"
00231 "  depfile = y\n"));
00232   Edge* edge = GetNode("out")->in_edge();
00233   EXPECT_EQ("depfile is y", edge->GetBinding("command"));
00234 }
00235 
00236 // Verify that building a nested phony rule prints "no work to do"
00237 TEST_F(GraphTest, NestedPhonyPrintsDone) {
00238   AssertParse(&state_,
00239 "build n1: phony \n"
00240 "build n2: phony n1\n"
00241   );
00242   string err;
00243   Edge* edge = GetNode("n2")->in_edge();
00244   EXPECT_TRUE(scan_.RecomputeDirty(edge, &err));
00245   ASSERT_EQ("", err);
00246 
00247   Plan plan_;
00248   EXPECT_TRUE(plan_.AddTarget(GetNode("n2"), &err));
00249   ASSERT_EQ("", err);
00250 
00251   EXPECT_EQ(0, plan_.command_edge_count());
00252   ASSERT_FALSE(plan_.more_to_do());
00253 }