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