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, VarInOutQuoteSpaces) {
00143   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
00144 "build a$ b: cat nospace with$ space nospace2\n"));
00145 
00146   Edge* edge = GetNode("a b")->in_edge();
00147   EXPECT_EQ("cat nospace \"with space\" nospace2 > \"a b\"",
00148       edge->EvaluateCommand());
00149 }
00150 
00151 // Regression test for https://github.com/martine/ninja/issues/380
00152 TEST_F(GraphTest, DepfileWithCanonicalizablePath) {
00153   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
00154 "rule catdep\n"
00155 "  depfile = $out.d\n"
00156 "  command = cat $in > $out\n"
00157 "build ./out.o: catdep ./foo.cc\n"));
00158   fs_.Create("foo.cc", "");
00159   fs_.Create("out.o.d", "out.o: bar/../foo.cc\n");
00160   fs_.Create("out.o", "");
00161 
00162   Edge* edge = GetNode("out.o")->in_edge();
00163   string err;
00164   EXPECT_TRUE(scan_.RecomputeDirty(edge, &err));
00165   ASSERT_EQ("", err);
00166 
00167   EXPECT_FALSE(GetNode("out.o")->dirty());
00168 }
00169 
00170 // Regression test for https://github.com/martine/ninja/issues/404
00171 TEST_F(GraphTest, DepfileRemoved) {
00172   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
00173 "rule catdep\n"
00174 "  depfile = $out.d\n"
00175 "  command = cat $in > $out\n"
00176 "build ./out.o: catdep ./foo.cc\n"));
00177   fs_.Create("foo.h", "");
00178   fs_.Create("foo.cc", "");
00179   fs_.Tick();
00180   fs_.Create("out.o.d", "out.o: foo.h\n");
00181   fs_.Create("out.o", "");
00182 
00183   Edge* edge = GetNode("out.o")->in_edge();
00184   string err;
00185   EXPECT_TRUE(scan_.RecomputeDirty(edge, &err));
00186   ASSERT_EQ("", err);
00187   EXPECT_FALSE(GetNode("out.o")->dirty());
00188 
00189   state_.Reset();
00190   fs_.RemoveFile("out.o.d");
00191   EXPECT_TRUE(scan_.RecomputeDirty(edge, &err));
00192   ASSERT_EQ("", err);
00193   EXPECT_TRUE(GetNode("out.o")->dirty());
00194 }
00195 
00196 // Check that rule-level variables are in scope for eval.
00197 TEST_F(GraphTest, RuleVariablesInScope) {
00198   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
00199 "rule r\n"
00200 "  depfile = x\n"
00201 "  command = depfile is $depfile\n"
00202 "build out: r in\n"));
00203   Edge* edge = GetNode("out")->in_edge();
00204   EXPECT_EQ("depfile is x", edge->EvaluateCommand());
00205 }
00206 
00207 // Check that build statements can override rule builtins like depfile.
00208 TEST_F(GraphTest, DepfileOverride) {
00209   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
00210 "rule r\n"
00211 "  depfile = x\n"
00212 "  command = unused\n"
00213 "build out: r in\n"
00214 "  depfile = y\n"));
00215   Edge* edge = GetNode("out")->in_edge();
00216   EXPECT_EQ("y", edge->GetBinding("depfile"));
00217 }
00218 
00219 // Check that overridden values show up in expansion of rule-level bindings.
00220 TEST_F(GraphTest, DepfileOverrideParent) {
00221   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
00222 "rule r\n"
00223 "  depfile = x\n"
00224 "  command = depfile is $depfile\n"
00225 "build out: r in\n"
00226 "  depfile = y\n"));
00227   Edge* edge = GetNode("out")->in_edge();
00228   EXPECT_EQ("depfile is y", edge->GetBinding("command"));
00229 }
00230 
00231 // Verify that building a nested phony rule prints "no work to do"
00232 TEST_F(GraphTest, NestedPhonyPrintsDone) {
00233   AssertParse(&state_,
00234 "build n1: phony \n"
00235 "build n2: phony n1\n"
00236   );
00237   string err;
00238   Edge* edge = GetNode("n2")->in_edge();
00239   EXPECT_TRUE(scan_.RecomputeDirty(edge, &err));
00240   ASSERT_EQ("", err);
00241 
00242   Plan plan_;
00243   EXPECT_TRUE(plan_.AddTarget(GetNode("n2"), &err));
00244   ASSERT_EQ("", err);
00245 
00246   EXPECT_EQ(0, plan_.command_edge_count());
00247   ASSERT_FALSE(plan_.more_to_do());
00248 }