1 // Copyright 2015 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 "dyndep_parser.h"
16
17 #include <map>
18 #include <vector>
19
20 #include "dyndep.h"
21 #include "graph.h"
22 #include "state.h"
23 #include "test.h"
24
25 struct DyndepParserTest : public testing::Test {
AssertParseDyndepParserTest26 void AssertParse(const char* input) {
27 DyndepParser parser(&state_, &fs_, &dyndep_file_);
28 string err;
29 EXPECT_TRUE(parser.ParseTest(input, &err));
30 ASSERT_EQ("", err);
31 }
32
SetUpDyndepParserTest33 virtual void SetUp() {
34 ::AssertParse(&state_,
35 "rule touch\n"
36 " command = touch $out\n"
37 "build out otherout: touch\n");
38 }
39
40 State state_;
41 VirtualFileSystem fs_;
42 DyndepFile dyndep_file_;
43 };
44
TEST_F(DyndepParserTest,Empty)45 TEST_F(DyndepParserTest, Empty) {
46 const char kInput[] =
47 "";
48 DyndepParser parser(&state_, &fs_, &dyndep_file_);
49 string err;
50 EXPECT_FALSE(parser.ParseTest(kInput, &err));
51 EXPECT_EQ("input:1: expected 'ninja_dyndep_version = ...'\n", err);
52 }
53
TEST_F(DyndepParserTest,Version1)54 TEST_F(DyndepParserTest, Version1) {
55 ASSERT_NO_FATAL_FAILURE(AssertParse(
56 "ninja_dyndep_version = 1\n"));
57 }
58
TEST_F(DyndepParserTest,Version1Extra)59 TEST_F(DyndepParserTest, Version1Extra) {
60 ASSERT_NO_FATAL_FAILURE(AssertParse(
61 "ninja_dyndep_version = 1-extra\n"));
62 }
63
TEST_F(DyndepParserTest,Version1_0)64 TEST_F(DyndepParserTest, Version1_0) {
65 ASSERT_NO_FATAL_FAILURE(AssertParse(
66 "ninja_dyndep_version = 1.0\n"));
67 }
68
TEST_F(DyndepParserTest,Version1_0Extra)69 TEST_F(DyndepParserTest, Version1_0Extra) {
70 ASSERT_NO_FATAL_FAILURE(AssertParse(
71 "ninja_dyndep_version = 1.0-extra\n"));
72 }
73
TEST_F(DyndepParserTest,CommentVersion)74 TEST_F(DyndepParserTest, CommentVersion) {
75 ASSERT_NO_FATAL_FAILURE(AssertParse(
76 "# comment\n"
77 "ninja_dyndep_version = 1\n"));
78 }
79
TEST_F(DyndepParserTest,BlankLineVersion)80 TEST_F(DyndepParserTest, BlankLineVersion) {
81 ASSERT_NO_FATAL_FAILURE(AssertParse(
82 "\n"
83 "ninja_dyndep_version = 1\n"));
84 }
85
TEST_F(DyndepParserTest,VersionCRLF)86 TEST_F(DyndepParserTest, VersionCRLF) {
87 ASSERT_NO_FATAL_FAILURE(AssertParse(
88 "ninja_dyndep_version = 1\r\n"));
89 }
90
TEST_F(DyndepParserTest,CommentVersionCRLF)91 TEST_F(DyndepParserTest, CommentVersionCRLF) {
92 ASSERT_NO_FATAL_FAILURE(AssertParse(
93 "# comment\r\n"
94 "ninja_dyndep_version = 1\r\n"));
95 }
96
TEST_F(DyndepParserTest,BlankLineVersionCRLF)97 TEST_F(DyndepParserTest, BlankLineVersionCRLF) {
98 ASSERT_NO_FATAL_FAILURE(AssertParse(
99 "\r\n"
100 "ninja_dyndep_version = 1\r\n"));
101 }
102
TEST_F(DyndepParserTest,VersionUnexpectedEOF)103 TEST_F(DyndepParserTest, VersionUnexpectedEOF) {
104 const char kInput[] =
105 "ninja_dyndep_version = 1.0";
106 DyndepParser parser(&state_, &fs_, &dyndep_file_);
107 string err;
108 EXPECT_FALSE(parser.ParseTest(kInput, &err));
109 EXPECT_EQ("input:1: unexpected EOF\n"
110 "ninja_dyndep_version = 1.0\n"
111 " ^ near here", err);
112 }
113
TEST_F(DyndepParserTest,UnsupportedVersion0)114 TEST_F(DyndepParserTest, UnsupportedVersion0) {
115 const char kInput[] =
116 "ninja_dyndep_version = 0\n";
117 DyndepParser parser(&state_, &fs_, &dyndep_file_);
118 string err;
119 EXPECT_FALSE(parser.ParseTest(kInput, &err));
120 EXPECT_EQ("input:1: unsupported 'ninja_dyndep_version = 0'\n"
121 "ninja_dyndep_version = 0\n"
122 " ^ near here", err);
123 }
124
TEST_F(DyndepParserTest,UnsupportedVersion1_1)125 TEST_F(DyndepParserTest, UnsupportedVersion1_1) {
126 const char kInput[] =
127 "ninja_dyndep_version = 1.1\n";
128 DyndepParser parser(&state_, &fs_, &dyndep_file_);
129 string err;
130 EXPECT_FALSE(parser.ParseTest(kInput, &err));
131 EXPECT_EQ("input:1: unsupported 'ninja_dyndep_version = 1.1'\n"
132 "ninja_dyndep_version = 1.1\n"
133 " ^ near here", err);
134 }
135
TEST_F(DyndepParserTest,DuplicateVersion)136 TEST_F(DyndepParserTest, DuplicateVersion) {
137 const char kInput[] =
138 "ninja_dyndep_version = 1\n"
139 "ninja_dyndep_version = 1\n";
140 DyndepParser parser(&state_, &fs_, &dyndep_file_);
141 string err;
142 EXPECT_FALSE(parser.ParseTest(kInput, &err));
143 EXPECT_EQ("input:2: unexpected identifier\n", err);
144 }
145
TEST_F(DyndepParserTest,MissingVersionOtherVar)146 TEST_F(DyndepParserTest, MissingVersionOtherVar) {
147 const char kInput[] =
148 "not_ninja_dyndep_version = 1\n";
149 DyndepParser parser(&state_, &fs_, &dyndep_file_);
150 string err;
151 EXPECT_FALSE(parser.ParseTest(kInput, &err));
152 EXPECT_EQ("input:1: expected 'ninja_dyndep_version = ...'\n"
153 "not_ninja_dyndep_version = 1\n"
154 " ^ near here", err);
155 }
156
TEST_F(DyndepParserTest,MissingVersionBuild)157 TEST_F(DyndepParserTest, MissingVersionBuild) {
158 const char kInput[] =
159 "build out: dyndep\n";
160 DyndepParser parser(&state_, &fs_, &dyndep_file_);
161 string err;
162 EXPECT_FALSE(parser.ParseTest(kInput, &err));
163 EXPECT_EQ("input:1: expected 'ninja_dyndep_version = ...'\n", err);
164 }
165
TEST_F(DyndepParserTest,UnexpectedEqual)166 TEST_F(DyndepParserTest, UnexpectedEqual) {
167 const char kInput[] =
168 "= 1\n";
169 DyndepParser parser(&state_, &fs_, &dyndep_file_);
170 string err;
171 EXPECT_FALSE(parser.ParseTest(kInput, &err));
172 EXPECT_EQ("input:1: unexpected '='\n", err);
173 }
174
TEST_F(DyndepParserTest,UnexpectedIndent)175 TEST_F(DyndepParserTest, UnexpectedIndent) {
176 const char kInput[] =
177 " = 1\n";
178 DyndepParser parser(&state_, &fs_, &dyndep_file_);
179 string err;
180 EXPECT_FALSE(parser.ParseTest(kInput, &err));
181 EXPECT_EQ("input:1: unexpected indent\n", err);
182 }
183
TEST_F(DyndepParserTest,OutDuplicate)184 TEST_F(DyndepParserTest, OutDuplicate) {
185 const char kInput[] =
186 "ninja_dyndep_version = 1\n"
187 "build out: dyndep\n"
188 "build out: dyndep\n";
189 DyndepParser parser(&state_, &fs_, &dyndep_file_);
190 string err;
191 EXPECT_FALSE(parser.ParseTest(kInput, &err));
192 EXPECT_EQ("input:3: multiple statements for 'out'\n"
193 "build out: dyndep\n"
194 " ^ near here", err);
195 }
196
TEST_F(DyndepParserTest,OutDuplicateThroughOther)197 TEST_F(DyndepParserTest, OutDuplicateThroughOther) {
198 const char kInput[] =
199 "ninja_dyndep_version = 1\n"
200 "build out: dyndep\n"
201 "build otherout: dyndep\n";
202 DyndepParser parser(&state_, &fs_, &dyndep_file_);
203 string err;
204 EXPECT_FALSE(parser.ParseTest(kInput, &err));
205 EXPECT_EQ("input:3: multiple statements for 'otherout'\n"
206 "build otherout: dyndep\n"
207 " ^ near here", err);
208 }
209
TEST_F(DyndepParserTest,NoOutEOF)210 TEST_F(DyndepParserTest, NoOutEOF) {
211 const char kInput[] =
212 "ninja_dyndep_version = 1\n"
213 "build";
214 DyndepParser parser(&state_, &fs_, &dyndep_file_);
215 string err;
216 EXPECT_FALSE(parser.ParseTest(kInput, &err));
217 EXPECT_EQ("input:2: unexpected EOF\n"
218 "build\n"
219 " ^ near here", err);
220 }
221
TEST_F(DyndepParserTest,NoOutColon)222 TEST_F(DyndepParserTest, NoOutColon) {
223 const char kInput[] =
224 "ninja_dyndep_version = 1\n"
225 "build :\n";
226 DyndepParser parser(&state_, &fs_, &dyndep_file_);
227 string err;
228 EXPECT_FALSE(parser.ParseTest(kInput, &err));
229 EXPECT_EQ("input:2: expected path\n"
230 "build :\n"
231 " ^ near here", err);
232 }
233
TEST_F(DyndepParserTest,OutNoStatement)234 TEST_F(DyndepParserTest, OutNoStatement) {
235 const char kInput[] =
236 "ninja_dyndep_version = 1\n"
237 "build missing: dyndep\n";
238 DyndepParser parser(&state_, &fs_, &dyndep_file_);
239 string err;
240 EXPECT_FALSE(parser.ParseTest(kInput, &err));
241 EXPECT_EQ("input:2: no build statement exists for 'missing'\n"
242 "build missing: dyndep\n"
243 " ^ near here", err);
244 }
245
TEST_F(DyndepParserTest,OutEOF)246 TEST_F(DyndepParserTest, OutEOF) {
247 const char kInput[] =
248 "ninja_dyndep_version = 1\n"
249 "build out";
250 DyndepParser parser(&state_, &fs_, &dyndep_file_);
251 string err;
252 EXPECT_FALSE(parser.ParseTest(kInput, &err));
253 EXPECT_EQ("input:2: unexpected EOF\n"
254 "build out\n"
255 " ^ near here", err);
256 }
257
TEST_F(DyndepParserTest,OutNoRule)258 TEST_F(DyndepParserTest, OutNoRule) {
259 const char kInput[] =
260 "ninja_dyndep_version = 1\n"
261 "build out:";
262 DyndepParser parser(&state_, &fs_, &dyndep_file_);
263 string err;
264 EXPECT_FALSE(parser.ParseTest(kInput, &err));
265 EXPECT_EQ("input:2: expected build command name 'dyndep'\n"
266 "build out:\n"
267 " ^ near here", err);
268 }
269
TEST_F(DyndepParserTest,OutBadRule)270 TEST_F(DyndepParserTest, OutBadRule) {
271 const char kInput[] =
272 "ninja_dyndep_version = 1\n"
273 "build out: touch";
274 DyndepParser parser(&state_, &fs_, &dyndep_file_);
275 string err;
276 EXPECT_FALSE(parser.ParseTest(kInput, &err));
277 EXPECT_EQ("input:2: expected build command name 'dyndep'\n"
278 "build out: touch\n"
279 " ^ near here", err);
280 }
281
TEST_F(DyndepParserTest,BuildEOF)282 TEST_F(DyndepParserTest, BuildEOF) {
283 const char kInput[] =
284 "ninja_dyndep_version = 1\n"
285 "build out: dyndep";
286 DyndepParser parser(&state_, &fs_, &dyndep_file_);
287 string err;
288 EXPECT_FALSE(parser.ParseTest(kInput, &err));
289 EXPECT_EQ("input:2: unexpected EOF\n"
290 "build out: dyndep\n"
291 " ^ near here", err);
292 }
293
TEST_F(DyndepParserTest,ExplicitOut)294 TEST_F(DyndepParserTest, ExplicitOut) {
295 const char kInput[] =
296 "ninja_dyndep_version = 1\n"
297 "build out exp: dyndep\n";
298 DyndepParser parser(&state_, &fs_, &dyndep_file_);
299 string err;
300 EXPECT_FALSE(parser.ParseTest(kInput, &err));
301 EXPECT_EQ("input:2: explicit outputs not supported\n"
302 "build out exp: dyndep\n"
303 " ^ near here", err);
304 }
305
TEST_F(DyndepParserTest,ExplicitIn)306 TEST_F(DyndepParserTest, ExplicitIn) {
307 const char kInput[] =
308 "ninja_dyndep_version = 1\n"
309 "build out: dyndep exp\n";
310 DyndepParser parser(&state_, &fs_, &dyndep_file_);
311 string err;
312 EXPECT_FALSE(parser.ParseTest(kInput, &err));
313 EXPECT_EQ("input:2: explicit inputs not supported\n"
314 "build out: dyndep exp\n"
315 " ^ near here", err);
316 }
317
TEST_F(DyndepParserTest,OrderOnlyIn)318 TEST_F(DyndepParserTest, OrderOnlyIn) {
319 const char kInput[] =
320 "ninja_dyndep_version = 1\n"
321 "build out: dyndep ||\n";
322 DyndepParser parser(&state_, &fs_, &dyndep_file_);
323 string err;
324 EXPECT_FALSE(parser.ParseTest(kInput, &err));
325 EXPECT_EQ("input:2: order-only inputs not supported\n"
326 "build out: dyndep ||\n"
327 " ^ near here", err);
328 }
329
TEST_F(DyndepParserTest,BadBinding)330 TEST_F(DyndepParserTest, BadBinding) {
331 const char kInput[] =
332 "ninja_dyndep_version = 1\n"
333 "build out: dyndep\n"
334 " not_restat = 1\n";
335 DyndepParser parser(&state_, &fs_, &dyndep_file_);
336 string err;
337 EXPECT_FALSE(parser.ParseTest(kInput, &err));
338 EXPECT_EQ("input:3: binding is not 'restat'\n"
339 " not_restat = 1\n"
340 " ^ near here", err);
341 }
342
TEST_F(DyndepParserTest,RestatTwice)343 TEST_F(DyndepParserTest, RestatTwice) {
344 const char kInput[] =
345 "ninja_dyndep_version = 1\n"
346 "build out: dyndep\n"
347 " restat = 1\n"
348 " restat = 1\n";
349 DyndepParser parser(&state_, &fs_, &dyndep_file_);
350 string err;
351 EXPECT_FALSE(parser.ParseTest(kInput, &err));
352 EXPECT_EQ("input:4: unexpected indent\n", err);
353 }
354
TEST_F(DyndepParserTest,NoImplicit)355 TEST_F(DyndepParserTest, NoImplicit) {
356 ASSERT_NO_FATAL_FAILURE(AssertParse(
357 "ninja_dyndep_version = 1\n"
358 "build out: dyndep\n"));
359
360 EXPECT_EQ(1u, dyndep_file_.size());
361 DyndepFile::iterator i = dyndep_file_.find(state_.edges_[0]);
362 ASSERT_NE(i, dyndep_file_.end());
363 EXPECT_EQ(false, i->second.restat_);
364 EXPECT_EQ(0u, i->second.implicit_outputs_.size());
365 EXPECT_EQ(0u, i->second.implicit_inputs_.size());
366 }
367
TEST_F(DyndepParserTest,EmptyImplicit)368 TEST_F(DyndepParserTest, EmptyImplicit) {
369 ASSERT_NO_FATAL_FAILURE(AssertParse(
370 "ninja_dyndep_version = 1\n"
371 "build out | : dyndep |\n"));
372
373 EXPECT_EQ(1u, dyndep_file_.size());
374 DyndepFile::iterator i = dyndep_file_.find(state_.edges_[0]);
375 ASSERT_NE(i, dyndep_file_.end());
376 EXPECT_EQ(false, i->second.restat_);
377 EXPECT_EQ(0u, i->second.implicit_outputs_.size());
378 EXPECT_EQ(0u, i->second.implicit_inputs_.size());
379 }
380
TEST_F(DyndepParserTest,ImplicitIn)381 TEST_F(DyndepParserTest, ImplicitIn) {
382 ASSERT_NO_FATAL_FAILURE(AssertParse(
383 "ninja_dyndep_version = 1\n"
384 "build out: dyndep | impin\n"));
385
386 EXPECT_EQ(1u, dyndep_file_.size());
387 DyndepFile::iterator i = dyndep_file_.find(state_.edges_[0]);
388 ASSERT_NE(i, dyndep_file_.end());
389 EXPECT_EQ(false, i->second.restat_);
390 EXPECT_EQ(0u, i->second.implicit_outputs_.size());
391 ASSERT_EQ(1u, i->second.implicit_inputs_.size());
392 EXPECT_EQ("impin", i->second.implicit_inputs_[0]->path());
393 }
394
TEST_F(DyndepParserTest,ImplicitIns)395 TEST_F(DyndepParserTest, ImplicitIns) {
396 ASSERT_NO_FATAL_FAILURE(AssertParse(
397 "ninja_dyndep_version = 1\n"
398 "build out: dyndep | impin1 impin2\n"));
399
400 EXPECT_EQ(1u, dyndep_file_.size());
401 DyndepFile::iterator i = dyndep_file_.find(state_.edges_[0]);
402 ASSERT_NE(i, dyndep_file_.end());
403 EXPECT_EQ(false, i->second.restat_);
404 EXPECT_EQ(0u, i->second.implicit_outputs_.size());
405 ASSERT_EQ(2u, i->second.implicit_inputs_.size());
406 EXPECT_EQ("impin1", i->second.implicit_inputs_[0]->path());
407 EXPECT_EQ("impin2", i->second.implicit_inputs_[1]->path());
408 }
409
TEST_F(DyndepParserTest,ImplicitOut)410 TEST_F(DyndepParserTest, ImplicitOut) {
411 ASSERT_NO_FATAL_FAILURE(AssertParse(
412 "ninja_dyndep_version = 1\n"
413 "build out | impout: dyndep\n"));
414
415 EXPECT_EQ(1u, dyndep_file_.size());
416 DyndepFile::iterator i = dyndep_file_.find(state_.edges_[0]);
417 ASSERT_NE(i, dyndep_file_.end());
418 EXPECT_EQ(false, i->second.restat_);
419 ASSERT_EQ(1u, i->second.implicit_outputs_.size());
420 EXPECT_EQ("impout", i->second.implicit_outputs_[0]->path());
421 EXPECT_EQ(0u, i->second.implicit_inputs_.size());
422 }
423
TEST_F(DyndepParserTest,ImplicitOuts)424 TEST_F(DyndepParserTest, ImplicitOuts) {
425 ASSERT_NO_FATAL_FAILURE(AssertParse(
426 "ninja_dyndep_version = 1\n"
427 "build out | impout1 impout2 : dyndep\n"));
428
429 EXPECT_EQ(1u, dyndep_file_.size());
430 DyndepFile::iterator i = dyndep_file_.find(state_.edges_[0]);
431 ASSERT_NE(i, dyndep_file_.end());
432 EXPECT_EQ(false, i->second.restat_);
433 ASSERT_EQ(2u, i->second.implicit_outputs_.size());
434 EXPECT_EQ("impout1", i->second.implicit_outputs_[0]->path());
435 EXPECT_EQ("impout2", i->second.implicit_outputs_[1]->path());
436 EXPECT_EQ(0u, i->second.implicit_inputs_.size());
437 }
438
TEST_F(DyndepParserTest,ImplicitInsAndOuts)439 TEST_F(DyndepParserTest, ImplicitInsAndOuts) {
440 ASSERT_NO_FATAL_FAILURE(AssertParse(
441 "ninja_dyndep_version = 1\n"
442 "build out | impout1 impout2: dyndep | impin1 impin2\n"));
443
444 EXPECT_EQ(1u, dyndep_file_.size());
445 DyndepFile::iterator i = dyndep_file_.find(state_.edges_[0]);
446 ASSERT_NE(i, dyndep_file_.end());
447 EXPECT_EQ(false, i->second.restat_);
448 ASSERT_EQ(2u, i->second.implicit_outputs_.size());
449 EXPECT_EQ("impout1", i->second.implicit_outputs_[0]->path());
450 EXPECT_EQ("impout2", i->second.implicit_outputs_[1]->path());
451 ASSERT_EQ(2u, i->second.implicit_inputs_.size());
452 EXPECT_EQ("impin1", i->second.implicit_inputs_[0]->path());
453 EXPECT_EQ("impin2", i->second.implicit_inputs_[1]->path());
454 }
455
TEST_F(DyndepParserTest,Restat)456 TEST_F(DyndepParserTest, Restat) {
457 ASSERT_NO_FATAL_FAILURE(AssertParse(
458 "ninja_dyndep_version = 1\n"
459 "build out: dyndep\n"
460 " restat = 1\n"));
461
462 EXPECT_EQ(1u, dyndep_file_.size());
463 DyndepFile::iterator i = dyndep_file_.find(state_.edges_[0]);
464 ASSERT_NE(i, dyndep_file_.end());
465 EXPECT_EQ(true, i->second.restat_);
466 EXPECT_EQ(0u, i->second.implicit_outputs_.size());
467 EXPECT_EQ(0u, i->second.implicit_inputs_.size());
468 }
469
TEST_F(DyndepParserTest,OtherOutput)470 TEST_F(DyndepParserTest, OtherOutput) {
471 ASSERT_NO_FATAL_FAILURE(AssertParse(
472 "ninja_dyndep_version = 1\n"
473 "build otherout: dyndep\n"));
474
475 EXPECT_EQ(1u, dyndep_file_.size());
476 DyndepFile::iterator i = dyndep_file_.find(state_.edges_[0]);
477 ASSERT_NE(i, dyndep_file_.end());
478 EXPECT_EQ(false, i->second.restat_);
479 EXPECT_EQ(0u, i->second.implicit_outputs_.size());
480 EXPECT_EQ(0u, i->second.implicit_inputs_.size());
481 }
482
TEST_F(DyndepParserTest,MultipleEdges)483 TEST_F(DyndepParserTest, MultipleEdges) {
484 ::AssertParse(&state_,
485 "build out2: touch\n");
486 ASSERT_EQ(2u, state_.edges_.size());
487 ASSERT_EQ(1u, state_.edges_[1]->outputs_.size());
488 EXPECT_EQ("out2", state_.edges_[1]->outputs_[0]->path());
489 EXPECT_EQ(0u, state_.edges_[0]->inputs_.size());
490
491 ASSERT_NO_FATAL_FAILURE(AssertParse(
492 "ninja_dyndep_version = 1\n"
493 "build out: dyndep\n"
494 "build out2: dyndep\n"
495 " restat = 1\n"));
496
497 EXPECT_EQ(2u, dyndep_file_.size());
498 {
499 DyndepFile::iterator i = dyndep_file_.find(state_.edges_[0]);
500 ASSERT_NE(i, dyndep_file_.end());
501 EXPECT_EQ(false, i->second.restat_);
502 EXPECT_EQ(0u, i->second.implicit_outputs_.size());
503 EXPECT_EQ(0u, i->second.implicit_inputs_.size());
504 }
505 {
506 DyndepFile::iterator i = dyndep_file_.find(state_.edges_[1]);
507 ASSERT_NE(i, dyndep_file_.end());
508 EXPECT_EQ(true, i->second.restat_);
509 EXPECT_EQ(0u, i->second.implicit_outputs_.size());
510 EXPECT_EQ(0u, i->second.implicit_inputs_.size());
511 }
512 }
513