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