23 GraphTest() : scan_(&state_, NULL, NULL, &fs_, NULL) {}
31 "build out: cat in | implicit\n"));
33 fs_.Create(
"out",
"");
36 EXPECT_TRUE(scan_.RecomputeDirty(GetNode(
"out"), NULL, &err));
47 "build out: cat in | implicit\n"));
49 fs_.Create(
"out",
"");
51 fs_.Create(
"implicit",
"");
54 EXPECT_TRUE(scan_.RecomputeDirty(GetNode(
"out"), NULL, &err));
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",
"");
71 fs_.Create(
"implicit.h",
"");
74 EXPECT_TRUE(scan_.RecomputeDirty(GetNode(
"out.o"), NULL, &err));
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",
"");
94 fs_.Create(
"data",
"");
97 EXPECT_TRUE(scan_.RecomputeDirty(GetNode(
"out.o"), NULL, &err));
108 "build out | out.imp: cat in\n"));
110 Edge* edge = GetNode(
"out")->in_edge();
115 EXPECT_EQ(edge, GetNode(
"out.imp")->in_edge());
120 "build out | out.imp: cat in\n"));
121 fs_.Create(
"in",
"");
122 fs_.Create(
"out",
"");
125 EXPECT_TRUE(scan_.RecomputeDirty(GetNode(
"out"), NULL, &err));
134 "build out | out.imp: cat in\n"));
135 fs_.Create(
"out.imp",
"");
137 fs_.Create(
"in",
"");
138 fs_.Create(
"out",
"");
141 EXPECT_TRUE(scan_.RecomputeDirty(GetNode(
"out"), NULL, &err));
150 "build | out.imp: cat in\n"));
152 Edge* edge = GetNode(
"out.imp")->in_edge();
156 EXPECT_EQ(edge, GetNode(
"out.imp")->in_edge());
161 "build | out.imp: cat in\n"));
162 fs_.Create(
"in",
"");
165 EXPECT_TRUE(scan_.RecomputeDirty(GetNode(
"out.imp"), NULL, &err));
173 "build | out.imp: cat in\n"));
174 fs_.Create(
"out.imp",
"");
176 fs_.Create(
"in",
"");
179 EXPECT_TRUE(scan_.RecomputeDirty(GetNode(
"out.imp"), NULL, &err));
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",
"");
196 EXPECT_TRUE(scan_.RecomputeDirty(GetNode(
"out.o"), NULL, &err));
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"));
210 vector<Node*> root_nodes = state_.RootNodes(&err);
212 for (
size_t i = 0; i < root_nodes.size(); ++i) {
213 string name = root_nodes[i]->path();
221 "build out$ 1: cat in1 in2 in$ with$ space | implicit || order_only\n"));
223 std::vector<std::string> inputs;
224 Edge* edge = GetNode(
"out 1")->in_edge();
243 EXPECT_EQ(
"\"in with space\"", inputs[2]);
253 "build a$ b: cat no'space with$ space$$ no\"space2\n"));
255 Edge* edge = GetNode(
"a b")->in_edge();
257 EXPECT_EQ(
"cat no'space \"with space$\" \"no\\\"space2\" > \"a b\"",
260 EXPECT_EQ(
"cat 'no'\\''space' 'with space$' 'no\"space2' > 'a b'",
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",
"");
277 EXPECT_TRUE(scan_.RecomputeDirty(GetNode(
"out.o"), NULL, &err));
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",
"");
293 fs_.Create(
"out.o.d",
"out.o: foo.h\n");
294 fs_.Create(
"out.o",
"");
297 EXPECT_TRUE(scan_.RecomputeDirty(GetNode(
"out.o"), NULL, &err));
302 fs_.RemoveFile(
"out.o.d");
303 EXPECT_TRUE(scan_.RecomputeDirty(GetNode(
"out.o"), NULL, &err));
313 " command = depfile is $depfile\n" 314 "build out: r in\n"));
315 Edge* edge = GetNode(
"out")->in_edge();
324 " command = unused\n" 327 Edge* edge = GetNode(
"out")->in_edge();
336 " command = depfile is $depfile\n" 339 Edge* edge = GetNode(
"out")->in_edge();
347 "build n2: phony n1\n" 350 EXPECT_TRUE(scan_.RecomputeDirty(GetNode(
"n2"), NULL, &err));
365 "build a: phony a\n",
369 EXPECT_FALSE(scan_.RecomputeDirty(GetNode(
"a"), NULL, &err));
370 ASSERT_EQ(
"dependency cycle: a -> a [-w phonycycle=err]", err);
375 "build out: cat mid\n" 376 "build mid: cat in\n" 377 "build in: cat pre\n" 378 "build pre: cat out\n");
381 EXPECT_FALSE(scan_.RecomputeDirty(GetNode(
"out"), NULL, &err));
382 ASSERT_EQ(
"dependency cycle: out -> mid -> in -> pre -> out", err);
388 "build a b: cat a\n");
389 EXPECT_FALSE(scan_.RecomputeDirty(GetNode(
"b"), NULL, &err));
390 ASSERT_EQ(
"dependency cycle: a -> a", 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);
405 "build c: cat a\n"));
406 EXPECT_FALSE(scan_.RecomputeDirty(GetNode(
"b"), NULL, &err));
407 ASSERT_EQ(
"dependency cycle: a -> c -> a", err);
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);
428 " command = unused\n" 429 "build a b: deprule\n" 431 fs_.Create(
"dep.d",
"a: b\n");
434 EXPECT_FALSE(scan_.RecomputeDirty(GetNode(
"a"), NULL, &err));
435 ASSERT_EQ(
"dependency cycle: b -> b", err);
440 Edge* edge = GetNode(
"a")->in_edge();
450 " command = unused\n" 452 " command = unused\n" 453 "build a b: deprule\n" 456 fs_.Create(
"dep.d",
"a: c\n");
459 EXPECT_FALSE(scan_.RecomputeDirty(GetNode(
"a"), NULL, &err));
460 ASSERT_EQ(
"dependency cycle: b -> c -> b", err);
465 Edge* edge = GetNode(
"a")->in_edge();
476 " command = unused\n" 478 " command = unused\n" 479 "build a b: deprule\n" 483 fs_.Create(
"dep.d",
"a: c\n");
486 EXPECT_FALSE(scan_.RecomputeDirty(GetNode(
"d"), NULL, &err));
487 ASSERT_EQ(
"dependency cycle: b -> c -> b", err);
492 Edge* edge = GetNode(
"a")->in_edge();
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"));
505 vector<Node*> root_nodes = state_.RootNodes(&err);
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");
521 " command = unused\n" 522 "build out: r in || dd\n" 526 "ninja_dyndep_version = 1\n" 527 "build out: dyndep\n" 532 EXPECT_TRUE(scan_.LoadDyndeps(GetNode(
"dd"), &err));
536 Edge* edge = GetNode(
"out")->in_edge();
550 " command = unused\n" 551 "build out1: r in || dd\n" 556 "ninja_dyndep_version = 1\n" 557 "build out1: dyndep | out2\n" 562 EXPECT_TRUE(scan_.LoadDyndeps(GetNode(
"dd"), &err));
566 Edge* edge = GetNode(
"out1")->in_edge();
581 " command = unused\n" 582 "build out: r in || dd\n" 589 EXPECT_EQ(
"loading 'dd': No such file or directory", err);
595 " command = unused\n" 596 "build out: r in || dd\n" 600 "ninja_dyndep_version = 1\n" 606 EXPECT_EQ(
"'out' not mentioned in its dyndep file 'dd'", err);
612 " command = unused\n" 613 "build out: r in || dd\n" 615 "build out2: r in || dd\n" 618 "ninja_dyndep_version = 1\n" 619 "build out: dyndep\n" 620 "build out2: dyndep\n" 626 EXPECT_EQ(
"dyndep file 'dd' mentions output 'out2' whose build statement " 627 "does not have a dyndep binding for the file", err);
633 " command = unused\n" 634 "build out1 | out-twice.imp: r in1\n" 635 "build out2: r in2 || dd\n" 639 "ninja_dyndep_version = 1\n" 640 "build out2 | out-twice.imp: dyndep\n" 646 EXPECT_EQ(
"multiple rules generate out-twice.imp", err);
652 " command = unused\n" 653 "build out1: r in1 || dd1\n" 655 "build out2: r in2 || dd2\n" 659 "ninja_dyndep_version = 1\n" 660 "build out1 | out-twice.imp: dyndep\n" 663 "ninja_dyndep_version = 1\n" 664 "build out2 | out-twice.imp: dyndep\n" 669 EXPECT_TRUE(scan_.LoadDyndeps(GetNode(
"dd1"), &err));
673 EXPECT_EQ(
"multiple rules generate out-twice.imp", err);
679 " command = unused\n" 680 "build out1: r in1 || dd\n" 682 "build out2: r in2 || dd\n" 684 "build outNot: r in3 || dd\n" 687 "ninja_dyndep_version = 1\n" 688 "build out1 | out1imp: dyndep | in1imp\n" 689 "build out2: dyndep | in2imp\n" 695 EXPECT_TRUE(scan_.LoadDyndeps(GetNode(
"dd"), &err));
699 Edge* edge1 = GetNode(
"out1")->in_edge();
711 EXPECT_EQ(edge1, GetNode(
"out1imp")->in_edge());
712 Node* in1imp = GetNode(
"in1imp");
716 Edge* edge2 = GetNode(
"out2")->in_edge();
718 EXPECT_EQ(
"out2", edge2->outputs_[0]->path());
721 EXPECT_EQ(
"in2", edge2->inputs_[0]->path());
722 EXPECT_EQ(
"in2imp", edge2->inputs_[1]->path());
723 EXPECT_EQ(
"dd", edge2->inputs_[2]->path());
727 Node* in2imp = GetNode(
"in2imp");
728 ASSERT_EQ(1u, in2imp->out_edges().size());
729 EXPECT_EQ(edge2, in2imp->out_edges()[0]);
735 " command = unused\n" 736 "build out: r || dd\n" 741 EXPECT_FALSE(scan_.RecomputeDirty(GetNode(
"out"), NULL, &err));
742 ASSERT_EQ(
"loading 'dd': No such file or directory", err);
748 " command = unused\n" 749 "build out: r || dd\n" 753 "ninja_dyndep_version = 1\n" 757 EXPECT_FALSE(scan_.RecomputeDirty(GetNode(
"out"), NULL, &err));
758 ASSERT_EQ(
"'out' not mentioned in its dyndep file 'dd'", err);
764 " command = unused\n" 765 "build out: r || dd\n" 769 "ninja_dyndep_version = 1\n" 770 "build out: dyndep | in\n" 772 fs_.Create(
"out",
"");
774 fs_.Create(
"in",
"");
777 EXPECT_TRUE(scan_.RecomputeDirty(GetNode(
"out"), NULL, &err));
790 " command = unused\n" 791 "build dd: r dd-in\n" 792 "build out: r || dd\n" 795 fs_.Create(
"dd-in",
"");
797 "ninja_dyndep_version = 1\n" 798 "build out: dyndep | in\n" 800 fs_.Create(
"out",
"");
802 fs_.Create(
"in",
"");
805 EXPECT_TRUE(scan_.RecomputeDirty(GetNode(
"out"), NULL, &err));
810 EXPECT_TRUE(GetNode(
"dd")->in_edge()->outputs_ready());
819 " command = unused\n" 820 "build dd: r dd-in\n" 821 "build out: r || dd\n" 824 fs_.Create(
"dd",
"this-should-not-be-loaded");
826 fs_.Create(
"dd-in",
"");
827 fs_.Create(
"out",
"");
830 EXPECT_TRUE(scan_.RecomputeDirty(GetNode(
"out"), NULL, &err));
834 EXPECT_FALSE(GetNode(
"dd")->in_edge()->outputs_ready());
838 EXPECT_FALSE(GetNode(
"out")->in_edge()->outputs_ready());
844 " command = unused\n" 846 "build dd: r dd-in || tmp\n" 847 "build out: r || dd\n" 850 fs_.Create(
"dd",
"this-should-not-be-loaded");
851 fs_.Create(
"dd-in",
"");
853 fs_.Create(
"out",
"");
856 EXPECT_TRUE(scan_.RecomputeDirty(GetNode(
"out"), NULL, &err));
860 EXPECT_FALSE(GetNode(
"dd")->in_edge()->outputs_ready());
862 EXPECT_FALSE(GetNode(
"out")->in_edge()->outputs_ready());
868 " command = unused\n" 869 "build dd1: r dd1-in\n" 870 "build dd2-in: r || dd1\n" 872 "build dd2: r dd2-in\n" 873 "build out: r || dd2\n" 876 fs_.Create(
"dd1",
"");
877 fs_.Create(
"dd2",
"");
878 fs_.Create(
"dd2-in",
"");
880 fs_.Create(
"dd1-in",
"");
881 fs_.Create(
"out",
"");
884 EXPECT_TRUE(scan_.RecomputeDirty(GetNode(
"out"), NULL, &err));
888 EXPECT_FALSE(GetNode(
"dd1")->in_edge()->outputs_ready());
890 EXPECT_FALSE(GetNode(
"dd2")->in_edge()->outputs_ready());
892 EXPECT_FALSE(GetNode(
"out")->in_edge()->outputs_ready());
898 " command = unused\n" 899 "build out: r in || dd\n" 904 fs_.Create(
"out.d",
"out: inimp\n");
906 "ninja_dyndep_version = 1\n" 907 "build out | circ: dyndep\n" 909 fs_.Create(
"out",
"");
911 Edge* edge = GetNode(
"out")->in_edge();
913 EXPECT_FALSE(scan_.RecomputeDirty(GetNode(
"out"), NULL, &err));
914 EXPECT_EQ(
"dependency cycle: circ -> in -> circ", err);
928 "build out: cat in |@ validate\n" 929 "build validate: cat in\n"));
931 fs_.Create(
"in",
"");
933 std::vector<Node*> validation_nodes;
934 EXPECT_TRUE(scan_.RecomputeDirty(GetNode(
"out"), &validation_nodes, &err));
938 EXPECT_EQ(validation_nodes[0]->path(),
"validate");
949 " command = touch $out\n" 950 "build in_ph: phony in1\n" 951 "build out1: touch in_ph\n" 953 fs_.Create(
"in1",
"");
954 fs_.Create(
"out1",
"");
955 Node* out1 = GetNode(
"out1");
956 Node* in1 = GetNode(
"in1");
958 EXPECT_TRUE(scan_.RecomputeDirty(out1, NULL, &err));
970 fs_.Create(
"in1",
"");
975 EXPECT_TRUE(scan_.RecomputeDirty(out1, NULL, &err));
An implementation of DiskInterface that uses an in-memory representation of disk state.
bool Stat(DiskInterface *disk_interface, std::string *err)
Return false on error.
void AssertParse(State *state, const char *input, ManifestParserOptions opts)
Plan stores the state of a build plan: what we intend to build, which steps we're ready to execute...
PhonyCycleAction phony_cycle_action_
Information about a node in the dependency graph: the file, whether it's dirty, mtime, etc.
std::vector< Node * > outputs_
int command_edge_count() const
Number of edges with commands to run.
An edge in the dependency graph; links between Nodes using Rules.
A base test fixture that includes a State object with a builtin "cat" rule.
std::vector< Node * > inputs_
std::string GetBinding(const std::string &key) const
Returns the shell-escaped value of |key|.
bool AddTarget(const Node *target, std::string *err)
Add a target to our plan (including all its dependencies).
DependencyScan manages the process of scanning the files in a graph and updating the dirty/outputs_re...
#define ASSERT_NO_FATAL_FAILURE(a)
std::string EvaluateCommand(bool incl_rsp_file=false) const
Expand all variables in a command and return it as a string.
const std::vector< Edge * > & out_edges() const
bool more_to_do() const
Returns true if there's more work to be done.
bool GetBindingBool(const std::string &key) const
void CollectInputs(bool shell_escape, std::vector< std::string > *out) const
TEST_F(GraphTest, MissingImplicit)