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