1 // Copyright 2011 Google Inc. All Rights Reserved.
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
7 // http://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
19 struct GraphTest : public StateTestWithBuiltinRules {
20 GraphTest() : scan_(&state_, NULL, &fs_) {}
22 VirtualFileSystem fs_;
26 TEST_F(GraphTest, MissingImplicit) {
27 ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
28 "build out: cat in | implicit\n"));
29 fs_.Create("in", 1, "");
30 fs_.Create("out", 1, "");
32 Edge* edge = GetNode("out")->in_edge();
34 EXPECT_TRUE(scan_.RecomputeDirty(edge, &err));
37 // A missing implicit dep *should* make the output dirty.
38 // (In fact, a build will fail.)
39 // This is a change from prior semantics of ninja.
40 EXPECT_TRUE(GetNode("out")->dirty());
43 TEST_F(GraphTest, ModifiedImplicit) {
44 ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
45 "build out: cat in | implicit\n"));
46 fs_.Create("in", 1, "");
47 fs_.Create("out", 1, "");
48 fs_.Create("implicit", 2, "");
50 Edge* edge = GetNode("out")->in_edge();
52 EXPECT_TRUE(scan_.RecomputeDirty(edge, &err));
55 // A modified implicit dep should make the output dirty.
56 EXPECT_TRUE(GetNode("out")->dirty());
59 TEST_F(GraphTest, FunkyMakefilePath) {
60 ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
63 " command = cat $in > $out\n"
64 "build out.o: catdep foo.cc\n"));
65 fs_.Create("implicit.h", 2, "");
66 fs_.Create("foo.cc", 1, "");
67 fs_.Create("out.o.d", 1, "out.o: ./foo/../implicit.h\n");
68 fs_.Create("out.o", 1, "");
70 Edge* edge = GetNode("out.o")->in_edge();
72 EXPECT_TRUE(scan_.RecomputeDirty(edge, &err));
75 // implicit.h has changed, though our depfile refers to it with a
76 // non-canonical path; we should still find it.
77 EXPECT_TRUE(GetNode("out.o")->dirty());
80 TEST_F(GraphTest, ExplicitImplicit) {
81 ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
84 " command = cat $in > $out\n"
85 "build implicit.h: cat data\n"
86 "build out.o: catdep foo.cc || implicit.h\n"));
87 fs_.Create("data", 2, "");
88 fs_.Create("implicit.h", 1, "");
89 fs_.Create("foo.cc", 1, "");
90 fs_.Create("out.o.d", 1, "out.o: implicit.h\n");
91 fs_.Create("out.o", 1, "");
93 Edge* edge = GetNode("out.o")->in_edge();
95 EXPECT_TRUE(scan_.RecomputeDirty(edge, &err));
98 // We have both an implicit and an explicit dep on implicit.h.
99 // The implicit dep should "win" (in the sense that it should cause
100 // the output to be dirty).
101 EXPECT_TRUE(GetNode("out.o")->dirty());
104 TEST_F(GraphTest, PathWithCurrentDirectory) {
105 ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
107 " depfile = $out.d\n"
108 " command = cat $in > $out\n"
109 "build ./out.o: catdep ./foo.cc\n"));
110 fs_.Create("foo.cc", 1, "");
111 fs_.Create("out.o.d", 1, "out.o: foo.cc\n");
112 fs_.Create("out.o", 1, "");
114 Edge* edge = GetNode("out.o")->in_edge();
116 EXPECT_TRUE(scan_.RecomputeDirty(edge, &err));
119 EXPECT_FALSE(GetNode("out.o")->dirty());
122 TEST_F(GraphTest, RootNodes) {
123 ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
124 "build out1: cat in1\n"
125 "build mid1: cat in1\n"
126 "build out2: cat mid1\n"
127 "build out3 out4: cat mid1\n"));
130 vector<Node*> root_nodes = state_.RootNodes(&err);
131 EXPECT_EQ(4u, root_nodes.size());
132 for (size_t i = 0; i < root_nodes.size(); ++i) {
133 string name = root_nodes[i]->path();
134 EXPECT_EQ("out", name.substr(0, 3));
138 TEST_F(GraphTest, VarInOutQuoteSpaces) {
139 ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
140 "build a$ b: cat nospace with$ space nospace2\n"));
142 Edge* edge = GetNode("a b")->in_edge();
143 EXPECT_EQ("cat nospace \"with space\" nospace2 > \"a b\"",
144 edge->EvaluateCommand());
147 // Regression test for https://github.com/martine/ninja/issues/380
148 TEST_F(GraphTest, DepfileWithCanonicalizablePath) {
149 ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
151 " depfile = $out.d\n"
152 " command = cat $in > $out\n"
153 "build ./out.o: catdep ./foo.cc\n"));
154 fs_.Create("foo.cc", 1, "");
155 fs_.Create("out.o.d", 1, "out.o: bar/../foo.cc\n");
156 fs_.Create("out.o", 1, "");
158 Edge* edge = GetNode("out.o")->in_edge();
160 EXPECT_TRUE(scan_.RecomputeDirty(edge, &err));
163 EXPECT_FALSE(GetNode("out.o")->dirty());
166 // Regression test for https://github.com/martine/ninja/issues/404
167 TEST_F(GraphTest, DepfileRemoved) {
168 ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
170 " depfile = $out.d\n"
171 " command = cat $in > $out\n"
172 "build ./out.o: catdep ./foo.cc\n"));
173 fs_.Create("foo.h", 1, "");
174 fs_.Create("foo.cc", 1, "");
175 fs_.Create("out.o.d", 2, "out.o: foo.h\n");
176 fs_.Create("out.o", 2, "");
178 Edge* edge = GetNode("out.o")->in_edge();
180 EXPECT_TRUE(scan_.RecomputeDirty(edge, &err));
182 EXPECT_FALSE(GetNode("out.o")->dirty());
185 fs_.RemoveFile("out.o.d");
186 EXPECT_TRUE(scan_.RecomputeDirty(edge, &err));
188 EXPECT_TRUE(GetNode("out.o")->dirty());
191 // Check that rule-level variables are in scope for eval.
192 TEST_F(GraphTest, RuleVariablesInScope) {
193 ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
196 " command = depfile is $depfile\n"
197 "build out: r in\n"));
198 Edge* edge = GetNode("out")->in_edge();
199 EXPECT_EQ("depfile is x", edge->EvaluateCommand());
202 // Check that build statements can override rule builtins like depfile.
203 TEST_F(GraphTest, DepfileOverride) {
204 ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
207 " command = unused\n"
210 Edge* edge = GetNode("out")->in_edge();
211 EXPECT_EQ("y", edge->GetBinding("depfile"));
214 // Check that overridden values show up in expansion of rule-level bindings.
215 TEST_F(GraphTest, DepfileOverrideParent) {
216 ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
219 " command = depfile is $depfile\n"
222 Edge* edge = GetNode("out")->in_edge();
223 EXPECT_EQ("depfile is y", edge->GetBinding("command"));