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
24 DepfileParser parser_;
25 string input_;
26};
27
28bool DepfileParserTest::Parse(const char* input, string* err) {
29 input_ = input;
30 return parser_.Parse(&input_, err);
31}
32
33TEST_F(DepfileParserTest, Basic) {
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, CarriageReturnContinuation) {
66 string err;
67 EXPECT_TRUE(Parse(
68"foo.o: \\\r\n"
69" bar.h baz.h\r\n",
70 &err));
71 ASSERT_EQ("", err);
72 ASSERT_EQ(1u, parser_.outs_.size());
73 EXPECT_EQ("foo.o", parser_.outs_[0].AsString());
74 EXPECT_EQ(2u, parser_.ins_.size());
75}
76
77TEST_F(DepfileParserTest, BackSlashes) {
78 string err;
79 EXPECT_TRUE(Parse(
80"Project\\Dir\\Build\\Release8\\Foo\\Foo.res : \\\n"
81" Dir\\Library\\Foo.rc \\\n"
82" Dir\\Library\\Version\\Bar.h \\\n"
83" Dir\\Library\\Foo.ico \\\n"
84" Project\\Thing\\Bar.tlb \\\n",
85 &err));
86 ASSERT_EQ("", err);
87 ASSERT_EQ(1u, parser_.outs_.size());
88 EXPECT_EQ("Project\\Dir\\Build\\Release8\\Foo\\Foo.res",
89 parser_.outs_[0].AsString());
90 EXPECT_EQ(4u, parser_.ins_.size());
91}
92
93TEST_F(DepfileParserTest, Spaces) {
94 string err;
95 EXPECT_TRUE(Parse(
96"a\\ bc\\ def: a\\ b c d",
97 &err));
98 ASSERT_EQ("", err);
99 ASSERT_EQ(1u, parser_.outs_.size());
100 EXPECT_EQ("a bc def",
101 parser_.outs_[0].AsString());
102 ASSERT_EQ(3u, parser_.ins_.size());
103 EXPECT_EQ("a b",
104 parser_.ins_[0].AsString());
105 EXPECT_EQ("c",
106 parser_.ins_[1].AsString());
107 EXPECT_EQ("d",
108 parser_.ins_[2].AsString());
109}
110
111TEST_F(DepfileParserTest, MultipleBackslashes) {
112 // Successive 2N+1 backslashes followed by space (' ') are replaced by N >= 0
113 // backslashes and the space. A single backslash before hash sign is removed.
114 // Other backslashes remain untouched (including 2N backslashes followed by
115 // space).
116 string err;
117 EXPECT_TRUE(Parse(
118"a\\ b\\#c.h: \\\\\\\\\\ \\\\\\\\ \\\\share\\info\\\\#1",
119 &err));
120 ASSERT_EQ("", err);
121 ASSERT_EQ(1u, parser_.outs_.size());
122 EXPECT_EQ("a b#c.h",
123 parser_.outs_[0].AsString());
124 ASSERT_EQ(3u, parser_.ins_.size());
125 EXPECT_EQ("\\\\ ",
126 parser_.ins_[0].AsString());
127 EXPECT_EQ("\\\\\\\\",
128 parser_.ins_[1].AsString());
129 EXPECT_EQ("\\\\share\\info\\#1",
130 parser_.ins_[2].AsString());
131}
132
133TEST_F(DepfileParserTest, Escapes) {
134 // Put backslashes before a variety of characters, see which ones make
135 // it through.
136 string err;
137 EXPECT_TRUE(Parse(
138"\\!\\@\\#$$\\%\\^\\&\\[\\]\\\\:",
139 &err));
140 ASSERT_EQ("", err);
141 ASSERT_EQ(1u, parser_.outs_.size());
142 EXPECT_EQ("\\!\\@#$\\%\\^\\&\\[\\]\\\\",
143 parser_.outs_[0].AsString());
144 ASSERT_EQ(0u, parser_.ins_.size());
145}
146
147TEST_F(DepfileParserTest, EscapedColons)
148{
149 std::string err;
150 // Tests for correct parsing of depfiles produced on Windows
151 // by both Clang, GCC pre 10 and GCC 10
152 EXPECT_TRUE(Parse(
153"c\\:\\gcc\\x86_64-w64-mingw32\\include\\stddef.o: \\\n"
154" c:\\gcc\\x86_64-w64-mingw32\\include\\stddef.h \n",
155 &err));
156 ASSERT_EQ("", err);
157 ASSERT_EQ(1u, parser_.outs_.size());
158 EXPECT_EQ("c:\\gcc\\x86_64-w64-mingw32\\include\\stddef.o",
159 parser_.outs_[0].AsString());
160 ASSERT_EQ(1u, parser_.ins_.size());
161 EXPECT_EQ("c:\\gcc\\x86_64-w64-mingw32\\include\\stddef.h",
162 parser_.ins_[0].AsString());
163}
164
165TEST_F(DepfileParserTest, EscapedTargetColon)
166{
167 std::string err;
168 EXPECT_TRUE(Parse(
169"foo1\\: x\n"
170"foo1\\:\n"
171"foo1\\:\r\n"
172"foo1\\:\t\n"
173"foo1\\:",
174 &err));
175 ASSERT_EQ("", err);
176 ASSERT_EQ(1u, parser_.outs_.size());
177 EXPECT_EQ("foo1\\", parser_.outs_[0].AsString());
178 ASSERT_EQ(1u, parser_.ins_.size());
179 EXPECT_EQ("x", parser_.ins_[0].AsString());
180}
181
182TEST_F(DepfileParserTest, SpecialChars) {
183 // See filenames like istreambuf.iterator_op!= in
184 // https://github.com/google/libcxx/tree/master/test/iterators/stream.iterators/istreambuf.iterator/
185 string err;
186 EXPECT_TRUE(Parse(
187"C:/Program\\ Files\\ (x86)/Microsoft\\ crtdefs.h: \\\n"
188" [email protected]~ t+t-x!=1 \\\n"
189" openldap/slapd.d/cn=config/cn=schema/cn={0}core.ldif\\\n"
190" Fu\303\244ball\\\n"
191" a[1]b@2%c",
192 &err));
193 ASSERT_EQ("", err);
194 ASSERT_EQ(1u, parser_.outs_.size());
195 EXPECT_EQ("C:/Program Files (x86)/Microsoft crtdefs.h",
196 parser_.outs_[0].AsString());
197 ASSERT_EQ(5u, parser_.ins_.size());
198 EXPECT_EQ("[email protected]~",
199 parser_.ins_[0].AsString());
200 EXPECT_EQ("t+t-x!=1",
201 parser_.ins_[1].AsString());
202 EXPECT_EQ("openldap/slapd.d/cn=config/cn=schema/cn={0}core.ldif",
203 parser_.ins_[2].AsString());
204 EXPECT_EQ("Fu\303\244ball",
205 parser_.ins_[3].AsString());
206 EXPECT_EQ("a[1]b@2%c",
207 parser_.ins_[4].AsString());
208}
209
210TEST_F(DepfileParserTest, UnifyMultipleOutputs) {
211 // check that multiple duplicate targets are properly unified
212 string err;
213 EXPECT_TRUE(Parse("foo foo: x y z", &err));
214 ASSERT_EQ(1u, parser_.outs_.size());
215 ASSERT_EQ("foo", parser_.outs_[0].AsString());
216 ASSERT_EQ(3u, parser_.ins_.size());
217 EXPECT_EQ("x", parser_.ins_[0].AsString());
218 EXPECT_EQ("y", parser_.ins_[1].AsString());
219 EXPECT_EQ("z", parser_.ins_[2].AsString());
220}
221
222TEST_F(DepfileParserTest, MultipleDifferentOutputs) {
223 // check that multiple different outputs are accepted by the parser
224 string err;
225 EXPECT_TRUE(Parse("foo bar: x y z", &err));
226 ASSERT_EQ(2u, parser_.outs_.size());
227 ASSERT_EQ("foo", parser_.outs_[0].AsString());
228 ASSERT_EQ("bar", parser_.outs_[1].AsString());
229 ASSERT_EQ(3u, parser_.ins_.size());
230 EXPECT_EQ("x", parser_.ins_[0].AsString());
231 EXPECT_EQ("y", parser_.ins_[1].AsString());
232 EXPECT_EQ("z", parser_.ins_[2].AsString());
233}
234
235TEST_F(DepfileParserTest, MultipleEmptyRules) {
236 string err;
237 EXPECT_TRUE(Parse("foo: x\n"
238 "foo: \n"
239 "foo:\n", &err));
240 ASSERT_EQ(1u, parser_.outs_.size());
241 ASSERT_EQ("foo", parser_.outs_[0].AsString());
242 ASSERT_EQ(1u, parser_.ins_.size());
243 EXPECT_EQ("x", parser_.ins_[0].AsString());
244}
245
246TEST_F(DepfileParserTest, UnifyMultipleRulesLF) {
247 string err;
248 EXPECT_TRUE(Parse("foo: x\n"
249 "foo: y\n"
250 "foo \\\n"
251 "foo: z\n", &err));
252 ASSERT_EQ(1u, parser_.outs_.size());
253 ASSERT_EQ("foo", parser_.outs_[0].AsString());
254 ASSERT_EQ(3u, parser_.ins_.size());
255 EXPECT_EQ("x", parser_.ins_[0].AsString());
256 EXPECT_EQ("y", parser_.ins_[1].AsString());
257 EXPECT_EQ("z", parser_.ins_[2].AsString());
258}
259
260TEST_F(DepfileParserTest, UnifyMultipleRulesCRLF) {
261 string err;
262 EXPECT_TRUE(Parse("foo: x\r\n"
263 "foo: y\r\n"
264 "foo \\\r\n"
265 "foo: z\r\n", &err));
266 ASSERT_EQ(1u, parser_.outs_.size());
267 ASSERT_EQ("foo", parser_.outs_[0].AsString());
268 ASSERT_EQ(3u, parser_.ins_.size());
269 EXPECT_EQ("x", parser_.ins_[0].AsString());
270 EXPECT_EQ("y", parser_.ins_[1].AsString());
271 EXPECT_EQ("z", parser_.ins_[2].AsString());
272}
273
274TEST_F(DepfileParserTest, UnifyMixedRulesLF) {
275 string err;
276 EXPECT_TRUE(Parse("foo: x\\\n"
277 " y\n"
278 "foo \\\n"
279 "foo: z\n", &err));
280 ASSERT_EQ(1u, parser_.outs_.size());
281 ASSERT_EQ("foo", parser_.outs_[0].AsString());
282 ASSERT_EQ(3u, parser_.ins_.size());
283 EXPECT_EQ("x", parser_.ins_[0].AsString());
284 EXPECT_EQ("y", parser_.ins_[1].AsString());
285 EXPECT_EQ("z", parser_.ins_[2].AsString());
286}
287
288TEST_F(DepfileParserTest, UnifyMixedRulesCRLF) {
289 string err;
290 EXPECT_TRUE(Parse("foo: x\\\r\n"
291 " y\r\n"
292 "foo \\\r\n"
293 "foo: z\r\n", &err));
294 ASSERT_EQ(1u, parser_.outs_.size());
295 ASSERT_EQ("foo", parser_.outs_[0].AsString());
296 ASSERT_EQ(3u, parser_.ins_.size());
297 EXPECT_EQ("x", parser_.ins_[0].AsString());
298 EXPECT_EQ("y", parser_.ins_[1].AsString());
299 EXPECT_EQ("z", parser_.ins_[2].AsString());
300}
301
302TEST_F(DepfileParserTest, IndentedRulesLF) {
303 string err;
304 EXPECT_TRUE(Parse(" foo: x\n"
305 " foo: y\n"
306 " foo: z\n", &err));
307 ASSERT_EQ(1u, parser_.outs_.size());
308 ASSERT_EQ("foo", parser_.outs_[0].AsString());
309 ASSERT_EQ(3u, parser_.ins_.size());
310 EXPECT_EQ("x", parser_.ins_[0].AsString());
311 EXPECT_EQ("y", parser_.ins_[1].AsString());
312 EXPECT_EQ("z", parser_.ins_[2].AsString());
313}
314
315TEST_F(DepfileParserTest, IndentedRulesCRLF) {
316 string err;
317 EXPECT_TRUE(Parse(" foo: x\r\n"
318 " foo: y\r\n"
319 " foo: z\r\n", &err));
320 ASSERT_EQ(1u, parser_.outs_.size());
321 ASSERT_EQ("foo", parser_.outs_[0].AsString());
322 ASSERT_EQ(3u, parser_.ins_.size());
323 EXPECT_EQ("x", parser_.ins_[0].AsString());
324 EXPECT_EQ("y", parser_.ins_[1].AsString());
325 EXPECT_EQ("z", parser_.ins_[2].AsString());
326}
327
328TEST_F(DepfileParserTest, TolerateMP) {
329 string err;
330 EXPECT_TRUE(Parse("foo: x y z\n"
331 "x:\n"
332 "y:\n"
333 "z:\n", &err));
334 ASSERT_EQ(1u, parser_.outs_.size());
335 ASSERT_EQ("foo", parser_.outs_[0].AsString());
336 ASSERT_EQ(3u, parser_.ins_.size());
337 EXPECT_EQ("x", parser_.ins_[0].AsString());
338 EXPECT_EQ("y", parser_.ins_[1].AsString());
339 EXPECT_EQ("z", parser_.ins_[2].AsString());
340}
341
342TEST_F(DepfileParserTest, MultipleRulesTolerateMP) {
343 string err;
344 EXPECT_TRUE(Parse("foo: x\n"
345 "x:\n"
346 "foo: y\n"
347 "y:\n"
348 "foo: z\n"
349 "z:\n", &err));
350 ASSERT_EQ(1u, parser_.outs_.size());
351 ASSERT_EQ("foo", parser_.outs_[0].AsString());
352 ASSERT_EQ(3u, parser_.ins_.size());
353 EXPECT_EQ("x", parser_.ins_[0].AsString());
354 EXPECT_EQ("y", parser_.ins_[1].AsString());
355 EXPECT_EQ("z", parser_.ins_[2].AsString());
356}
357
358TEST_F(DepfileParserTest, MultipleRulesDifferentOutputs) {
359 // check that multiple different outputs are accepted by the parser
360 // when spread across multiple rules
361 string err;
362 EXPECT_TRUE(Parse("foo: x y\n"
363 "bar: y z\n", &err));
364 ASSERT_EQ(2u, parser_.outs_.size());
365 ASSERT_EQ("foo", parser_.outs_[0].AsString());
366 ASSERT_EQ("bar", parser_.outs_[1].AsString());
367 ASSERT_EQ(3u, parser_.ins_.size());
368 EXPECT_EQ("x", parser_.ins_[0].AsString());
369 EXPECT_EQ("y", parser_.ins_[1].AsString());
370 EXPECT_EQ("z", parser_.ins_[2].AsString());
371}
372
373TEST_F(DepfileParserTest, BuggyMP) {
374 std::string err;
375 EXPECT_FALSE(Parse("foo: x y z\n"
376 "x: alsoin\n"
377 "y:\n"
378 "z:\n", &err));
379 ASSERT_EQ("inputs may not also have inputs", err);
380}
381