Ninja
graph_test.cc
Go to the documentation of this file.
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 
23  GraphTest() : scan_(&state_, NULL, NULL, &fs_, NULL) {}
24 
27 };
28 
29 TEST_F(GraphTest, MissingImplicit) {
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 
45 TEST_F(GraphTest, ModifiedImplicit) {
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 
61 TEST_F(GraphTest, FunkyMakefilePath) {
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 
82 TEST_F(GraphTest, ExplicitImplicit) {
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 
106 TEST_F(GraphTest, ImplicitOutputParse) {
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 
118 TEST_F(GraphTest, ImplicitOutputMissing) {
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 
132 TEST_F(GraphTest, ImplicitOutputOutOfDate) {
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 
148 TEST_F(GraphTest, ImplicitOutputOnlyParse) {
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 
159 TEST_F(GraphTest, ImplicitOutputOnlyMissing) {
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 
171 TEST_F(GraphTest, ImplicitOutputOnlyOutOfDate) {
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 
185 TEST_F(GraphTest, PathWithCurrentDirectory) {
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 
202 TEST_F(GraphTest, RootNodes) {
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 
218 TEST_F(GraphTest, CollectInputs) {
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 
251 TEST_F(GraphTest, VarInOutPathEscaping) {
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
266 TEST_F(GraphTest, DepfileWithCanonicalizablePath) {
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
284 TEST_F(GraphTest, DepfileRemoved) {
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.
309 TEST_F(GraphTest, RuleVariablesInScope) {
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.
320 TEST_F(GraphTest, DepfileOverride) {
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.
332 TEST_F(GraphTest, DepfileOverrideParent) {
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"
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 
361 TEST_F(GraphTest, PhonySelfReferenceError) {
362  ManifestParserOptions parser_opts;
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 
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 
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 
393 TEST_F(GraphTest, CycleInEdgesButNotInNodes2) {
394  string err;
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 
401 TEST_F(GraphTest, CycleInEdgesButNotInNodes3) {
402  string err;
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 
410 TEST_F(GraphTest, CycleInEdgesButNotInNodes4) {
411  string err;
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.
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.
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.
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
498 TEST_F(GraphTest, Decanonicalize) {
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
926 TEST_F(GraphTest, Validation) {
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.
945 TEST_F(GraphTest, PhonyDepsMtimes) {
946  string err;
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 }
An implementation of DiskInterface that uses an in-memory representation of disk state.
Definition: test.h:134
bool Stat(DiskInterface *disk_interface, std::string *err)
Return false on error.
Definition: graph.cc:34
int order_only_deps_
Definition: graph.h:229
void AssertParse(State *state, const char *input, ManifestParserOptions opts)
Definition: test.cc:100
int implicit_deps_
Definition: graph.h:228
Plan stores the state of a build plan: what we intend to build, which steps we&#39;re ready to execute...
Definition: build.h:40
PhonyCycleAction phony_cycle_action_
#define EXPECT_TRUE(a)
Definition: test.h:76
Information about a node in the dependency graph: the file, whether it&#39;s dirty, mtime, etc.
Definition: graph.h:39
#define EXPECT_FALSE(a)
Definition: test.h:78
std::vector< Node * > outputs_
Definition: graph.h:204
int command_edge_count() const
Number of edges with commands to run.
Definition: build.h:74
An edge in the dependency graph; links between Nodes using Rules.
Definition: graph.h:164
A base test fixture that includes a State object with a builtin "cat" rule.
Definition: test.h:113
VirtualFileSystem fs_
Definition: graph_test.cc:25
#define EXPECT_EQ(a, b)
Definition: test.h:64
DependencyScan scan_
Definition: graph_test.cc:26
#define ASSERT_FALSE(a)
Definition: test.h:95
bool dirty() const
Definition: graph.h:97
int implicit_outs_
Definition: graph.h:243
int64_t TimeStamp
Definition: timestamp.h:31
std::vector< Node * > inputs_
Definition: graph.h:203
#define ASSERT_EQ(a, b)
Definition: test.h:81
std::string GetBinding(const std::string &key) const
Returns the shell-escaped value of |key|.
Definition: graph.cc:491
bool AddTarget(const Node *target, std::string *err)
Add a target to our plan (including all its dependencies).
Definition: build.cc:91
TimeStamp mtime() const
Definition: graph.h:95
DependencyScan manages the process of scanning the files in a graph and updating the dirty/outputs_re...
Definition: graph.h:312
#define EXPECT_GT(a, b)
Definition: test.h:68
#define ASSERT_NO_FATAL_FAILURE(a)
Definition: test.h:97
std::string EvaluateCommand(bool incl_rsp_file=false) const
Expand all variables in a command and return it as a string.
Definition: graph.cc:481
const std::vector< Edge * > & out_edges() const
Definition: graph.h:110
#define ASSERT_TRUE(a)
Definition: test.h:93
bool more_to_do() const
Returns true if there&#39;s more work to be done.
Definition: build.h:53
bool GetBindingBool(const std::string &key) const
Definition: graph.cc:496
void CollectInputs(bool shell_escape, std::vector< std::string > *out) const
Definition: graph.cc:459
TEST_F(GraphTest, MissingImplicit)
Definition: graph_test.cc:29