1 // Copyright 2011 Google Inc. All Rights Reserved.
2 //
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
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
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.
14 
15 #include "graph.h"
16 #include "build.h"
17 
18 #include "test.h"
19 
20 using namespace std;
21 
22 struct GraphTest : public StateTestWithBuiltinRules {
GraphTestGraphTest23   GraphTest() : scan_(&state_, NULL, NULL, &fs_, NULL) {}
24 
25   VirtualFileSystem fs_;
26   DependencyScan scan_;
27 };
28 
TEST_F(GraphTest, MissingImplicit)29 TEST_F(GraphTest, MissingImplicit) {
30   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
31 "build out: cat in | implicit\n"));
32   fs_.Create("in", "");
33   fs_.Create("out", "");
34 
35   string err;
36   EXPECT_TRUE(scan_.RecomputeDirty(GetNode("out"), NULL, &err));
37   ASSERT_EQ("", err);
38 
39   // A missing implicit dep *should* make the output dirty.
40   // (In fact, a build will fail.)
41   // This is a change from prior semantics of ninja.
42   EXPECT_TRUE(GetNode("out")->dirty());
43 }
44 
TEST_F(GraphTest, ModifiedImplicit)45 TEST_F(GraphTest, ModifiedImplicit) {
46   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
47 "build out: cat in | implicit\n"));
48   fs_.Create("in", "");
49   fs_.Create("out", "");
50   fs_.Tick();
51   fs_.Create("implicit", "");
52 
53   string err;
54   EXPECT_TRUE(scan_.RecomputeDirty(GetNode("out"), NULL, &err));
55   ASSERT_EQ("", err);
56 
57   // A modified implicit dep should make the output dirty.
58   EXPECT_TRUE(GetNode("out")->dirty());
59 }
60 
TEST_F(GraphTest, FunkyMakefilePath)61 TEST_F(GraphTest, FunkyMakefilePath) {
62   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
63 "rule catdep\n"
64 "  depfile = $out.d\n"
65 "  command = cat $in > $out\n"
66 "build out.o: catdep foo.cc\n"));
67   fs_.Create("foo.cc",  "");
68   fs_.Create("out.o.d", "out.o: ./foo/../implicit.h\n");
69   fs_.Create("out.o", "");
70   fs_.Tick();
71   fs_.Create("implicit.h", "");
72 
73   string err;
74   EXPECT_TRUE(scan_.RecomputeDirty(GetNode("out.o"), NULL, &err));
75   ASSERT_EQ("", err);
76 
77   // implicit.h has changed, though our depfile refers to it with a
78   // non-canonical path; we should still find it.
79   EXPECT_TRUE(GetNode("out.o")->dirty());
80 }
81 
TEST_F(GraphTest, ExplicitImplicit)82 TEST_F(GraphTest, ExplicitImplicit) {
83   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
84 "rule catdep\n"
85 "  depfile = $out.d\n"
86 "  command = cat $in > $out\n"
87 "build implicit.h: cat data\n"
88 "build out.o: catdep foo.cc || implicit.h\n"));
89   fs_.Create("implicit.h", "");
90   fs_.Create("foo.cc", "");
91   fs_.Create("out.o.d", "out.o: implicit.h\n");
92   fs_.Create("out.o", "");
93   fs_.Tick();
94   fs_.Create("data", "");
95 
96   string err;
97   EXPECT_TRUE(scan_.RecomputeDirty(GetNode("out.o"), NULL, &err));
98   ASSERT_EQ("", err);
99 
100   // We have both an implicit and an explicit dep on implicit.h.
101   // The implicit dep should "win" (in the sense that it should cause
102   // the output to be dirty).
103   EXPECT_TRUE(GetNode("out.o")->dirty());
104 }
105 
TEST_F(GraphTest, ImplicitOutputParse)106 TEST_F(GraphTest, ImplicitOutputParse) {
107   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
108 "build out | out.imp: cat in\n"));
109 
110   Edge* edge = GetNode("out")->in_edge();
111   EXPECT_EQ(2, edge->outputs_.size());
112   EXPECT_EQ("out", edge->outputs_[0]->path());
113   EXPECT_EQ("out.imp", edge->outputs_[1]->path());
114   EXPECT_EQ(1, edge->implicit_outs_);
115   EXPECT_EQ(edge, GetNode("out.imp")->in_edge());
116 }
117 
TEST_F(GraphTest, ImplicitOutputMissing)118 TEST_F(GraphTest, ImplicitOutputMissing) {
119   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
120 "build out | out.imp: cat in\n"));
121   fs_.Create("in", "");
122   fs_.Create("out", "");
123 
124   string err;
125   EXPECT_TRUE(scan_.RecomputeDirty(GetNode("out"), NULL, &err));
126   ASSERT_EQ("", err);
127 
128   EXPECT_TRUE(GetNode("out")->dirty());
129   EXPECT_TRUE(GetNode("out.imp")->dirty());
130 }
131 
TEST_F(GraphTest, ImplicitOutputOutOfDate)132 TEST_F(GraphTest, ImplicitOutputOutOfDate) {
133   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
134 "build out | out.imp: cat in\n"));
135   fs_.Create("out.imp", "");
136   fs_.Tick();
137   fs_.Create("in", "");
138   fs_.Create("out", "");
139 
140   string err;
141   EXPECT_TRUE(scan_.RecomputeDirty(GetNode("out"), NULL, &err));
142   ASSERT_EQ("", err);
143 
144   EXPECT_TRUE(GetNode("out")->dirty());
145   EXPECT_TRUE(GetNode("out.imp")->dirty());
146 }
147 
TEST_F(GraphTest, ImplicitOutputOnlyParse)148 TEST_F(GraphTest, ImplicitOutputOnlyParse) {
149   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
150 "build | out.imp: cat in\n"));
151 
152   Edge* edge = GetNode("out.imp")->in_edge();
153   EXPECT_EQ(1, edge->outputs_.size());
154   EXPECT_EQ("out.imp", edge->outputs_[0]->path());
155   EXPECT_EQ(1, edge->implicit_outs_);
156   EXPECT_EQ(edge, GetNode("out.imp")->in_edge());
157 }
158 
TEST_F(GraphTest, ImplicitOutputOnlyMissing)159 TEST_F(GraphTest, ImplicitOutputOnlyMissing) {
160   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
161 "build | out.imp: cat in\n"));
162   fs_.Create("in", "");
163 
164   string err;
165   EXPECT_TRUE(scan_.RecomputeDirty(GetNode("out.imp"), NULL, &err));
166   ASSERT_EQ("", err);
167 
168   EXPECT_TRUE(GetNode("out.imp")->dirty());
169 }
170 
TEST_F(GraphTest, ImplicitOutputOnlyOutOfDate)171 TEST_F(GraphTest, ImplicitOutputOnlyOutOfDate) {
172   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
173 "build | out.imp: cat in\n"));
174   fs_.Create("out.imp", "");
175   fs_.Tick();
176   fs_.Create("in", "");
177 
178   string err;
179   EXPECT_TRUE(scan_.RecomputeDirty(GetNode("out.imp"), NULL, &err));
180   ASSERT_EQ("", err);
181 
182   EXPECT_TRUE(GetNode("out.imp")->dirty());
183 }
184 
TEST_F(GraphTest, PathWithCurrentDirectory)185 TEST_F(GraphTest, PathWithCurrentDirectory) {
186   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
187 "rule catdep\n"
188 "  depfile = $out.d\n"
189 "  command = cat $in > $out\n"
190 "build ./out.o: catdep ./foo.cc\n"));
191   fs_.Create("foo.cc", "");
192   fs_.Create("out.o.d", "out.o: foo.cc\n");
193   fs_.Create("out.o", "");
194 
195   string err;
196   EXPECT_TRUE(scan_.RecomputeDirty(GetNode("out.o"), NULL, &err));
197   ASSERT_EQ("", err);
198 
199   EXPECT_FALSE(GetNode("out.o")->dirty());
200 }
201 
TEST_F(GraphTest, RootNodes)202 TEST_F(GraphTest, RootNodes) {
203   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
204 "build out1: cat in1\n"
205 "build mid1: cat in1\n"
206 "build out2: cat mid1\n"
207 "build out3 out4: cat mid1\n"));
208 
209   string err;
210   vector<Node*> root_nodes = state_.RootNodes(&err);
211   EXPECT_EQ(4u, root_nodes.size());
212   for (size_t i = 0; i < root_nodes.size(); ++i) {
213     string name = root_nodes[i]->path();
214     EXPECT_EQ("out", name.substr(0, 3));
215   }
216 }
217 
TEST_F(GraphTest, CollectInputs)218 TEST_F(GraphTest, CollectInputs) {
219   ASSERT_NO_FATAL_FAILURE(AssertParse(
220       &state_,
221       "build out$ 1: cat in1 in2 in$ with$ space | implicit || order_only\n"));
222 
223   std::vector<std::string> inputs;
224   Edge* edge = GetNode("out 1")->in_edge();
225 
226   // Test without shell escaping.
227   inputs.clear();
228   edge->CollectInputs(false, &inputs);
229   EXPECT_EQ(5u, inputs.size());
230   EXPECT_EQ("in1", inputs[0]);
231   EXPECT_EQ("in2", inputs[1]);
232   EXPECT_EQ("in with space", inputs[2]);
233   EXPECT_EQ("implicit", inputs[3]);
234   EXPECT_EQ("order_only", inputs[4]);
235 
236   // Test with shell escaping.
237   inputs.clear();
238   edge->CollectInputs(true, &inputs);
239   EXPECT_EQ(5u, inputs.size());
240   EXPECT_EQ("in1", inputs[0]);
241   EXPECT_EQ("in2", inputs[1]);
242 #ifdef _WIN32
243   EXPECT_EQ("\"in with space\"", inputs[2]);
244 #else
245   EXPECT_EQ("'in with space'", inputs[2]);
246 #endif
247   EXPECT_EQ("implicit", inputs[3]);
248   EXPECT_EQ("order_only", inputs[4]);
249 }
250 
TEST_F(GraphTest, VarInOutPathEscaping)251 TEST_F(GraphTest, VarInOutPathEscaping) {
252   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
253 "build a$ b: cat no'space with$ space$$ no\"space2\n"));
254 
255   Edge* edge = GetNode("a b")->in_edge();
256 #ifdef _WIN32
257   EXPECT_EQ("cat no'space \"with space$\" \"no\\\"space2\" > \"a b\"",
258       edge->EvaluateCommand());
259 #else
260   EXPECT_EQ("cat 'no'\\''space' 'with space$' 'no\"space2' > 'a b'",
261       edge->EvaluateCommand());
262 #endif
263 }
264 
265 // Regression test for https://github.com/ninja-build/ninja/issues/380
TEST_F(GraphTest, DepfileWithCanonicalizablePath)266 TEST_F(GraphTest, DepfileWithCanonicalizablePath) {
267   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
268 "rule catdep\n"
269 "  depfile = $out.d\n"
270 "  command = cat $in > $out\n"
271 "build ./out.o: catdep ./foo.cc\n"));
272   fs_.Create("foo.cc", "");
273   fs_.Create("out.o.d", "out.o: bar/../foo.cc\n");
274   fs_.Create("out.o", "");
275 
276   string err;
277   EXPECT_TRUE(scan_.RecomputeDirty(GetNode("out.o"), NULL, &err));
278   ASSERT_EQ("", err);
279 
280   EXPECT_FALSE(GetNode("out.o")->dirty());
281 }
282 
283 // Regression test for https://github.com/ninja-build/ninja/issues/404
TEST_F(GraphTest, DepfileRemoved)284 TEST_F(GraphTest, DepfileRemoved) {
285   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
286 "rule catdep\n"
287 "  depfile = $out.d\n"
288 "  command = cat $in > $out\n"
289 "build ./out.o: catdep ./foo.cc\n"));
290   fs_.Create("foo.h", "");
291   fs_.Create("foo.cc", "");
292   fs_.Tick();
293   fs_.Create("out.o.d", "out.o: foo.h\n");
294   fs_.Create("out.o", "");
295 
296   string err;
297   EXPECT_TRUE(scan_.RecomputeDirty(GetNode("out.o"), NULL, &err));
298   ASSERT_EQ("", err);
299   EXPECT_FALSE(GetNode("out.o")->dirty());
300 
301   state_.Reset();
302   fs_.RemoveFile("out.o.d");
303   EXPECT_TRUE(scan_.RecomputeDirty(GetNode("out.o"), NULL, &err));
304   ASSERT_EQ("", err);
305   EXPECT_TRUE(GetNode("out.o")->dirty());
306 }
307 
308 // Check that rule-level variables are in scope for eval.
TEST_F(GraphTest, RuleVariablesInScope)309 TEST_F(GraphTest, RuleVariablesInScope) {
310   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
311 "rule r\n"
312 "  depfile = x\n"
313 "  command = depfile is $depfile\n"
314 "build out: r in\n"));
315   Edge* edge = GetNode("out")->in_edge();
316   EXPECT_EQ("depfile is x", edge->EvaluateCommand());
317 }
318 
319 // Check that build statements can override rule builtins like depfile.
TEST_F(GraphTest, DepfileOverride)320 TEST_F(GraphTest, DepfileOverride) {
321   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
322 "rule r\n"
323 "  depfile = x\n"
324 "  command = unused\n"
325 "build out: r in\n"
326 "  depfile = y\n"));
327   Edge* edge = GetNode("out")->in_edge();
328   EXPECT_EQ("y", edge->GetBinding("depfile"));
329 }
330 
331 // Check that overridden values show up in expansion of rule-level bindings.
TEST_F(GraphTest, DepfileOverrideParent)332 TEST_F(GraphTest, DepfileOverrideParent) {
333   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
334 "rule r\n"
335 "  depfile = x\n"
336 "  command = depfile is $depfile\n"
337 "build out: r in\n"
338 "  depfile = y\n"));
339   Edge* edge = GetNode("out")->in_edge();
340   EXPECT_EQ("depfile is y", edge->GetBinding("command"));
341 }
342 
343 // Verify that building a nested phony rule prints "no work to do"
TEST_F(GraphTest, NestedPhonyPrintsDone)344 TEST_F(GraphTest, NestedPhonyPrintsDone) {
345   AssertParse(&state_,
346 "build n1: phony \n"
347 "build n2: phony n1\n"
348   );
349   string err;
350   EXPECT_TRUE(scan_.RecomputeDirty(GetNode("n2"), NULL, &err));
351   ASSERT_EQ("", err);
352 
353   Plan plan_;
354   EXPECT_TRUE(plan_.AddTarget(GetNode("n2"), &err));
355   ASSERT_EQ("", err);
356 
357   EXPECT_EQ(0, plan_.command_edge_count());
358   ASSERT_FALSE(plan_.more_to_do());
359 }
360 
TEST_F(GraphTest, PhonySelfReferenceError)361 TEST_F(GraphTest, PhonySelfReferenceError) {
362   ManifestParserOptions parser_opts;
363   parser_opts.phony_cycle_action_ = kPhonyCycleActionError;
364   AssertParse(&state_,
365 "build a: phony a\n",
366   parser_opts);
367 
368   string err;
369   EXPECT_FALSE(scan_.RecomputeDirty(GetNode("a"), NULL, &err));
370   ASSERT_EQ("dependency cycle: a -> a [-w phonycycle=err]", err);
371 }
372 
TEST_F(GraphTest, DependencyCycle)373 TEST_F(GraphTest, DependencyCycle) {
374   AssertParse(&state_,
375 "build out: cat mid\n"
376 "build mid: cat in\n"
377 "build in: cat pre\n"
378 "build pre: cat out\n");
379 
380   string err;
381   EXPECT_FALSE(scan_.RecomputeDirty(GetNode("out"), NULL, &err));
382   ASSERT_EQ("dependency cycle: out -> mid -> in -> pre -> out", err);
383 }
384 
TEST_F(GraphTest, CycleInEdgesButNotInNodes1)385 TEST_F(GraphTest, CycleInEdgesButNotInNodes1) {
386   string err;
387   AssertParse(&state_,
388 "build a b: cat a\n");
389   EXPECT_FALSE(scan_.RecomputeDirty(GetNode("b"), NULL, &err));
390   ASSERT_EQ("dependency cycle: a -> a", err);
391 }
392 
TEST_F(GraphTest, CycleInEdgesButNotInNodes2)393 TEST_F(GraphTest, CycleInEdgesButNotInNodes2) {
394   string err;
395   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
396 "build b a: cat a\n"));
397   EXPECT_FALSE(scan_.RecomputeDirty(GetNode("b"), NULL, &err));
398   ASSERT_EQ("dependency cycle: a -> a", err);
399 }
400 
TEST_F(GraphTest, CycleInEdgesButNotInNodes3)401 TEST_F(GraphTest, CycleInEdgesButNotInNodes3) {
402   string err;
403   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
404 "build a b: cat c\n"
405 "build c: cat a\n"));
406   EXPECT_FALSE(scan_.RecomputeDirty(GetNode("b"), NULL, &err));
407   ASSERT_EQ("dependency cycle: a -> c -> a", err);
408 }
409 
TEST_F(GraphTest, CycleInEdgesButNotInNodes4)410 TEST_F(GraphTest, CycleInEdgesButNotInNodes4) {
411   string err;
412   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
413 "build d: cat c\n"
414 "build c: cat b\n"
415 "build b: cat a\n"
416 "build a e: cat d\n"
417 "build f: cat e\n"));
418   EXPECT_FALSE(scan_.RecomputeDirty(GetNode("f"), NULL, &err));
419   ASSERT_EQ("dependency cycle: a -> d -> c -> b -> a", err);
420 }
421 
422 // Verify that cycles in graphs with multiple outputs are handled correctly
423 // in RecomputeDirty() and don't cause deps to be loaded multiple times.
TEST_F(GraphTest, CycleWithLengthZeroFromDepfile)424 TEST_F(GraphTest, CycleWithLengthZeroFromDepfile) {
425   AssertParse(&state_,
426 "rule deprule\n"
427 "   depfile = dep.d\n"
428 "   command = unused\n"
429 "build a b: deprule\n"
430   );
431   fs_.Create("dep.d", "a: b\n");
432 
433   string err;
434   EXPECT_FALSE(scan_.RecomputeDirty(GetNode("a"), NULL, &err));
435   ASSERT_EQ("dependency cycle: b -> b", err);
436 
437   // Despite the depfile causing edge to be a cycle (it has outputs a and b,
438   // but the depfile also adds b as an input), the deps should have been loaded
439   // only once:
440   Edge* edge = GetNode("a")->in_edge();
441   EXPECT_EQ(1, edge->inputs_.size());
442   EXPECT_EQ("b", edge->inputs_[0]->path());
443 }
444 
445 // Like CycleWithLengthZeroFromDepfile but with a higher cycle length.
TEST_F(GraphTest, CycleWithLengthOneFromDepfile)446 TEST_F(GraphTest, CycleWithLengthOneFromDepfile) {
447   AssertParse(&state_,
448 "rule deprule\n"
449 "   depfile = dep.d\n"
450 "   command = unused\n"
451 "rule r\n"
452 "   command = unused\n"
453 "build a b: deprule\n"
454 "build c: r b\n"
455   );
456   fs_.Create("dep.d", "a: c\n");
457 
458   string err;
459   EXPECT_FALSE(scan_.RecomputeDirty(GetNode("a"), NULL, &err));
460   ASSERT_EQ("dependency cycle: b -> c -> b", err);
461 
462   // Despite the depfile causing edge to be a cycle (|edge| has outputs a and b,
463   // but c's in_edge has b as input but the depfile also adds |edge| as
464   // output)), the deps should have been loaded only once:
465   Edge* edge = GetNode("a")->in_edge();
466   EXPECT_EQ(1, edge->inputs_.size());
467   EXPECT_EQ("c", edge->inputs_[0]->path());
468 }
469 
470 // Like CycleWithLengthOneFromDepfile but building a node one hop away from
471 // the cycle.
TEST_F(GraphTest, CycleWithLengthOneFromDepfileOneHopAway)472 TEST_F(GraphTest, CycleWithLengthOneFromDepfileOneHopAway) {
473   AssertParse(&state_,
474 "rule deprule\n"
475 "   depfile = dep.d\n"
476 "   command = unused\n"
477 "rule r\n"
478 "   command = unused\n"
479 "build a b: deprule\n"
480 "build c: r b\n"
481 "build d: r a\n"
482   );
483   fs_.Create("dep.d", "a: c\n");
484 
485   string err;
486   EXPECT_FALSE(scan_.RecomputeDirty(GetNode("d"), NULL, &err));
487   ASSERT_EQ("dependency cycle: b -> c -> b", err);
488 
489   // Despite the depfile causing edge to be a cycle (|edge| has outputs a and b,
490   // but c's in_edge has b as input but the depfile also adds |edge| as
491   // output)), the deps should have been loaded only once:
492   Edge* edge = GetNode("a")->in_edge();
493   EXPECT_EQ(1, edge->inputs_.size());
494   EXPECT_EQ("c", edge->inputs_[0]->path());
495 }
496 
497 #ifdef _WIN32
TEST_F(GraphTest, Decanonicalize)498 TEST_F(GraphTest, Decanonicalize) {
499   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
500 "build out\\out1: cat src\\in1\n"
501 "build out\\out2/out3\\out4: cat mid1\n"
502 "build out3 out4\\foo: cat mid1\n"));
503 
504   string err;
505   vector<Node*> root_nodes = state_.RootNodes(&err);
506   EXPECT_EQ(4u, root_nodes.size());
507   EXPECT_EQ(root_nodes[0]->path(), "out/out1");
508   EXPECT_EQ(root_nodes[1]->path(), "out/out2/out3/out4");
509   EXPECT_EQ(root_nodes[2]->path(), "out3");
510   EXPECT_EQ(root_nodes[3]->path(), "out4/foo");
511   EXPECT_EQ(root_nodes[0]->PathDecanonicalized(), "out\\out1");
512   EXPECT_EQ(root_nodes[1]->PathDecanonicalized(), "out\\out2/out3\\out4");
513   EXPECT_EQ(root_nodes[2]->PathDecanonicalized(), "out3");
514   EXPECT_EQ(root_nodes[3]->PathDecanonicalized(), "out4\\foo");
515 }
516 #endif
517 
TEST_F(GraphTest, DyndepLoadTrivial)518 TEST_F(GraphTest, DyndepLoadTrivial) {
519   AssertParse(&state_,
520 "rule r\n"
521 "  command = unused\n"
522 "build out: r in || dd\n"
523 "  dyndep = dd\n"
524   );
525   fs_.Create("dd",
526 "ninja_dyndep_version = 1\n"
527 "build out: dyndep\n"
528   );
529 
530   string err;
531   ASSERT_TRUE(GetNode("dd")->dyndep_pending());
532   EXPECT_TRUE(scan_.LoadDyndeps(GetNode("dd"), &err));
533   EXPECT_EQ("", err);
534   EXPECT_FALSE(GetNode("dd")->dyndep_pending());
535 
536   Edge* edge = GetNode("out")->in_edge();
537   ASSERT_EQ(1u, edge->outputs_.size());
538   EXPECT_EQ("out", edge->outputs_[0]->path());
539   ASSERT_EQ(2u, edge->inputs_.size());
540   EXPECT_EQ("in", edge->inputs_[0]->path());
541   EXPECT_EQ("dd", edge->inputs_[1]->path());
542   EXPECT_EQ(0u, edge->implicit_deps_);
543   EXPECT_EQ(1u, edge->order_only_deps_);
544   EXPECT_FALSE(edge->GetBindingBool("restat"));
545 }
546 
TEST_F(GraphTest, DyndepLoadImplicit)547 TEST_F(GraphTest, DyndepLoadImplicit) {
548   AssertParse(&state_,
549 "rule r\n"
550 "  command = unused\n"
551 "build out1: r in || dd\n"
552 "  dyndep = dd\n"
553 "build out2: r in\n"
554   );
555   fs_.Create("dd",
556 "ninja_dyndep_version = 1\n"
557 "build out1: dyndep | out2\n"
558   );
559 
560   string err;
561   ASSERT_TRUE(GetNode("dd")->dyndep_pending());
562   EXPECT_TRUE(scan_.LoadDyndeps(GetNode("dd"), &err));
563   EXPECT_EQ("", err);
564   EXPECT_FALSE(GetNode("dd")->dyndep_pending());
565 
566   Edge* edge = GetNode("out1")->in_edge();
567   ASSERT_EQ(1u, edge->outputs_.size());
568   EXPECT_EQ("out1", edge->outputs_[0]->path());
569   ASSERT_EQ(3u, edge->inputs_.size());
570   EXPECT_EQ("in", edge->inputs_[0]->path());
571   EXPECT_EQ("out2", edge->inputs_[1]->path());
572   EXPECT_EQ("dd", edge->inputs_[2]->path());
573   EXPECT_EQ(1u, edge->implicit_deps_);
574   EXPECT_EQ(1u, edge->order_only_deps_);
575   EXPECT_FALSE(edge->GetBindingBool("restat"));
576 }
577 
TEST_F(GraphTest, DyndepLoadMissingFile)578 TEST_F(GraphTest, DyndepLoadMissingFile) {
579   AssertParse(&state_,
580 "rule r\n"
581 "  command = unused\n"
582 "build out: r in || dd\n"
583 "  dyndep = dd\n"
584   );
585 
586   string err;
587   ASSERT_TRUE(GetNode("dd")->dyndep_pending());
588   EXPECT_FALSE(scan_.LoadDyndeps(GetNode("dd"), &err));
589   EXPECT_EQ("loading 'dd': No such file or directory", err);
590 }
591 
TEST_F(GraphTest, DyndepLoadMissingEntry)592 TEST_F(GraphTest, DyndepLoadMissingEntry) {
593   AssertParse(&state_,
594 "rule r\n"
595 "  command = unused\n"
596 "build out: r in || dd\n"
597 "  dyndep = dd\n"
598   );
599   fs_.Create("dd",
600 "ninja_dyndep_version = 1\n"
601   );
602 
603   string err;
604   ASSERT_TRUE(GetNode("dd")->dyndep_pending());
605   EXPECT_FALSE(scan_.LoadDyndeps(GetNode("dd"), &err));
606   EXPECT_EQ("'out' not mentioned in its dyndep file 'dd'", err);
607 }
608 
TEST_F(GraphTest, DyndepLoadExtraEntry)609 TEST_F(GraphTest, DyndepLoadExtraEntry) {
610   AssertParse(&state_,
611 "rule r\n"
612 "  command = unused\n"
613 "build out: r in || dd\n"
614 "  dyndep = dd\n"
615 "build out2: r in || dd\n"
616   );
617   fs_.Create("dd",
618 "ninja_dyndep_version = 1\n"
619 "build out: dyndep\n"
620 "build out2: dyndep\n"
621   );
622 
623   string err;
624   ASSERT_TRUE(GetNode("dd")->dyndep_pending());
625   EXPECT_FALSE(scan_.LoadDyndeps(GetNode("dd"), &err));
626   EXPECT_EQ("dyndep file 'dd' mentions output 'out2' whose build statement "
627             "does not have a dyndep binding for the file", err);
628 }
629 
TEST_F(GraphTest, DyndepLoadOutputWithMultipleRules1)630 TEST_F(GraphTest, DyndepLoadOutputWithMultipleRules1) {
631   AssertParse(&state_,
632 "rule r\n"
633 "  command = unused\n"
634 "build out1 | out-twice.imp: r in1\n"
635 "build out2: r in2 || dd\n"
636 "  dyndep = dd\n"
637   );
638   fs_.Create("dd",
639 "ninja_dyndep_version = 1\n"
640 "build out2 | out-twice.imp: dyndep\n"
641   );
642 
643   string err;
644   ASSERT_TRUE(GetNode("dd")->dyndep_pending());
645   EXPECT_FALSE(scan_.LoadDyndeps(GetNode("dd"), &err));
646   EXPECT_EQ("multiple rules generate out-twice.imp", err);
647 }
648 
TEST_F(GraphTest, DyndepLoadOutputWithMultipleRules2)649 TEST_F(GraphTest, DyndepLoadOutputWithMultipleRules2) {
650   AssertParse(&state_,
651 "rule r\n"
652 "  command = unused\n"
653 "build out1: r in1 || dd1\n"
654 "  dyndep = dd1\n"
655 "build out2: r in2 || dd2\n"
656 "  dyndep = dd2\n"
657   );
658   fs_.Create("dd1",
659 "ninja_dyndep_version = 1\n"
660 "build out1 | out-twice.imp: dyndep\n"
661   );
662   fs_.Create("dd2",
663 "ninja_dyndep_version = 1\n"
664 "build out2 | out-twice.imp: dyndep\n"
665   );
666 
667   string err;
668   ASSERT_TRUE(GetNode("dd1")->dyndep_pending());
669   EXPECT_TRUE(scan_.LoadDyndeps(GetNode("dd1"), &err));
670   EXPECT_EQ("", err);
671   ASSERT_TRUE(GetNode("dd2")->dyndep_pending());
672   EXPECT_FALSE(scan_.LoadDyndeps(GetNode("dd2"), &err));
673   EXPECT_EQ("multiple rules generate out-twice.imp", err);
674 }
675 
TEST_F(GraphTest, DyndepLoadMultiple)676 TEST_F(GraphTest, DyndepLoadMultiple) {
677   AssertParse(&state_,
678 "rule r\n"
679 "  command = unused\n"
680 "build out1: r in1 || dd\n"
681 "  dyndep = dd\n"
682 "build out2: r in2 || dd\n"
683 "  dyndep = dd\n"
684 "build outNot: r in3 || dd\n"
685   );
686   fs_.Create("dd",
687 "ninja_dyndep_version = 1\n"
688 "build out1 | out1imp: dyndep | in1imp\n"
689 "build out2: dyndep | in2imp\n"
690 "  restat = 1\n"
691   );
692 
693   string err;
694   ASSERT_TRUE(GetNode("dd")->dyndep_pending());
695   EXPECT_TRUE(scan_.LoadDyndeps(GetNode("dd"), &err));
696   EXPECT_EQ("", err);
697   EXPECT_FALSE(GetNode("dd")->dyndep_pending());
698 
699   Edge* edge1 = GetNode("out1")->in_edge();
700   ASSERT_EQ(2u, edge1->outputs_.size());
701   EXPECT_EQ("out1", edge1->outputs_[0]->path());
702   EXPECT_EQ("out1imp", edge1->outputs_[1]->path());
703   EXPECT_EQ(1u, edge1->implicit_outs_);
704   ASSERT_EQ(3u, edge1->inputs_.size());
705   EXPECT_EQ("in1", edge1->inputs_[0]->path());
706   EXPECT_EQ("in1imp", edge1->inputs_[1]->path());
707   EXPECT_EQ("dd", edge1->inputs_[2]->path());
708   EXPECT_EQ(1u, edge1->implicit_deps_);
709   EXPECT_EQ(1u, edge1->order_only_deps_);
710   EXPECT_FALSE(edge1->GetBindingBool("restat"));
711   EXPECT_EQ(edge1, GetNode("out1imp")->in_edge());
712   Node* in1imp = GetNode("in1imp");
713   ASSERT_EQ(1u, in1imp->out_edges().size());
714   EXPECT_EQ(edge1, in1imp->out_edges()[0]);
715 
716   Edge* edge2 = GetNode("out2")->in_edge();
717   ASSERT_EQ(1u, edge2->outputs_.size());
718   EXPECT_EQ("out2", edge2->outputs_[0]->path());
719   EXPECT_EQ(0u, edge2->implicit_outs_);
720   ASSERT_EQ(3u, edge2->inputs_.size());
721   EXPECT_EQ("in2", edge2->inputs_[0]->path());
722   EXPECT_EQ("in2imp", edge2->inputs_[1]->path());
723   EXPECT_EQ("dd", edge2->inputs_[2]->path());
724   EXPECT_EQ(1u, edge2->implicit_deps_);
725   EXPECT_EQ(1u, edge2->order_only_deps_);
726   EXPECT_TRUE(edge2->GetBindingBool("restat"));
727   Node* in2imp = GetNode("in2imp");
728   ASSERT_EQ(1u, in2imp->out_edges().size());
729   EXPECT_EQ(edge2, in2imp->out_edges()[0]);
730 }
731 
TEST_F(GraphTest, DyndepFileMissing)732 TEST_F(GraphTest, DyndepFileMissing) {
733   AssertParse(&state_,
734 "rule r\n"
735 "  command = unused\n"
736 "build out: r || dd\n"
737 "  dyndep = dd\n"
738   );
739 
740   string err;
741   EXPECT_FALSE(scan_.RecomputeDirty(GetNode("out"), NULL, &err));
742   ASSERT_EQ("loading 'dd': No such file or directory", err);
743 }
744 
TEST_F(GraphTest, DyndepFileError)745 TEST_F(GraphTest, DyndepFileError) {
746   AssertParse(&state_,
747 "rule r\n"
748 "  command = unused\n"
749 "build out: r || dd\n"
750 "  dyndep = dd\n"
751   );
752   fs_.Create("dd",
753 "ninja_dyndep_version = 1\n"
754   );
755 
756   string err;
757   EXPECT_FALSE(scan_.RecomputeDirty(GetNode("out"), NULL, &err));
758   ASSERT_EQ("'out' not mentioned in its dyndep file 'dd'", err);
759 }
760 
TEST_F(GraphTest, DyndepImplicitInputNewer)761 TEST_F(GraphTest, DyndepImplicitInputNewer) {
762   AssertParse(&state_,
763 "rule r\n"
764 "  command = unused\n"
765 "build out: r || dd\n"
766 "  dyndep = dd\n"
767   );
768   fs_.Create("dd",
769 "ninja_dyndep_version = 1\n"
770 "build out: dyndep | in\n"
771   );
772   fs_.Create("out", "");
773   fs_.Tick();
774   fs_.Create("in", "");
775 
776   string err;
777   EXPECT_TRUE(scan_.RecomputeDirty(GetNode("out"), NULL, &err));
778   ASSERT_EQ("", err);
779 
780   EXPECT_FALSE(GetNode("in")->dirty());
781   EXPECT_FALSE(GetNode("dd")->dirty());
782 
783   // "out" is dirty due to dyndep-specified implicit input
784   EXPECT_TRUE(GetNode("out")->dirty());
785 }
786 
TEST_F(GraphTest, DyndepFileReady)787 TEST_F(GraphTest, DyndepFileReady) {
788   AssertParse(&state_,
789 "rule r\n"
790 "  command = unused\n"
791 "build dd: r dd-in\n"
792 "build out: r || dd\n"
793 "  dyndep = dd\n"
794   );
795   fs_.Create("dd-in", "");
796   fs_.Create("dd",
797 "ninja_dyndep_version = 1\n"
798 "build out: dyndep | in\n"
799   );
800   fs_.Create("out", "");
801   fs_.Tick();
802   fs_.Create("in", "");
803 
804   string err;
805   EXPECT_TRUE(scan_.RecomputeDirty(GetNode("out"), NULL, &err));
806   ASSERT_EQ("", err);
807 
808   EXPECT_FALSE(GetNode("in")->dirty());
809   EXPECT_FALSE(GetNode("dd")->dirty());
810   EXPECT_TRUE(GetNode("dd")->in_edge()->outputs_ready());
811 
812   // "out" is dirty due to dyndep-specified implicit input
813   EXPECT_TRUE(GetNode("out")->dirty());
814 }
815 
TEST_F(GraphTest, DyndepFileNotClean)816 TEST_F(GraphTest, DyndepFileNotClean) {
817   AssertParse(&state_,
818 "rule r\n"
819 "  command = unused\n"
820 "build dd: r dd-in\n"
821 "build out: r || dd\n"
822 "  dyndep = dd\n"
823   );
824   fs_.Create("dd", "this-should-not-be-loaded");
825   fs_.Tick();
826   fs_.Create("dd-in", "");
827   fs_.Create("out", "");
828 
829   string err;
830   EXPECT_TRUE(scan_.RecomputeDirty(GetNode("out"), NULL, &err));
831   ASSERT_EQ("", err);
832 
833   EXPECT_TRUE(GetNode("dd")->dirty());
834   EXPECT_FALSE(GetNode("dd")->in_edge()->outputs_ready());
835 
836   // "out" is clean but not ready since "dd" is not ready
837   EXPECT_FALSE(GetNode("out")->dirty());
838   EXPECT_FALSE(GetNode("out")->in_edge()->outputs_ready());
839 }
840 
TEST_F(GraphTest, DyndepFileNotReady)841 TEST_F(GraphTest, DyndepFileNotReady) {
842   AssertParse(&state_,
843 "rule r\n"
844 "  command = unused\n"
845 "build tmp: r\n"
846 "build dd: r dd-in || tmp\n"
847 "build out: r || dd\n"
848 "  dyndep = dd\n"
849   );
850   fs_.Create("dd", "this-should-not-be-loaded");
851   fs_.Create("dd-in", "");
852   fs_.Tick();
853   fs_.Create("out", "");
854 
855   string err;
856   EXPECT_TRUE(scan_.RecomputeDirty(GetNode("out"), NULL, &err));
857   ASSERT_EQ("", err);
858 
859   EXPECT_FALSE(GetNode("dd")->dirty());
860   EXPECT_FALSE(GetNode("dd")->in_edge()->outputs_ready());
861   EXPECT_FALSE(GetNode("out")->dirty());
862   EXPECT_FALSE(GetNode("out")->in_edge()->outputs_ready());
863 }
864 
TEST_F(GraphTest, DyndepFileSecondNotReady)865 TEST_F(GraphTest, DyndepFileSecondNotReady) {
866   AssertParse(&state_,
867 "rule r\n"
868 "  command = unused\n"
869 "build dd1: r dd1-in\n"
870 "build dd2-in: r || dd1\n"
871 "  dyndep = dd1\n"
872 "build dd2: r dd2-in\n"
873 "build out: r || dd2\n"
874 "  dyndep = dd2\n"
875   );
876   fs_.Create("dd1", "");
877   fs_.Create("dd2", "");
878   fs_.Create("dd2-in", "");
879   fs_.Tick();
880   fs_.Create("dd1-in", "");
881   fs_.Create("out", "");
882 
883   string err;
884   EXPECT_TRUE(scan_.RecomputeDirty(GetNode("out"), NULL, &err));
885   ASSERT_EQ("", err);
886 
887   EXPECT_TRUE(GetNode("dd1")->dirty());
888   EXPECT_FALSE(GetNode("dd1")->in_edge()->outputs_ready());
889   EXPECT_FALSE(GetNode("dd2")->dirty());
890   EXPECT_FALSE(GetNode("dd2")->in_edge()->outputs_ready());
891   EXPECT_FALSE(GetNode("out")->dirty());
892   EXPECT_FALSE(GetNode("out")->in_edge()->outputs_ready());
893 }
894 
TEST_F(GraphTest, DyndepFileCircular)895 TEST_F(GraphTest, DyndepFileCircular) {
896   AssertParse(&state_,
897 "rule r\n"
898 "  command = unused\n"
899 "build out: r in || dd\n"
900 "  depfile = out.d\n"
901 "  dyndep = dd\n"
902 "build in: r circ\n"
903   );
904   fs_.Create("out.d", "out: inimp\n");
905   fs_.Create("dd",
906 "ninja_dyndep_version = 1\n"
907 "build out | circ: dyndep\n"
908   );
909   fs_.Create("out", "");
910 
911   Edge* edge = GetNode("out")->in_edge();
912   string err;
913   EXPECT_FALSE(scan_.RecomputeDirty(GetNode("out"), NULL, &err));
914   EXPECT_EQ("dependency cycle: circ -> in -> circ", err);
915 
916   // Verify that "out.d" was loaded exactly once despite
917   // circular reference discovered from dyndep file.
918   ASSERT_EQ(3u, edge->inputs_.size());
919   EXPECT_EQ("in", edge->inputs_[0]->path());
920   EXPECT_EQ("inimp", edge->inputs_[1]->path());
921   EXPECT_EQ("dd", edge->inputs_[2]->path());
922   EXPECT_EQ(1u, edge->implicit_deps_);
923   EXPECT_EQ(1u, edge->order_only_deps_);
924 }
925 
TEST_F(GraphTest, Validation)926 TEST_F(GraphTest, Validation) {
927   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
928 "build out: cat in |@ validate\n"
929 "build validate: cat in\n"));
930 
931   fs_.Create("in", "");
932   string err;
933   std::vector<Node*> validation_nodes;
934   EXPECT_TRUE(scan_.RecomputeDirty(GetNode("out"), &validation_nodes, &err));
935   ASSERT_EQ("", err);
936 
937   ASSERT_EQ(validation_nodes.size(), 1);
938   EXPECT_EQ(validation_nodes[0]->path(), "validate");
939 
940   EXPECT_TRUE(GetNode("out")->dirty());
941   EXPECT_TRUE(GetNode("validate")->dirty());
942 }
943 
944 // Check that phony's dependencies' mtimes are propagated.
TEST_F(GraphTest, PhonyDepsMtimes)945 TEST_F(GraphTest, PhonyDepsMtimes) {
946   string err;
947   ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
948 "rule touch\n"
949 " command = touch $out\n"
950 "build in_ph: phony in1\n"
951 "build out1: touch in_ph\n"
952 ));
953   fs_.Create("in1", "");
954   fs_.Create("out1", "");
955   Node* out1 = GetNode("out1");
956   Node* in1  = GetNode("in1");
957 
958   EXPECT_TRUE(scan_.RecomputeDirty(out1, NULL, &err));
959   EXPECT_TRUE(!out1->dirty());
960 
961   // Get the mtime of out1
962   ASSERT_TRUE(in1->Stat(&fs_, &err));
963   ASSERT_TRUE(out1->Stat(&fs_, &err));
964   TimeStamp out1Mtime1 = out1->mtime();
965   TimeStamp in1Mtime1 = in1->mtime();
966 
967   // Touch in1. This should cause out1 to be dirty
968   state_.Reset();
969   fs_.Tick();
970   fs_.Create("in1", "");
971 
972   ASSERT_TRUE(in1->Stat(&fs_, &err));
973   EXPECT_GT(in1->mtime(), in1Mtime1);
974 
975   EXPECT_TRUE(scan_.RecomputeDirty(out1, NULL, &err));
976   EXPECT_GT(in1->mtime(), in1Mtime1);
977   EXPECT_EQ(out1->mtime(), out1Mtime1);
978   EXPECT_TRUE(out1->dirty());
979 }
980 
981