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 | |
24 | DepfileParser parser_; |
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 | |
33 | TEST_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 | |
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, 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 | |
77 | TEST_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 | |
93 | TEST_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 | |
111 | TEST_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 | |
133 | TEST_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 | |
147 | TEST_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 | |
165 | TEST_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 | |
182 | TEST_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 | |
210 | TEST_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 | |
222 | TEST_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 | |
235 | TEST_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 | |
246 | TEST_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 | |
260 | TEST_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 | |
274 | TEST_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 | |
288 | TEST_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 | |
302 | TEST_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 | |
315 | TEST_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 | |
328 | TEST_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 | |
342 | TEST_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 | |
358 | TEST_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 | |
373 | TEST_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 | |