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
Parse(const char * input,string * err)28 bool DepfileParserTest::Parse(const char* input, string* err) {
29 input_ = input;
30 return parser_.Parse(&input_, err);
31 }
32
TEST_F(DepfileParserTest,Basic)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
TEST_F(DepfileParserTest,EarlyNewlineAndWhitespace)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
TEST_F(DepfileParserTest,Continuation)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
TEST_F(DepfileParserTest,CarriageReturnContinuation)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
TEST_F(DepfileParserTest,BackSlashes)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
TEST_F(DepfileParserTest,Spaces)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
TEST_F(DepfileParserTest,MultipleBackslashes)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
TEST_F(DepfileParserTest,Escapes)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
TEST_F(DepfileParserTest,EscapedColons)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
TEST_F(DepfileParserTest,EscapedTargetColon)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
TEST_F(DepfileParserTest,SpecialChars)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 " en@quot.header~ 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("en@quot.header~",
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
TEST_F(DepfileParserTest,UnifyMultipleOutputs)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
TEST_F(DepfileParserTest,MultipleDifferentOutputs)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
TEST_F(DepfileParserTest,MultipleEmptyRules)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
TEST_F(DepfileParserTest,UnifyMultipleRulesLF)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
TEST_F(DepfileParserTest,UnifyMultipleRulesCRLF)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
TEST_F(DepfileParserTest,UnifyMixedRulesLF)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
TEST_F(DepfileParserTest,UnifyMixedRulesCRLF)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
TEST_F(DepfileParserTest,IndentedRulesLF)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
TEST_F(DepfileParserTest,IndentedRulesCRLF)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
TEST_F(DepfileParserTest,TolerateMP)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
TEST_F(DepfileParserTest,MultipleRulesTolerateMP)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
TEST_F(DepfileParserTest,MultipleRulesDifferentOutputs)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
TEST_F(DepfileParserTest,BuggyMP)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