Ninja
depfile_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 "depfile_parser.h"
16 
17 #include "test.h"
18 
19 using namespace std;
20 
21 struct DepfileParserTest : public testing::Test {
22  bool Parse(const char* input, string* err);
23 
25  string input_;
26 };
27 
28 bool DepfileParserTest::Parse(const char* input, string* err) {
29  input_ = input;
30  return parser_.Parse(&input_, err);
31 }
32 
34  string err;
35  EXPECT_TRUE(Parse(
36 "build/ninja.o: ninja.cc ninja.h eval_env.h manifest_parser.h\n",
37  &err));
38  ASSERT_EQ("", err);
39  ASSERT_EQ(1u, parser_.outs_.size());
40  EXPECT_EQ("build/ninja.o", parser_.outs_[0].AsString());
41  EXPECT_EQ(4u, parser_.ins_.size());
42 }
43 
44 TEST_F(DepfileParserTest, EarlyNewlineAndWhitespace) {
45  string err;
46  EXPECT_TRUE(Parse(
47 " \\\n"
48 " out: in\n",
49  &err));
50  ASSERT_EQ("", err);
51 }
52 
53 TEST_F(DepfileParserTest, Continuation) {
54  string err;
55  EXPECT_TRUE(Parse(
56 "foo.o: \\\n"
57 " bar.h baz.h\n",
58  &err));
59  ASSERT_EQ("", err);
60  ASSERT_EQ(1u, parser_.outs_.size());
61  EXPECT_EQ("foo.o", parser_.outs_[0].AsString());
62  EXPECT_EQ(2u, parser_.ins_.size());
63 }
64 
65 TEST_F(DepfileParserTest, WindowsDrivePaths) {
66  string err;
67  EXPECT_TRUE(Parse("foo.o: //?/c:/bar.h\n", &err));
68  ASSERT_EQ("", err);
69  ASSERT_EQ(1u, parser_.outs_.size());
70  EXPECT_EQ("foo.o", parser_.outs_[0].AsString());
71  EXPECT_EQ(1u, parser_.ins_.size());
72  EXPECT_EQ("//?/c:/bar.h", parser_.ins_[0].AsString());
73 }
74 
75 TEST_F(DepfileParserTest, AmpersandsAndQuotes) {
76  string err;
77  EXPECT_TRUE(Parse("foo&bar.o foo'bar.o foo\"bar.o: foo&bar.h foo'bar.h foo\"bar.h\n", &err));
78  ASSERT_EQ("", err);
79  ASSERT_EQ(3u, parser_.outs_.size());
80  EXPECT_EQ("foo&bar.o", parser_.outs_[0].AsString());
81  EXPECT_EQ("foo'bar.o", parser_.outs_[1].AsString());
82  EXPECT_EQ("foo\"bar.o", parser_.outs_[2].AsString());
83  EXPECT_EQ(3u, parser_.ins_.size());
84  EXPECT_EQ("foo&bar.h", parser_.ins_[0].AsString());
85  EXPECT_EQ("foo'bar.h", parser_.ins_[1].AsString());
86  EXPECT_EQ("foo\"bar.h", parser_.ins_[2].AsString());
87 }
88 
89 TEST_F(DepfileParserTest, CarriageReturnContinuation) {
90  string err;
91  EXPECT_TRUE(Parse(
92 "foo.o: \\\r\n"
93 " bar.h baz.h\r\n",
94  &err));
95  ASSERT_EQ("", err);
96  ASSERT_EQ(1u, parser_.outs_.size());
97  EXPECT_EQ("foo.o", parser_.outs_[0].AsString());
98  EXPECT_EQ(2u, parser_.ins_.size());
99 }
100 
101 TEST_F(DepfileParserTest, BackSlashes) {
102  string err;
103  EXPECT_TRUE(Parse(
104 "Project\\Dir\\Build\\Release8\\Foo\\Foo.res : \\\n"
105 " Dir\\Library\\Foo.rc \\\n"
106 " Dir\\Library\\Version\\Bar.h \\\n"
107 " Dir\\Library\\Foo.ico \\\n"
108 " Project\\Thing\\Bar.tlb \\\n",
109  &err));
110  ASSERT_EQ("", err);
111  ASSERT_EQ(1u, parser_.outs_.size());
112  EXPECT_EQ("Project\\Dir\\Build\\Release8\\Foo\\Foo.res",
113  parser_.outs_[0].AsString());
114  EXPECT_EQ(4u, parser_.ins_.size());
115 }
116 
118  string err;
119  EXPECT_TRUE(Parse(
120 "a\\ bc\\ def: a\\ b c d",
121  &err));
122  ASSERT_EQ("", err);
123  ASSERT_EQ(1u, parser_.outs_.size());
124  EXPECT_EQ("a bc def",
125  parser_.outs_[0].AsString());
126  ASSERT_EQ(3u, parser_.ins_.size());
127  EXPECT_EQ("a b",
128  parser_.ins_[0].AsString());
129  EXPECT_EQ("c",
130  parser_.ins_[1].AsString());
131  EXPECT_EQ("d",
132  parser_.ins_[2].AsString());
133 }
134 
135 TEST_F(DepfileParserTest, MultipleBackslashes) {
136  // Successive 2N+1 backslashes followed by space (' ') are replaced by N >= 0
137  // backslashes and the space. A single backslash before hash sign is removed.
138  // Other backslashes remain untouched (including 2N backslashes followed by
139  // space).
140  string err;
141  EXPECT_TRUE(Parse(
142 "a\\ b\\#c.h: \\\\\\\\\\ \\\\\\\\ \\\\share\\info\\\\#1",
143  &err));
144  ASSERT_EQ("", err);
145  ASSERT_EQ(1u, parser_.outs_.size());
146  EXPECT_EQ("a b#c.h",
147  parser_.outs_[0].AsString());
148  ASSERT_EQ(3u, parser_.ins_.size());
149  EXPECT_EQ("\\\\ ",
150  parser_.ins_[0].AsString());
151  EXPECT_EQ("\\\\\\\\",
152  parser_.ins_[1].AsString());
153  EXPECT_EQ("\\\\share\\info\\#1",
154  parser_.ins_[2].AsString());
155 }
156 
158  // Put backslashes before a variety of characters, see which ones make
159  // it through.
160  string err;
161  EXPECT_TRUE(Parse(
162 "\\!\\@\\#$$\\%\\^\\&\\[\\]\\\\:",
163  &err));
164  ASSERT_EQ("", err);
165  ASSERT_EQ(1u, parser_.outs_.size());
166  EXPECT_EQ("\\!\\@#$\\%\\^\\&\\[\\]\\\\",
167  parser_.outs_[0].AsString());
168  ASSERT_EQ(0u, parser_.ins_.size());
169 }
170 
171 TEST_F(DepfileParserTest, EscapedColons)
172 {
173  std::string err;
174  // Tests for correct parsing of depfiles produced on Windows
175  // by both Clang, GCC pre 10 and GCC 10
176  EXPECT_TRUE(Parse(
177 "c\\:\\gcc\\x86_64-w64-mingw32\\include\\stddef.o: \\\n"
178 " c:\\gcc\\x86_64-w64-mingw32\\include\\stddef.h \n",
179  &err));
180  ASSERT_EQ("", err);
181  ASSERT_EQ(1u, parser_.outs_.size());
182  EXPECT_EQ("c:\\gcc\\x86_64-w64-mingw32\\include\\stddef.o",
183  parser_.outs_[0].AsString());
184  ASSERT_EQ(1u, parser_.ins_.size());
185  EXPECT_EQ("c:\\gcc\\x86_64-w64-mingw32\\include\\stddef.h",
186  parser_.ins_[0].AsString());
187 }
188 
189 TEST_F(DepfileParserTest, EscapedTargetColon)
190 {
191  std::string err;
192  EXPECT_TRUE(Parse(
193 "foo1\\: x\n"
194 "foo1\\:\n"
195 "foo1\\:\r\n"
196 "foo1\\:\t\n"
197 "foo1\\:",
198  &err));
199  ASSERT_EQ("", err);
200  ASSERT_EQ(1u, parser_.outs_.size());
201  EXPECT_EQ("foo1\\", parser_.outs_[0].AsString());
202  ASSERT_EQ(1u, parser_.ins_.size());
203  EXPECT_EQ("x", parser_.ins_[0].AsString());
204 }
205 
206 TEST_F(DepfileParserTest, SpecialChars) {
207  // See filenames like istreambuf.iterator_op!= in
208  // https://github.com/google/libcxx/tree/master/test/iterators/stream.iterators/istreambuf.iterator/
209  string err;
210  EXPECT_TRUE(Parse(
211 "C:/Program\\ Files\\ (x86)/Microsoft\\ crtdefs.h: \\\n"
212 " en@quot.header~ t+t-x!=1 \\\n"
213 " openldap/slapd.d/cn=config/cn=schema/cn={0}core.ldif\\\n"
214 " Fu\303\244ball\\\n"
215 " a[1]b@2%c",
216  &err));
217  ASSERT_EQ("", err);
218  ASSERT_EQ(1u, parser_.outs_.size());
219  EXPECT_EQ("C:/Program Files (x86)/Microsoft crtdefs.h",
220  parser_.outs_[0].AsString());
221  ASSERT_EQ(5u, parser_.ins_.size());
222  EXPECT_EQ("en@quot.header~",
223  parser_.ins_[0].AsString());
224  EXPECT_EQ("t+t-x!=1",
225  parser_.ins_[1].AsString());
226  EXPECT_EQ("openldap/slapd.d/cn=config/cn=schema/cn={0}core.ldif",
227  parser_.ins_[2].AsString());
228  EXPECT_EQ("Fu\303\244ball",
229  parser_.ins_[3].AsString());
230  EXPECT_EQ("a[1]b@2%c",
231  parser_.ins_[4].AsString());
232 }
233 
234 TEST_F(DepfileParserTest, UnifyMultipleOutputs) {
235  // check that multiple duplicate targets are properly unified
236  string err;
237  EXPECT_TRUE(Parse("foo foo: x y z", &err));
238  ASSERT_EQ(1u, parser_.outs_.size());
239  ASSERT_EQ("foo", parser_.outs_[0].AsString());
240  ASSERT_EQ(3u, parser_.ins_.size());
241  EXPECT_EQ("x", parser_.ins_[0].AsString());
242  EXPECT_EQ("y", parser_.ins_[1].AsString());
243  EXPECT_EQ("z", parser_.ins_[2].AsString());
244 }
245 
246 TEST_F(DepfileParserTest, MultipleDifferentOutputs) {
247  // check that multiple different outputs are accepted by the parser
248  string err;
249  EXPECT_TRUE(Parse("foo bar: x y z", &err));
250  ASSERT_EQ(2u, parser_.outs_.size());
251  ASSERT_EQ("foo", parser_.outs_[0].AsString());
252  ASSERT_EQ("bar", parser_.outs_[1].AsString());
253  ASSERT_EQ(3u, parser_.ins_.size());
254  EXPECT_EQ("x", parser_.ins_[0].AsString());
255  EXPECT_EQ("y", parser_.ins_[1].AsString());
256  EXPECT_EQ("z", parser_.ins_[2].AsString());
257 }
258 
259 TEST_F(DepfileParserTest, MultipleEmptyRules) {
260  string err;
261  EXPECT_TRUE(Parse("foo: x\n"
262  "foo: \n"
263  "foo:\n", &err));
264  ASSERT_EQ(1u, parser_.outs_.size());
265  ASSERT_EQ("foo", parser_.outs_[0].AsString());
266  ASSERT_EQ(1u, parser_.ins_.size());
267  EXPECT_EQ("x", parser_.ins_[0].AsString());
268 }
269 
270 TEST_F(DepfileParserTest, UnifyMultipleRulesLF) {
271  string err;
272  EXPECT_TRUE(Parse("foo: x\n"
273  "foo: y\n"
274  "foo \\\n"
275  "foo: z\n", &err));
276  ASSERT_EQ(1u, parser_.outs_.size());
277  ASSERT_EQ("foo", parser_.outs_[0].AsString());
278  ASSERT_EQ(3u, parser_.ins_.size());
279  EXPECT_EQ("x", parser_.ins_[0].AsString());
280  EXPECT_EQ("y", parser_.ins_[1].AsString());
281  EXPECT_EQ("z", parser_.ins_[2].AsString());
282 }
283 
284 TEST_F(DepfileParserTest, UnifyMultipleRulesCRLF) {
285  string err;
286  EXPECT_TRUE(Parse("foo: x\r\n"
287  "foo: y\r\n"
288  "foo \\\r\n"
289  "foo: z\r\n", &err));
290  ASSERT_EQ(1u, parser_.outs_.size());
291  ASSERT_EQ("foo", parser_.outs_[0].AsString());
292  ASSERT_EQ(3u, parser_.ins_.size());
293  EXPECT_EQ("x", parser_.ins_[0].AsString());
294  EXPECT_EQ("y", parser_.ins_[1].AsString());
295  EXPECT_EQ("z", parser_.ins_[2].AsString());
296 }
297 
298 TEST_F(DepfileParserTest, UnifyMixedRulesLF) {
299  string err;
300  EXPECT_TRUE(Parse("foo: x\\\n"
301  " y\n"
302  "foo \\\n"
303  "foo: z\n", &err));
304  ASSERT_EQ(1u, parser_.outs_.size());
305  ASSERT_EQ("foo", parser_.outs_[0].AsString());
306  ASSERT_EQ(3u, parser_.ins_.size());
307  EXPECT_EQ("x", parser_.ins_[0].AsString());
308  EXPECT_EQ("y", parser_.ins_[1].AsString());
309  EXPECT_EQ("z", parser_.ins_[2].AsString());
310 }
311 
312 TEST_F(DepfileParserTest, UnifyMixedRulesCRLF) {
313  string err;
314  EXPECT_TRUE(Parse("foo: x\\\r\n"
315  " y\r\n"
316  "foo \\\r\n"
317  "foo: z\r\n", &err));
318  ASSERT_EQ(1u, parser_.outs_.size());
319  ASSERT_EQ("foo", parser_.outs_[0].AsString());
320  ASSERT_EQ(3u, parser_.ins_.size());
321  EXPECT_EQ("x", parser_.ins_[0].AsString());
322  EXPECT_EQ("y", parser_.ins_[1].AsString());
323  EXPECT_EQ("z", parser_.ins_[2].AsString());
324 }
325 
326 TEST_F(DepfileParserTest, IndentedRulesLF) {
327  string err;
328  EXPECT_TRUE(Parse(" foo: x\n"
329  " foo: y\n"
330  " foo: z\n", &err));
331  ASSERT_EQ(1u, parser_.outs_.size());
332  ASSERT_EQ("foo", parser_.outs_[0].AsString());
333  ASSERT_EQ(3u, parser_.ins_.size());
334  EXPECT_EQ("x", parser_.ins_[0].AsString());
335  EXPECT_EQ("y", parser_.ins_[1].AsString());
336  EXPECT_EQ("z", parser_.ins_[2].AsString());
337 }
338 
339 TEST_F(DepfileParserTest, IndentedRulesCRLF) {
340  string err;
341  EXPECT_TRUE(Parse(" foo: x\r\n"
342  " foo: y\r\n"
343  " foo: z\r\n", &err));
344  ASSERT_EQ(1u, parser_.outs_.size());
345  ASSERT_EQ("foo", parser_.outs_[0].AsString());
346  ASSERT_EQ(3u, parser_.ins_.size());
347  EXPECT_EQ("x", parser_.ins_[0].AsString());
348  EXPECT_EQ("y", parser_.ins_[1].AsString());
349  EXPECT_EQ("z", parser_.ins_[2].AsString());
350 }
351 
352 TEST_F(DepfileParserTest, TolerateMP) {
353  string err;
354  EXPECT_TRUE(Parse("foo: x y z\n"
355  "x:\n"
356  "y:\n"
357  "z:\n", &err));
358  ASSERT_EQ(1u, parser_.outs_.size());
359  ASSERT_EQ("foo", parser_.outs_[0].AsString());
360  ASSERT_EQ(3u, parser_.ins_.size());
361  EXPECT_EQ("x", parser_.ins_[0].AsString());
362  EXPECT_EQ("y", parser_.ins_[1].AsString());
363  EXPECT_EQ("z", parser_.ins_[2].AsString());
364 }
365 
366 TEST_F(DepfileParserTest, MultipleRulesTolerateMP) {
367  string err;
368  EXPECT_TRUE(Parse("foo: x\n"
369  "x:\n"
370  "foo: y\n"
371  "y:\n"
372  "foo: z\n"
373  "z:\n", &err));
374  ASSERT_EQ(1u, parser_.outs_.size());
375  ASSERT_EQ("foo", parser_.outs_[0].AsString());
376  ASSERT_EQ(3u, parser_.ins_.size());
377  EXPECT_EQ("x", parser_.ins_[0].AsString());
378  EXPECT_EQ("y", parser_.ins_[1].AsString());
379  EXPECT_EQ("z", parser_.ins_[2].AsString());
380 }
381 
382 TEST_F(DepfileParserTest, MultipleRulesDifferentOutputs) {
383  // check that multiple different outputs are accepted by the parser
384  // when spread across multiple rules
385  string err;
386  EXPECT_TRUE(Parse("foo: x y\n"
387  "bar: y z\n", &err));
388  ASSERT_EQ(2u, parser_.outs_.size());
389  ASSERT_EQ("foo", parser_.outs_[0].AsString());
390  ASSERT_EQ("bar", parser_.outs_[1].AsString());
391  ASSERT_EQ(3u, parser_.ins_.size());
392  EXPECT_EQ("x", parser_.ins_[0].AsString());
393  EXPECT_EQ("y", parser_.ins_[1].AsString());
394  EXPECT_EQ("z", parser_.ins_[2].AsString());
395 }
396 
398  std::string err;
399  EXPECT_FALSE(Parse("foo: x y z\n"
400  "x: alsoin\n"
401  "y:\n"
402  "z:\n", &err));
403  ASSERT_EQ("inputs may not also have inputs", err);
404 }
405 
407  std::string err;
408  EXPECT_TRUE(Parse("", &err));
409  ASSERT_EQ(0u, parser_.outs_.size());
410  ASSERT_EQ(0u, parser_.ins_.size());
411 }
412 
413 TEST_F(DepfileParserTest, EmptyLines) {
414  std::string err;
415  EXPECT_TRUE(Parse("\n\n", &err));
416  ASSERT_EQ(0u, parser_.outs_.size());
417  ASSERT_EQ(0u, parser_.ins_.size());
418 }
419 
420 TEST_F(DepfileParserTest, MissingColon) {
421  // The file is not empty but is missing a colon separator.
422  std::string err;
423  EXPECT_FALSE(Parse("foo.o foo.c\n", &err));
424  EXPECT_EQ("expected ':' in depfile", err);
425 }
TEST_F(DepfileParserTest, Basic)
Definition: hash_map.h:26
bool Parse(const char *input, string *err)
Parser for the dependency information emitted by gcc's -M flags.