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
19using namespace std;
20
21struct DepfileParserTest : public testing::Test {
22 bool Parse(const char* input, string* err);
23
25 string input_;
26};
27
28bool 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
44TEST_F(DepfileParserTest, EarlyNewlineAndWhitespace) {
45 string err;
46 EXPECT_TRUE(Parse(
47" \\\n"
48" out: in\n",
49 &err));
50 ASSERT_EQ("", err);
51}
52
53TEST_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
65TEST_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
75TEST_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
89TEST_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
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
135TEST_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
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
189TEST_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
206TEST_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
234TEST_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
246TEST_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
259TEST_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
270TEST_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
284TEST_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
298TEST_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
312TEST_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
326TEST_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
339TEST_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
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
366TEST_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
382TEST_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
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
420TEST_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.