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