Ninja
manifest_parser_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 "manifest_parser.h"
16
17#include <map>
18#include <vector>
19
20#include "graph.h"
21#include "state.h"
22#include "test.h"
23
24using namespace std;
25
26struct ParserTest : public testing::Test {
27 void AssertParse(const char* input) {
28 ManifestParser parser(&state, &fs_);
29 string err;
30 EXPECT_TRUE(parser.ParseTest(input, &err));
31 ASSERT_EQ("", err);
33 }
34
37};
38
40 ASSERT_NO_FATAL_FAILURE(AssertParse(""));
41}
42
44 ASSERT_NO_FATAL_FAILURE(AssertParse(
45"rule cat\n"
46" command = cat $in > $out\n"
47"\n"
48"rule date\n"
49" command = date > $out\n"
50"\n"
51"build result: cat in_1.cc in-2.O\n"));
52
53 ASSERT_EQ(3u, state.bindings_.GetRules().size());
54 const auto& rule = state.bindings_.GetRules().begin()->second;
55 EXPECT_EQ("cat", rule->name());
56 EXPECT_EQ("[cat ][$in][ > ][$out]",
57 rule->GetBinding("command")->Serialize());
58}
59
60TEST_F(ParserTest, RuleAttributes) {
61 // Check that all of the allowed rule attributes are parsed ok.
62 ASSERT_NO_FATAL_FAILURE(AssertParse(
63"rule cat\n"
64" command = a\n"
65" depfile = a\n"
66" deps = a\n"
67" description = a\n"
68" generator = a\n"
69" restat = a\n"
70" rspfile = a\n"
71" rspfile_content = a\n"
72));
73}
74
75TEST_F(ParserTest, IgnoreIndentedComments) {
76 ASSERT_NO_FATAL_FAILURE(AssertParse(
77" #indented comment\n"
78"rule cat\n"
79" command = cat $in > $out\n"
80" #generator = 1\n"
81" restat = 1 # comment\n"
82" #comment\n"
83"build result: cat in_1.cc in-2.O\n"
84" #comment\n"));
85
86 ASSERT_EQ(2u, state.bindings_.GetRules().size());
87 const auto& rule = state.bindings_.GetRules().begin()->second;
88 EXPECT_EQ("cat", rule->name());
89 Edge* edge = state.GetNode("result", 0)->in_edge();
90 EXPECT_TRUE(edge->GetBindingBool("restat"));
91 EXPECT_FALSE(edge->GetBindingBool("generator"));
92}
93
94TEST_F(ParserTest, IgnoreIndentedBlankLines) {
95 // the indented blanks used to cause parse errors
96 ASSERT_NO_FATAL_FAILURE(AssertParse(
97" \n"
98"rule cat\n"
99" command = cat $in > $out\n"
100" \n"
101"build result: cat in_1.cc in-2.O\n"
102" \n"
103"variable=1\n"));
104
105 // the variable must be in the top level environment
106 EXPECT_EQ("1", state.bindings_.LookupVariable("variable"));
107}
108
109TEST_F(ParserTest, ResponseFiles) {
110 ASSERT_NO_FATAL_FAILURE(AssertParse(
111"rule cat_rsp\n"
112" command = cat $rspfile > $out\n"
113" rspfile = $rspfile\n"
114" rspfile_content = $in\n"
115"\n"
116"build out: cat_rsp in\n"
117" rspfile=out.rsp\n"));
118
119 ASSERT_EQ(2u, state.bindings_.GetRules().size());
120 const auto& rule = state.bindings_.GetRules().begin()->second;
121 EXPECT_EQ("cat_rsp", rule->name());
122 EXPECT_EQ("[cat ][$rspfile][ > ][$out]",
123 rule->GetBinding("command")->Serialize());
124 EXPECT_EQ("[$rspfile]", rule->GetBinding("rspfile")->Serialize());
125 EXPECT_EQ("[$in]", rule->GetBinding("rspfile_content")->Serialize());
126}
127
128TEST_F(ParserTest, InNewline) {
129 ASSERT_NO_FATAL_FAILURE(AssertParse(
130"rule cat_rsp\n"
131" command = cat $in_newline > $out\n"
132"\n"
133"build out: cat_rsp in in2\n"
134" rspfile=out.rsp\n"));
135
136 ASSERT_EQ(2u, state.bindings_.GetRules().size());
137 const auto& rule = state.bindings_.GetRules().begin()->second;
138 EXPECT_EQ("cat_rsp", rule->name());
139 EXPECT_EQ("[cat ][$in_newline][ > ][$out]",
140 rule->GetBinding("command")->Serialize());
141
142 Edge* edge = state.edges_[0];
143 EXPECT_EQ("cat in\nin2 > out", edge->EvaluateCommand());
144}
145
146TEST_F(ParserTest, Variables) {
147 ASSERT_NO_FATAL_FAILURE(AssertParse(
148"l = one-letter-test\n"
149"rule link\n"
150" command = ld $l $extra $with_under -o $out $in\n"
151"\n"
152"extra = -pthread\n"
153"with_under = -under\n"
154"build a: link b c\n"
155"nested1 = 1\n"
156"nested2 = $nested1/2\n"
157"build supernested: link x\n"
158" extra = $nested2/3\n"));
159
160 ASSERT_EQ(2u, state.edges_.size());
161 Edge* edge = state.edges_[0];
162 EXPECT_EQ("ld one-letter-test -pthread -under -o a b c",
163 edge->EvaluateCommand());
164 EXPECT_EQ("1/2", state.bindings_.LookupVariable("nested2"));
165
166 edge = state.edges_[1];
167 EXPECT_EQ("ld one-letter-test 1/2/3 -under -o supernested x",
168 edge->EvaluateCommand());
169}
170
171TEST_F(ParserTest, VariableScope) {
172 ASSERT_NO_FATAL_FAILURE(AssertParse(
173"foo = bar\n"
174"rule cmd\n"
175" command = cmd $foo $in $out\n"
176"\n"
177"build inner: cmd a\n"
178" foo = baz\n"
179"build outer: cmd b\n"
180"\n" // Extra newline after build line tickles a regression.
181));
182
183 ASSERT_EQ(2u, state.edges_.size());
184 EXPECT_EQ("cmd baz a inner", state.edges_[0]->EvaluateCommand());
185 EXPECT_EQ("cmd bar b outer", state.edges_[1]->EvaluateCommand());
186}
187
188TEST_F(ParserTest, Continuation) {
189 ASSERT_NO_FATAL_FAILURE(AssertParse(
190"rule link\n"
191" command = foo bar $\n"
192" baz\n"
193"\n"
194"build a: link c $\n"
195" d e f\n"));
196
197 ASSERT_EQ(2u, state.bindings_.GetRules().size());
198 const auto& rule = state.bindings_.GetRules().begin()->second;
199 EXPECT_EQ("link", rule->name());
200 EXPECT_EQ("[foo bar baz]", rule->GetBinding("command")->Serialize());
201}
202
203TEST_F(ParserTest, Backslash) {
204 ASSERT_NO_FATAL_FAILURE(AssertParse(
205"foo = bar\\baz\n"
206"foo2 = bar\\ baz\n"
207));
208 EXPECT_EQ("bar\\baz", state.bindings_.LookupVariable("foo"));
209 EXPECT_EQ("bar\\ baz", state.bindings_.LookupVariable("foo2"));
210}
211
213 ASSERT_NO_FATAL_FAILURE(AssertParse(
214"# this is a comment\n"
215"foo = not # a comment\n"));
216 EXPECT_EQ("not # a comment", state.bindings_.LookupVariable("foo"));
217}
218
220 ASSERT_NO_FATAL_FAILURE(AssertParse(
221"rule foo\n"
222" command = ${out}bar$$baz$$$\n"
223"blah\n"
224"x = $$dollar\n"
225"build $x: foo y\n"
226));
227 EXPECT_EQ("$dollar", state.bindings_.LookupVariable("x"));
228#ifdef _WIN32
229 EXPECT_EQ("$dollarbar$baz$blah", state.edges_[0]->EvaluateCommand());
230#else
231 EXPECT_EQ("'$dollar'bar$baz$blah", state.edges_[0]->EvaluateCommand());
232#endif
233}
234
235TEST_F(ParserTest, EscapeSpaces) {
236 ASSERT_NO_FATAL_FAILURE(AssertParse(
237"rule spaces\n"
238" command = something\n"
239"build foo$ bar: spaces $$one two$$$ three\n"
240));
241 EXPECT_TRUE(state.LookupNode("foo bar"));
242 EXPECT_EQ(state.edges_[0]->outputs_[0]->path(), "foo bar");
243 EXPECT_EQ(state.edges_[0]->inputs_[0]->path(), "$one");
244 EXPECT_EQ(state.edges_[0]->inputs_[1]->path(), "two$ three");
245 EXPECT_EQ(state.edges_[0]->EvaluateCommand(), "something");
246}
247
248TEST_F(ParserTest, CanonicalizeFile) {
249 ASSERT_NO_FATAL_FAILURE(AssertParse(
250"rule cat\n"
251" command = cat $in > $out\n"
252"build out: cat in/1 in//2\n"
253"build in/1: cat\n"
254"build in/2: cat\n"));
255
256 EXPECT_TRUE(state.LookupNode("in/1"));
257 EXPECT_TRUE(state.LookupNode("in/2"));
258 EXPECT_FALSE(state.LookupNode("in//1"));
259 EXPECT_FALSE(state.LookupNode("in//2"));
260}
261
262#ifdef _WIN32
263TEST_F(ParserTest, CanonicalizeFileBackslashes) {
264 ASSERT_NO_FATAL_FAILURE(AssertParse(
265"rule cat\n"
266" command = cat $in > $out\n"
267"build out: cat in\\1 in\\\\2\n"
268"build in\\1: cat\n"
269"build in\\2: cat\n"));
270
271 Node* node = state.LookupNode("in/1");;
272 EXPECT_TRUE(node);
273 EXPECT_EQ(1, node->slash_bits());
274 node = state.LookupNode("in/2");
275 EXPECT_TRUE(node);
276 EXPECT_EQ(1, node->slash_bits());
277 EXPECT_FALSE(state.LookupNode("in//1"));
278 EXPECT_FALSE(state.LookupNode("in//2"));
279}
280#endif
281
282TEST_F(ParserTest, PathVariables) {
283 ASSERT_NO_FATAL_FAILURE(AssertParse(
284"rule cat\n"
285" command = cat $in > $out\n"
286"dir = out\n"
287"build $dir/exe: cat src\n"));
288
289 EXPECT_FALSE(state.LookupNode("$dir/exe"));
290 EXPECT_TRUE(state.LookupNode("out/exe"));
291}
292
293TEST_F(ParserTest, CanonicalizePaths) {
294 ASSERT_NO_FATAL_FAILURE(AssertParse(
295"rule cat\n"
296" command = cat $in > $out\n"
297"build ./out.o: cat ./bar/baz/../foo.cc\n"));
298
299 EXPECT_FALSE(state.LookupNode("./out.o"));
300 EXPECT_TRUE(state.LookupNode("out.o"));
301 EXPECT_FALSE(state.LookupNode("./bar/baz/../foo.cc"));
302 EXPECT_TRUE(state.LookupNode("bar/foo.cc"));
303}
304
305#ifdef _WIN32
306TEST_F(ParserTest, CanonicalizePathsBackslashes) {
307 ASSERT_NO_FATAL_FAILURE(AssertParse(
308"rule cat\n"
309" command = cat $in > $out\n"
310"build ./out.o: cat ./bar/baz/../foo.cc\n"
311"build .\\out2.o: cat .\\bar/baz\\..\\foo.cc\n"
312"build .\\out3.o: cat .\\bar\\baz\\..\\foo3.cc\n"
313));
314
315 EXPECT_FALSE(state.LookupNode("./out.o"));
316 EXPECT_FALSE(state.LookupNode(".\\out2.o"));
317 EXPECT_FALSE(state.LookupNode(".\\out3.o"));
318 EXPECT_TRUE(state.LookupNode("out.o"));
319 EXPECT_TRUE(state.LookupNode("out2.o"));
320 EXPECT_TRUE(state.LookupNode("out3.o"));
321 EXPECT_FALSE(state.LookupNode("./bar/baz/../foo.cc"));
322 EXPECT_FALSE(state.LookupNode(".\\bar/baz\\..\\foo.cc"));
323 EXPECT_FALSE(state.LookupNode(".\\bar/baz\\..\\foo3.cc"));
324 Node* node = state.LookupNode("bar/foo.cc");
325 EXPECT_TRUE(node);
326 EXPECT_EQ(0, node->slash_bits());
327 node = state.LookupNode("bar/foo3.cc");
328 EXPECT_TRUE(node);
329 EXPECT_EQ(1, node->slash_bits());
330}
331#endif
332
333TEST_F(ParserTest, DuplicateEdgeWithMultipleOutputsError) {
334 const char kInput[] =
335"rule cat\n"
336" command = cat $in > $out\n"
337"build out1 out2: cat in1\n"
338"build out1: cat in2\n"
339"build final: cat out1\n";
340 ManifestParser parser(&state, &fs_);
341 string err;
342 EXPECT_FALSE(parser.ParseTest(kInput, &err));
343 EXPECT_EQ("input:5: multiple rules generate out1\n", err);
344}
345
346TEST_F(ParserTest, DuplicateEdgeInIncludedFile) {
347 fs_.Create("sub.ninja",
348 "rule cat\n"
349 " command = cat $in > $out\n"
350 "build out1 out2: cat in1\n"
351 "build out1: cat in2\n"
352 "build final: cat out1\n");
353 const char kInput[] =
354 "subninja sub.ninja\n";
355 ManifestParser parser(&state, &fs_);
356 string err;
357 EXPECT_FALSE(parser.ParseTest(kInput, &err));
358 EXPECT_EQ("sub.ninja:5: multiple rules generate out1\n", err);
359}
360
361TEST_F(ParserTest, PhonySelfReferenceIgnored) {
362 ASSERT_NO_FATAL_FAILURE(AssertParse(
363"build a: phony a\n"
364));
365
366 Node* node = state.LookupNode("a");
367 Edge* edge = node->in_edge();
368 ASSERT_TRUE(edge->inputs_.empty());
369}
370
371TEST_F(ParserTest, PhonySelfReferenceKept) {
372 const char kInput[] =
373"build a: phony a\n";
374 ManifestParserOptions parser_opts;
376 ManifestParser parser(&state, &fs_, parser_opts);
377 string err;
378 EXPECT_TRUE(parser.ParseTest(kInput, &err));
379 EXPECT_EQ("", err);
380
381 Node* node = state.LookupNode("a");
382 Edge* edge = node->in_edge();
383 ASSERT_EQ(edge->inputs_.size(), size_t(1));
384 ASSERT_EQ(edge->inputs_[0], node);
385}
386
387TEST_F(ParserTest, ReservedWords) {
388 ASSERT_NO_FATAL_FAILURE(AssertParse(
389"rule build\n"
390" command = rule run $out\n"
391"build subninja: build include default foo.cc\n"
392"default subninja\n"));
393}
394
396 {
397 State local_state;
398 ManifestParser parser(&local_state, NULL);
399 string err;
400 EXPECT_FALSE(parser.ParseTest(string("subn", 4), &err));
401 EXPECT_EQ("input:1: expected '=', got eof\n"
402 "subn\n"
403 " ^ near here"
404 , err);
405 }
406
407 {
408 State local_state;
409 ManifestParser parser(&local_state, NULL);
410 string err;
411 EXPECT_FALSE(parser.ParseTest("foobar", &err));
412 EXPECT_EQ("input:1: expected '=', got eof\n"
413 "foobar\n"
414 " ^ near here"
415 , err);
416 }
417
418 {
419 State local_state;
420 ManifestParser parser(&local_state, NULL);
421 string err;
422 EXPECT_FALSE(parser.ParseTest("x 3", &err));
423 EXPECT_EQ("input:1: expected '=', got identifier\n"
424 "x 3\n"
425 " ^ near here"
426 , err);
427 }
428
429 {
430 State local_state;
431 ManifestParser parser(&local_state, NULL);
432 string err;
433 EXPECT_FALSE(parser.ParseTest("x = 3", &err));
434 EXPECT_EQ("input:1: unexpected EOF\n"
435 "x = 3\n"
436 " ^ near here"
437 , err);
438 }
439
440 {
441 State local_state;
442 ManifestParser parser(&local_state, NULL);
443 string err;
444 EXPECT_FALSE(parser.ParseTest("x = 3\ny 2", &err));
445 EXPECT_EQ("input:2: expected '=', got identifier\n"
446 "y 2\n"
447 " ^ near here"
448 , err);
449 }
450
451 {
452 State local_state;
453 ManifestParser parser(&local_state, NULL);
454 string err;
455 EXPECT_FALSE(parser.ParseTest("x = $", &err));
456 EXPECT_EQ("input:1: bad $-escape (literal $ must be written as $$)\n"
457 "x = $\n"
458 " ^ near here"
459 , err);
460 }
461
462 {
463 State local_state;
464 ManifestParser parser(&local_state, NULL);
465 string err;
466 EXPECT_FALSE(parser.ParseTest("x = $\n $[\n", &err));
467 EXPECT_EQ("input:2: bad $-escape (literal $ must be written as $$)\n"
468 " $[\n"
469 " ^ near here"
470 , err);
471 }
472
473 {
474 State local_state;
475 ManifestParser parser(&local_state, NULL);
476 string err;
477 EXPECT_FALSE(parser.ParseTest("x = a$\n b$\n $\n", &err));
478 EXPECT_EQ("input:4: unexpected EOF\n"
479 , err);
480 }
481
482 {
483 State local_state;
484 ManifestParser parser(&local_state, NULL);
485 string err;
486 EXPECT_FALSE(parser.ParseTest("build\n", &err));
487 EXPECT_EQ("input:1: expected path\n"
488 "build\n"
489 " ^ near here"
490 , err);
491 }
492
493 {
494 State local_state;
495 ManifestParser parser(&local_state, NULL);
496 string err;
497 EXPECT_FALSE(parser.ParseTest("build x: y z\n", &err));
498 EXPECT_EQ("input:1: unknown build rule 'y'\n"
499 "build x: y z\n"
500 " ^ near here"
501 , err);
502 }
503
504 {
505 State local_state;
506 ManifestParser parser(&local_state, NULL);
507 string err;
508 EXPECT_FALSE(parser.ParseTest("build x:: y z\n", &err));
509 EXPECT_EQ("input:1: expected build command name\n"
510 "build x:: y z\n"
511 " ^ near here"
512 , err);
513 }
514
515 {
516 State local_state;
517 ManifestParser parser(&local_state, NULL);
518 string err;
519 EXPECT_FALSE(parser.ParseTest("rule cat\n command = cat ok\n"
520 "build x: cat $\n :\n",
521 &err));
522 EXPECT_EQ("input:4: expected newline, got ':'\n"
523 " :\n"
524 " ^ near here"
525 , err);
526 }
527
528 {
529 State local_state;
530 ManifestParser parser(&local_state, NULL);
531 string err;
532 EXPECT_FALSE(parser.ParseTest("rule cat\n",
533 &err));
534 EXPECT_EQ("input:2: expected 'command =' line\n", err);
535 }
536
537 {
538 State local_state;
539 ManifestParser parser(&local_state, NULL);
540 string err;
541 EXPECT_FALSE(parser.ParseTest("rule cat\n"
542 " command = echo\n"
543 "rule cat\n"
544 " command = echo\n", &err));
545 EXPECT_EQ("input:3: duplicate rule 'cat'\n"
546 "rule cat\n"
547 " ^ near here"
548 , err);
549 }
550
551 {
552 State local_state;
553 ManifestParser parser(&local_state, NULL);
554 string err;
555 EXPECT_FALSE(parser.ParseTest("rule cat\n"
556 " command = echo\n"
557 " rspfile = cat.rsp\n", &err));
558 EXPECT_EQ(
559 "input:4: rspfile and rspfile_content need to be both specified\n",
560 err);
561 }
562
563 {
564 State local_state;
565 ManifestParser parser(&local_state, NULL);
566 string err;
567 EXPECT_FALSE(parser.ParseTest("rule cat\n"
568 " command = ${fafsd\n"
569 "foo = bar\n",
570 &err));
571 EXPECT_EQ("input:2: bad $-escape (literal $ must be written as $$)\n"
572 " command = ${fafsd\n"
573 " ^ near here"
574 , err);
575 }
576
577
578 {
579 State local_state;
580 ManifestParser parser(&local_state, NULL);
581 string err;
582 EXPECT_FALSE(parser.ParseTest("rule cat\n"
583 " command = cat\n"
584 "build $.: cat foo\n",
585 &err));
586 EXPECT_EQ("input:3: bad $-escape (literal $ must be written as $$)\n"
587 "build $.: cat foo\n"
588 " ^ near here"
589 , err);
590 }
591
592
593 {
594 State local_state;
595 ManifestParser parser(&local_state, NULL);
596 string err;
597 EXPECT_FALSE(parser.ParseTest("rule cat\n"
598 " command = cat\n"
599 "build $: cat foo\n",
600 &err));
601 EXPECT_EQ("input:3: expected ':', got newline ($ also escapes ':')\n"
602 "build $: cat foo\n"
603 " ^ near here"
604 , err);
605 }
606
607 {
608 State local_state;
609 ManifestParser parser(&local_state, NULL);
610 string err;
611 EXPECT_FALSE(parser.ParseTest("rule %foo\n",
612 &err));
613 EXPECT_EQ("input:1: expected rule name\n"
614 "rule %foo\n"
615 " ^ near here",
616 err);
617 }
618
619 {
620 State local_state;
621 ManifestParser parser(&local_state, NULL);
622 string err;
623 EXPECT_FALSE(parser.ParseTest("rule cc\n"
624 " command = foo\n"
625 " othervar = bar\n",
626 &err));
627 EXPECT_EQ("input:3: unexpected variable 'othervar'\n"
628 " othervar = bar\n"
629 " ^ near here"
630 , err);
631 }
632
633 {
634 State local_state;
635 ManifestParser parser(&local_state, NULL);
636 string err;
637 EXPECT_FALSE(parser.ParseTest("rule cc\n command = foo\n"
638 "build $.: cc bar.cc\n",
639 &err));
640 EXPECT_EQ("input:3: bad $-escape (literal $ must be written as $$)\n"
641 "build $.: cc bar.cc\n"
642 " ^ near here"
643 , err);
644 }
645
646 {
647 State local_state;
648 ManifestParser parser(&local_state, NULL);
649 string err;
650 EXPECT_FALSE(parser.ParseTest("rule cc\n command = foo\n && bar",
651 &err));
652 EXPECT_EQ("input:3: expected variable name\n"
653 " && bar\n"
654 " ^ near here",
655 err);
656 }
657
658 {
659 State local_state;
660 ManifestParser parser(&local_state, NULL);
661 string err;
662 EXPECT_FALSE(parser.ParseTest("rule cc\n command = foo\n"
663 "build $: cc bar.cc\n",
664 &err));
665 EXPECT_EQ("input:3: expected ':', got newline ($ also escapes ':')\n"
666 "build $: cc bar.cc\n"
667 " ^ near here"
668 , err);
669 }
670
671 {
672 State local_state;
673 ManifestParser parser(&local_state, NULL);
674 string err;
675 EXPECT_FALSE(parser.ParseTest("default\n",
676 &err));
677 EXPECT_EQ("input:1: expected target name\n"
678 "default\n"
679 " ^ near here"
680 , err);
681 }
682
683 {
684 State local_state;
685 ManifestParser parser(&local_state, NULL);
686 string err;
687 EXPECT_FALSE(parser.ParseTest("default nonexistent\n",
688 &err));
689 EXPECT_EQ("input:1: unknown target 'nonexistent'\n"
690 "default nonexistent\n"
691 " ^ near here"
692 , err);
693 }
694
695 {
696 State local_state;
697 ManifestParser parser(&local_state, NULL);
698 string err;
699 EXPECT_FALSE(parser.ParseTest("rule r\n command = r\n"
700 "build b: r\n"
701 "default b:\n",
702 &err));
703 EXPECT_EQ("input:4: expected newline, got ':'\n"
704 "default b:\n"
705 " ^ near here"
706 , err);
707 }
708
709 {
710 State local_state;
711 ManifestParser parser(&local_state, NULL);
712 string err;
713 EXPECT_FALSE(parser.ParseTest("default $a\n", &err));
714 EXPECT_EQ("input:1: empty path\n"
715 "default $a\n"
716 " ^ near here"
717 , err);
718 }
719
720 {
721 State local_state;
722 ManifestParser parser(&local_state, NULL);
723 string err;
724 EXPECT_FALSE(parser.ParseTest("rule r\n"
725 " command = r\n"
726 "build $a: r $c\n", &err));
727 // XXX the line number is wrong; we should evaluate paths in ParseEdge
728 // as we see them, not after we've read them all!
729 EXPECT_EQ("input:4: empty path\n", err);
730 }
731
732 {
733 State local_state;
734 ManifestParser parser(&local_state, NULL);
735 string err;
736 // the indented blank line must terminate the rule
737 // this also verifies that "unexpected (token)" errors are correct
738 EXPECT_FALSE(parser.ParseTest("rule r\n"
739 " command = r\n"
740 " \n"
741 " generator = 1\n", &err));
742 EXPECT_EQ("input:4: unexpected indent\n", err);
743 }
744
745 {
746 State local_state;
747 ManifestParser parser(&local_state, NULL);
748 string err;
749 EXPECT_FALSE(parser.ParseTest("pool\n", &err));
750 EXPECT_EQ("input:1: expected pool name\n"
751 "pool\n"
752 " ^ near here", err);
753 }
754
755 {
756 State local_state;
757 ManifestParser parser(&local_state, NULL);
758 string err;
759 EXPECT_FALSE(parser.ParseTest("pool foo\n", &err));
760 EXPECT_EQ("input:2: expected 'depth =' line\n", err);
761 }
762
763 {
764 State local_state;
765 ManifestParser parser(&local_state, NULL);
766 string err;
767 EXPECT_FALSE(parser.ParseTest("pool foo\n"
768 " depth = 4\n"
769 "pool foo\n", &err));
770 EXPECT_EQ("input:3: duplicate pool 'foo'\n"
771 "pool foo\n"
772 " ^ near here"
773 , err);
774 }
775
776 {
777 State local_state;
778 ManifestParser parser(&local_state, NULL);
779 string err;
780 EXPECT_FALSE(parser.ParseTest("pool foo\n"
781 " depth = -1\n", &err));
782 EXPECT_EQ("input:2: invalid pool depth\n"
783 " depth = -1\n"
784 " ^ near here"
785 , err);
786 }
787
788 {
789 State local_state;
790 ManifestParser parser(&local_state, NULL);
791 string err;
792 EXPECT_FALSE(parser.ParseTest("pool foo\n"
793 " bar = 1\n", &err));
794 EXPECT_EQ("input:2: unexpected variable 'bar'\n"
795 " bar = 1\n"
796 " ^ near here"
797 , err);
798 }
799
800 {
801 State local_state;
802 ManifestParser parser(&local_state, NULL);
803 string err;
804 // Pool names are dereferenced at edge parsing time.
805 EXPECT_FALSE(parser.ParseTest("rule run\n"
806 " command = echo\n"
807 " pool = unnamed_pool\n"
808 "build out: run in\n", &err));
809 EXPECT_EQ("input:5: unknown pool name 'unnamed_pool'\n", err);
810 }
811}
812
813TEST_F(ParserTest, MissingInput) {
814 State local_state;
815 ManifestParser parser(&local_state, &fs_);
816 string err;
817 EXPECT_FALSE(parser.Load("build.ninja", &err));
818 EXPECT_EQ("loading 'build.ninja': No such file or directory", err);
819}
820
821TEST_F(ParserTest, MultipleOutputs) {
822 State local_state;
823 ManifestParser parser(&local_state, NULL);
824 string err;
825 EXPECT_TRUE(parser.ParseTest("rule cc\n command = foo\n depfile = bar\n"
826 "build a.o b.o: cc c.cc\n",
827 &err));
828 EXPECT_EQ("", err);
829}
830
831TEST_F(ParserTest, MultipleOutputsWithDeps) {
832 State local_state;
833 ManifestParser parser(&local_state, NULL);
834 string err;
835 EXPECT_TRUE(parser.ParseTest("rule cc\n command = foo\n deps = gcc\n"
836 "build a.o b.o: cc c.cc\n",
837 &err));
838 EXPECT_EQ("", err);
839}
840
841TEST_F(ParserTest, SubNinja) {
842 fs_.Create("test.ninja",
843 "var = inner\n"
844 "build $builddir/inner: varref\n");
845 ASSERT_NO_FATAL_FAILURE(AssertParse(
846"builddir = some_dir/\n"
847"rule varref\n"
848" command = varref $var\n"
849"var = outer\n"
850"build $builddir/outer: varref\n"
851"subninja test.ninja\n"
852"build $builddir/outer2: varref\n"));
853 ASSERT_EQ(1u, fs_.files_read_.size());
854
855 EXPECT_EQ("test.ninja", fs_.files_read_[0]);
856 EXPECT_TRUE(state.LookupNode("some_dir/outer"));
857 // Verify our builddir setting is inherited.
858 EXPECT_TRUE(state.LookupNode("some_dir/inner"));
859
860 ASSERT_EQ(3u, state.edges_.size());
861 EXPECT_EQ("varref outer", state.edges_[0]->EvaluateCommand());
862 EXPECT_EQ("varref inner", state.edges_[1]->EvaluateCommand());
863 EXPECT_EQ("varref outer", state.edges_[2]->EvaluateCommand());
864}
865
866TEST_F(ParserTest, MissingSubNinja) {
867 ManifestParser parser(&state, &fs_);
868 string err;
869 EXPECT_FALSE(parser.ParseTest("subninja foo.ninja\n", &err));
870 EXPECT_EQ("input:1: loading 'foo.ninja': No such file or directory\n"
871 "subninja foo.ninja\n"
872 " ^ near here"
873 , err);
874}
875
876TEST_F(ParserTest, DuplicateRuleInDifferentSubninjas) {
877 // Test that rules are scoped to subninjas.
878 fs_.Create("test.ninja", "rule cat\n"
879 " command = cat\n");
880 ManifestParser parser(&state, &fs_);
881 string err;
882 EXPECT_TRUE(parser.ParseTest("rule cat\n"
883 " command = cat\n"
884 "subninja test.ninja\n", &err));
885}
886
887TEST_F(ParserTest, DuplicateRuleInDifferentSubninjasWithInclude) {
888 // Test that rules are scoped to subninjas even with includes.
889 fs_.Create("rules.ninja", "rule cat\n"
890 " command = cat\n");
891 fs_.Create("test.ninja", "include rules.ninja\n"
892 "build x : cat\n");
893 ManifestParser parser(&state, &fs_);
894 string err;
895 EXPECT_TRUE(parser.ParseTest("include rules.ninja\n"
896 "subninja test.ninja\n"
897 "build y : cat\n", &err));
898}
899
901 fs_.Create("include.ninja", "var = inner\n");
902 ASSERT_NO_FATAL_FAILURE(AssertParse(
903"var = outer\n"
904"include include.ninja\n"));
905
906 ASSERT_EQ(1u, fs_.files_read_.size());
907 EXPECT_EQ("include.ninja", fs_.files_read_[0]);
908 EXPECT_EQ("inner", state.bindings_.LookupVariable("var"));
909}
910
911TEST_F(ParserTest, BrokenInclude) {
912 fs_.Create("include.ninja", "build\n");
913 ManifestParser parser(&state, &fs_);
914 string err;
915 EXPECT_FALSE(parser.ParseTest("include include.ninja\n", &err));
916 EXPECT_EQ("include.ninja:1: expected path\n"
917 "build\n"
918 " ^ near here"
919 , err);
920}
921
922TEST_F(ParserTest, Implicit) {
923 ASSERT_NO_FATAL_FAILURE(AssertParse(
924"rule cat\n"
925" command = cat $in > $out\n"
926"build foo: cat bar | baz\n"));
927
928 Edge* edge = state.LookupNode("foo")->in_edge();
929 ASSERT_TRUE(edge->is_implicit(1));
930}
931
932TEST_F(ParserTest, OrderOnly) {
933 ASSERT_NO_FATAL_FAILURE(AssertParse(
934"rule cat\n command = cat $in > $out\n"
935"build foo: cat bar || baz\n"));
936
937 Edge* edge = state.LookupNode("foo")->in_edge();
938 ASSERT_TRUE(edge->is_order_only(1));
939}
940
941TEST_F(ParserTest, Validations) {
942 ASSERT_NO_FATAL_FAILURE(AssertParse(
943"rule cat\n command = cat $in > $out\n"
944"build foo: cat bar |@ baz\n"));
945
946 Edge* edge = state.LookupNode("foo")->in_edge();
947 ASSERT_EQ(edge->validations_.size(), size_t(1));
948 EXPECT_EQ(edge->validations_[0]->path(), "baz");
949}
950
951TEST_F(ParserTest, ImplicitOutput) {
952 ASSERT_NO_FATAL_FAILURE(AssertParse(
953"rule cat\n"
954" command = cat $in > $out\n"
955"build foo | imp: cat bar\n"));
956
957 Edge* edge = state.LookupNode("imp")->in_edge();
958 ASSERT_EQ(edge->outputs_.size(), size_t(2));
959 EXPECT_TRUE(edge->is_implicit_out(1));
960}
961
962TEST_F(ParserTest, ImplicitOutputEmpty) {
963 ASSERT_NO_FATAL_FAILURE(AssertParse(
964"rule cat\n"
965" command = cat $in > $out\n"
966"build foo | : cat bar\n"));
967
968 Edge* edge = state.LookupNode("foo")->in_edge();
969 ASSERT_EQ(edge->outputs_.size(), size_t(1));
970 EXPECT_FALSE(edge->is_implicit_out(0));
971}
972
973TEST_F(ParserTest, ImplicitOutputDupeError) {
974 const char kInput[] =
975"rule cat\n"
976" command = cat $in > $out\n"
977"build foo baz | foo baq foo: cat bar\n";
978 ManifestParser parser(&state, &fs_);
979 string err;
980 EXPECT_FALSE(parser.ParseTest(kInput, &err));
981 EXPECT_EQ("input:4: foo is defined as an output multiple times\n", err);
982}
983
984TEST_F(ParserTest, ImplicitOutputDupesError) {
985 const char kInput[] =
986"rule cat\n"
987" command = cat $in > $out\n"
988"build foo foo foo | foo foo foo foo: cat bar\n";
989 ManifestParser parser(&state, &fs_);
990 string err;
991 EXPECT_FALSE(parser.ParseTest(kInput, &err));
992 EXPECT_EQ("input:4: foo is defined as an output multiple times\n", err);
993}
994
995TEST_F(ParserTest, NoExplicitOutput) {
996 ManifestParser parser(&state, NULL);
997 string err;
998 EXPECT_TRUE(parser.ParseTest(
999"rule cat\n"
1000" command = cat $in > $out\n"
1001"build | imp : cat bar\n", &err));
1002}
1003
1004TEST_F(ParserTest, DefaultDefault) {
1005 ASSERT_NO_FATAL_FAILURE(AssertParse(
1006"rule cat\n command = cat $in > $out\n"
1007"build a: cat foo\n"
1008"build b: cat foo\n"
1009"build c: cat foo\n"
1010"build d: cat foo\n"));
1011
1012 string err;
1013 EXPECT_EQ(4u, state.DefaultNodes(&err).size());
1014 EXPECT_EQ("", err);
1015}
1016
1017TEST_F(ParserTest, DefaultDefaultCycle) {
1018 ASSERT_NO_FATAL_FAILURE(AssertParse(
1019"rule cat\n command = cat $in > $out\n"
1020"build a: cat a\n"));
1021
1022 string err;
1023 EXPECT_EQ(0u, state.DefaultNodes(&err).size());
1024 EXPECT_EQ("could not determine root nodes of build graph", err);
1025}
1026
1027TEST_F(ParserTest, DefaultStatements) {
1028 ASSERT_NO_FATAL_FAILURE(AssertParse(
1029"rule cat\n command = cat $in > $out\n"
1030"build a: cat foo\n"
1031"build b: cat foo\n"
1032"build c: cat foo\n"
1033"build d: cat foo\n"
1034"third = c\n"
1035"default a b\n"
1036"default $third\n"));
1037
1038 string err;
1039 vector<Node*> nodes = state.DefaultNodes(&err);
1040 EXPECT_EQ("", err);
1041 ASSERT_EQ(3u, nodes.size());
1042 EXPECT_EQ("a", nodes[0]->path());
1043 EXPECT_EQ("b", nodes[1]->path());
1044 EXPECT_EQ("c", nodes[2]->path());
1045}
1046
1048 ASSERT_NO_FATAL_FAILURE(AssertParse(
1049"rule utf8\n"
1050" command = true\n"
1051" description = compilaci\xC3\xB3\n"));
1052}
1053
1055 State local_state;
1056 ManifestParser parser(&local_state, NULL);
1057 string err;
1058
1059 EXPECT_TRUE(parser.ParseTest("# comment with crlf\r\n", &err));
1060 EXPECT_TRUE(parser.ParseTest("foo = foo\nbar = bar\r\n", &err));
1061 EXPECT_TRUE(parser.ParseTest(
1062 "pool link_pool\r\n"
1063 " depth = 15\r\n\r\n"
1064 "rule xyz\r\n"
1065 " command = something$expand \r\n"
1066 " description = YAY!\r\n",
1067 &err));
1068}
1069
1070TEST_F(ParserTest, DyndepNotSpecified) {
1071 ASSERT_NO_FATAL_FAILURE(AssertParse(
1072"rule cat\n"
1073" command = cat $in > $out\n"
1074"build result: cat in\n"));
1075 Edge* edge = state.GetNode("result", 0)->in_edge();
1076 ASSERT_FALSE(edge->dyndep_);
1077}
1078
1079TEST_F(ParserTest, DyndepNotInput) {
1080 State lstate;
1081 ManifestParser parser(&lstate, NULL);
1082 string err;
1083 EXPECT_FALSE(parser.ParseTest(
1084"rule touch\n"
1085" command = touch $out\n"
1086"build result: touch\n"
1087" dyndep = notin\n",
1088 &err));
1089 EXPECT_EQ("input:5: dyndep 'notin' is not an input\n", err);
1090}
1091
1092TEST_F(ParserTest, DyndepExplicitInput) {
1093 ASSERT_NO_FATAL_FAILURE(AssertParse(
1094"rule cat\n"
1095" command = cat $in > $out\n"
1096"build result: cat in\n"
1097" dyndep = in\n"));
1098 Edge* edge = state.GetNode("result", 0)->in_edge();
1099 ASSERT_TRUE(edge->dyndep_);
1100 EXPECT_TRUE(edge->dyndep_->dyndep_pending());
1101 EXPECT_EQ(edge->dyndep_->path(), "in");
1102}
1103
1104TEST_F(ParserTest, DyndepImplicitInput) {
1105 ASSERT_NO_FATAL_FAILURE(AssertParse(
1106"rule cat\n"
1107" command = cat $in > $out\n"
1108"build result: cat in | dd\n"
1109" dyndep = dd\n"));
1110 Edge* edge = state.GetNode("result", 0)->in_edge();
1111 ASSERT_TRUE(edge->dyndep_);
1112 EXPECT_TRUE(edge->dyndep_->dyndep_pending());
1113 EXPECT_EQ(edge->dyndep_->path(), "dd");
1114}
1115
1116TEST_F(ParserTest, DyndepOrderOnlyInput) {
1117 ASSERT_NO_FATAL_FAILURE(AssertParse(
1118"rule cat\n"
1119" command = cat $in > $out\n"
1120"build result: cat in || dd\n"
1121" dyndep = dd\n"));
1122 Edge* edge = state.GetNode("result", 0)->in_edge();
1123 ASSERT_TRUE(edge->dyndep_);
1124 EXPECT_TRUE(edge->dyndep_->dyndep_pending());
1125 EXPECT_EQ(edge->dyndep_->path(), "dd");
1126}
1127
1128TEST_F(ParserTest, DyndepRuleInput) {
1129 ASSERT_NO_FATAL_FAILURE(AssertParse(
1130"rule cat\n"
1131" command = cat $in > $out\n"
1132" dyndep = $in\n"
1133"build result: cat in\n"));
1134 Edge* edge = state.GetNode("result", 0)->in_edge();
1135 ASSERT_TRUE(edge->dyndep_);
1136 EXPECT_TRUE(edge->dyndep_->dyndep_pending());
1137 EXPECT_EQ(edge->dyndep_->path(), "in");
1138}
@ kPhonyCycleActionError
TEST_F(ParserTest, Empty)
Definition hash_map.h:26
An edge in the dependency graph; links between Nodes using Rules.
Definition graph.h:175
std::vector< Node * > outputs_
Definition graph.h:217
Node * dyndep_
Definition graph.h:219
bool is_order_only(size_t index)
Definition graph.h:249
bool GetBindingBool(const std::string &key) const
Definition graph.cc:516
bool is_implicit(size_t index)
Definition graph.h:245
bool is_implicit_out(size_t index) const
Definition graph.h:259
std::string EvaluateCommand(bool incl_rsp_file=false) const
Expand all variables in a command and return it as a string.
Definition graph.cc:501
std::vector< Node * > validations_
Definition graph.h:218
std::vector< Node * > inputs_
Definition graph.h:216
PhonyCycleAction phony_cycle_action_
Parses .ninja files.
bool ParseTest(const std::string &input, std::string *err)
Parse a text string of input. Used by tests.
Information about a node in the dependency graph: the file, whether it's dirty, mtime,...
Definition graph.h:42
const std::string & path() const
Definition graph.h:82
Edge * in_edge() const
Definition graph.h:100
bool dyndep_pending() const
Definition graph.h:97
uint64_t slash_bits() const
Definition graph.h:89
VirtualFileSystem fs_
void AssertParse(const char *input)
bool Load(const std::string &filename, std::string *err, Lexer *parent=NULL)
Load and parse a file.
Definition parser.cc:22
Global state (file status) for a single run.
Definition state.h:95
An implementation of DiskInterface that uses an in-memory representation of disk state.
Definition test.h:51
void AssertParse(State *state, const char *input, ManifestParserOptions opts)
Definition test.cc:100
void VerifyGraph(const State &state)
Definition test.cc:113