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 20using namespace std; 21 22struct GraphTest : public StateTestWithBuiltinRules { 23 GraphTest() : scan_(&state_, NULL, NULL, &fs_, NULL) {} 24 25 VirtualFileSystem fs_; 26 DependencyScan scan_; 27}; 28 29TEST_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 45TEST_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 61TEST_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 82TEST_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 106TEST_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 118TEST_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 132TEST_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 148TEST_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 159TEST_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 171TEST_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 185TEST_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 202TEST_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 218TEST_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 251TEST_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 266TEST_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 284TEST_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. 309TEST_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. 320TEST_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. 332TEST_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" 344TEST_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 361TEST_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 373TEST_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 385TEST_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 393TEST_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 401TEST_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 410TEST_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. 424TEST_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. 446TEST_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. 472TEST_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 498TEST_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 518TEST_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 547TEST_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 578TEST_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 592TEST_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 609TEST_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 630TEST_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 649TEST_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 676TEST_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 732TEST_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 745TEST_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 761TEST_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 787TEST_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 816TEST_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 841TEST_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 865TEST_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 895TEST_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 926TEST_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. 945TEST_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