blob: a32df650eb994f290dee8118e40d05b322146456 [file] [log] [blame]
Dan Willemsen43398532018-02-21 02:10:29 -08001// Copyright 2018 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
Dan Willemsenc89b6f12019-08-29 14:47:40 -070015package makedeps
Dan Willemsen43398532018-02-21 02:10:29 -080016
17import (
18 "bytes"
19 "io"
20 "io/ioutil"
21 "os"
22 "testing"
23)
24
25func TestParse(t *testing.T) {
26 testCases := []struct {
27 name string
28 input string
29 output Deps
30 err error
31 }{
32 // These come from the ninja test suite
33 {
34 name: "Basic",
35 input: "build/ninja.o: ninja.cc ninja.h eval_env.h manifest_parser.h",
36 output: Deps{
37 Output: "build/ninja.o",
38 Inputs: []string{
39 "ninja.cc",
40 "ninja.h",
41 "eval_env.h",
42 "manifest_parser.h",
43 },
44 },
45 },
46 {
47 name: "EarlyNewlineAndWhitespace",
48 input: ` \
49 out: in`,
50 output: Deps{
51 Output: "out",
52 Inputs: []string{"in"},
53 },
54 },
55 {
56 name: "Continuation",
57 input: `foo.o: \
58 bar.h baz.h
59`,
60 output: Deps{
61 Output: "foo.o",
62 Inputs: []string{"bar.h", "baz.h"},
63 },
64 },
65 {
66 name: "CarriageReturnContinuation",
67 input: "foo.o: \\\r\n bar.h baz.h\r\n",
68 output: Deps{
69 Output: "foo.o",
70 Inputs: []string{"bar.h", "baz.h"},
71 },
72 },
73 {
74 name: "BackSlashes",
75 input: `Project\Dir\Build\Release8\Foo\Foo.res : \
76 Dir\Library\Foo.rc \
77 Dir\Library\Version\Bar.h \
78 Dir\Library\Foo.ico \
79 Project\Thing\Bar.tlb \
80`,
81 output: Deps{
82 Output: `Project\Dir\Build\Release8\Foo\Foo.res`,
83 Inputs: []string{
84 `Dir\Library\Foo.rc`,
85 `Dir\Library\Version\Bar.h`,
86 `Dir\Library\Foo.ico`,
87 `Project\Thing\Bar.tlb`,
88 },
89 },
90 },
91 {
92 name: "Spaces",
93 input: `a\ bc\ def: a\ b c d`,
94 output: Deps{
95 Output: `a bc def`,
96 Inputs: []string{"a b", "c", "d"},
97 },
98 },
99 {
100 name: "Escapes",
101 input: `\!\@\#$$\%\^\&\\:`,
102 output: Deps{
103 Output: `\!\@#$\%\^\&\`,
104 },
105 },
106 {
107 name: "SpecialChars",
108 // Ninja includes a number of '=', but our parser can't handle that,
109 // since it sees the equals and switches over to assuming it's an
110 // assignment.
111 //
112 // We don't have any files in our tree that contain an '=' character,
113 // and Kati can't handle parsing this either, so for now I'm just
114 // going to remove all the '=' characters below.
115 //
116 // It looks like make will only do this for the first
117 // dependency, but not later dependencies.
118 input: `C\:/Program\ Files\ (x86)/Microsoft\ crtdefs.h: \
119 en@quot.header~ t+t-x!1 \
120 openldap/slapd.d/cnconfig/cnschema/cn{0}core.ldif \
121 Fu` + "\303\244ball",
122 output: Deps{
123 Output: "C:/Program Files (x86)/Microsoft crtdefs.h",
124 Inputs: []string{
125 "en@quot.header~",
126 "t+t-x!1",
127 "openldap/slapd.d/cnconfig/cnschema/cn{0}core.ldif",
128 "Fu\303\244ball",
129 },
130 },
131 },
132 // Ninja's UnifyMultipleOutputs and RejectMultipleDifferentOutputs tests have been omitted,
133 // since we don't want the same behavior.
134
135 // Our own tests
136 {
137 name: "Multiple outputs",
138 input: `a b: c
139a: d
140b: e`,
141 output: Deps{
142 Output: "b",
143 Inputs: []string{
144 "c",
145 "d",
146 "e",
147 },
148 },
149 },
150 }
151
152 for _, tc := range testCases {
153 t.Run(tc.name, func(t *testing.T) {
154 out, err := Parse("test.d", bytes.NewBufferString(tc.input))
155 if err != tc.err {
156 t.Fatalf("Unexpected error: %v (expected %v)", err, tc.err)
157 }
158
159 if out.Output != tc.output.Output {
160 t.Errorf("output file doesn't match:\n"+
161 " str: %#v\n"+
162 "want: %#v\n"+
163 " got: %#v", tc.input, tc.output.Output, out.Output)
164 }
165
166 matches := true
167 if len(out.Inputs) != len(tc.output.Inputs) {
168 matches = false
169 } else {
170 for i := range out.Inputs {
171 if out.Inputs[i] != tc.output.Inputs[i] {
172 matches = false
173 }
174 }
175 }
176 if !matches {
177 t.Errorf("input files don't match:\n"+
178 " str: %#v\n"+
179 "want: %#v\n"+
180 " got: %#v", tc.input, tc.output.Inputs, out.Inputs)
181 }
182 })
183 }
184}
185
186func BenchmarkParsing(b *testing.B) {
187 // Write it out to a file to most closely match ninja's perftest
188 tmpfile, err := ioutil.TempFile("", "depfile")
189 if err != nil {
190 b.Fatal("Failed to create temp file:", err)
191 }
192 defer os.Remove(tmpfile.Name())
193 _, err = io.WriteString(tmpfile, `out/soong/.intermediates/external/ninja/ninja/linux_glibc_x86_64/obj/external/ninja/src/ninja.o: \
194 external/ninja/src/ninja.cc external/libcxx/include/errno.h \
195 external/libcxx/include/__config \
196 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/features.h \
197 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/predefs.h \
198 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/sys/cdefs.h \
199 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/wordsize.h \
200 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/gnu/stubs.h \
201 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/gnu/stubs-64.h \
202 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/errno.h \
203 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/errno.h \
204 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/linux/errno.h \
205 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/asm/errno.h \
206 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/asm-generic/errno.h \
207 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/asm-generic/errno-base.h \
208 external/libcxx/include/limits.h \
209 prebuilts/clang/host/linux-x86/clang-4639204/lib64/clang/6.0.1/include/limits.h \
210 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/limits.h \
211 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/posix1_lim.h \
212 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/local_lim.h \
213 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/linux/limits.h \
214 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/posix2_lim.h \
215 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/xopen_lim.h \
216 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/stdio_lim.h \
217 external/libcxx/include/stdio.h \
218 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/stdio.h \
219 external/libcxx/include/stddef.h \
220 prebuilts/clang/host/linux-x86/clang-4639204/lib64/clang/6.0.1/include/stddef.h \
221 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/types.h \
222 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/typesizes.h \
223 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/libio.h \
224 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/_G_config.h \
225 external/libcxx/include/wchar.h \
226 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/wchar.h \
227 prebuilts/clang/host/linux-x86/clang-4639204/lib64/clang/6.0.1/include/stdarg.h \
228 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/sys_errlist.h \
229 external/libcxx/include/stdlib.h \
230 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/stdlib.h \
231 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/waitflags.h \
232 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/waitstatus.h \
233 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/endian.h \
234 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/endian.h \
235 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/byteswap.h \
236 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/xlocale.h \
237 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/sys/types.h \
238 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/time.h \
239 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/sys/select.h \
240 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/select.h \
241 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/sigset.h \
242 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/time.h \
243 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/select2.h \
244 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/sys/sysmacros.h \
245 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \
246 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/alloca.h \
247 external/libcxx/include/string.h \
248 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/string.h \
249 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/getopt.h \
250 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/unistd.h \
251 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/posix_opt.h \
252 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/environments.h \
253 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/confname.h \
254 external/ninja/src/browse.h external/ninja/src/build.h \
255 external/libcxx/include/cstdio external/libcxx/include/map \
256 external/libcxx/include/__tree external/libcxx/include/iterator \
257 external/libcxx/include/iosfwd \
258 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/wchar.h \
259 external/libcxx/include/__functional_base \
260 external/libcxx/include/type_traits external/libcxx/include/cstddef \
261 prebuilts/clang/host/linux-x86/clang-4639204/lib64/clang/6.0.1/include/__stddef_max_align_t.h \
262 external/libcxx/include/__nullptr external/libcxx/include/typeinfo \
263 external/libcxx/include/exception external/libcxx/include/cstdlib \
264 external/libcxx/include/cstdint external/libcxx/include/stdint.h \
265 prebuilts/clang/host/linux-x86/clang-4639204/lib64/clang/6.0.1/include/stdint.h \
266 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/stdint.h \
267 external/libcxx/include/new external/libcxx/include/utility \
268 external/libcxx/include/__tuple \
269 external/libcxx/include/initializer_list \
270 external/libcxx/include/cstring external/libcxx/include/__debug \
271 external/libcxx/include/memory external/libcxx/include/limits \
272 external/libcxx/include/__undef_macros external/libcxx/include/tuple \
273 external/libcxx/include/stdexcept external/libcxx/include/cassert \
274 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/assert.h \
275 external/libcxx/include/atomic external/libcxx/include/algorithm \
276 external/libcxx/include/functional external/libcxx/include/queue \
277 external/libcxx/include/deque external/libcxx/include/__split_buffer \
278 external/libcxx/include/vector external/libcxx/include/__bit_reference \
279 external/libcxx/include/climits external/libcxx/include/set \
280 external/libcxx/include/string external/libcxx/include/string_view \
281 external/libcxx/include/__string external/libcxx/include/cwchar \
282 external/libcxx/include/cwctype external/libcxx/include/cctype \
283 external/libcxx/include/ctype.h \
284 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/ctype.h \
285 external/libcxx/include/wctype.h \
286 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/wctype.h \
287 external/ninja/src/graph.h external/ninja/src/eval_env.h \
288 external/ninja/src/string_piece.h external/ninja/src/timestamp.h \
289 external/ninja/src/util.h external/ninja/src/exit_status.h \
290 external/ninja/src/line_printer.h external/ninja/src/metrics.h \
291 external/ninja/src/build_log.h external/ninja/src/hash_map.h \
292 external/libcxx/include/unordered_map \
293 external/libcxx/include/__hash_table external/libcxx/include/cmath \
294 external/libcxx/include/math.h \
295 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/math.h \
296 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/huge_val.h \
297 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/huge_valf.h \
298 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/huge_vall.h \
299 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/inf.h \
300 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/nan.h \
301 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/mathdef.h \
302 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/mathcalls.h \
303 external/ninja/src/deps_log.h external/ninja/src/clean.h \
304 external/ninja/src/debug_flags.h external/ninja/src/disk_interface.h \
305 external/ninja/src/graphviz.h external/ninja/src/manifest_parser.h \
306 external/ninja/src/lexer.h external/ninja/src/state.h \
307 external/ninja/src/version.h`)
308 tmpfile.Close()
309 if err != nil {
310 b.Fatal("Failed to write dep file:", err)
311 }
312 b.ResetTimer()
313
314 for n := 0; n < b.N; n++ {
315 depfile, err := ioutil.ReadFile(tmpfile.Name())
316 if err != nil {
317 b.Fatal("Failed to read dep file:", err)
318 }
319
320 _, err = Parse(tmpfile.Name(), bytes.NewBuffer(depfile))
321 if err != nil {
322 b.Fatal("Failed to parse:", err)
323 }
324 }
325}
326
327func TestDepPrint(t *testing.T) {
328 testCases := []struct {
329 name string
330 input Deps
331 output string
332 }{
333 {
334 name: "Empty",
335 input: Deps{
336 Output: "a",
337 },
338 output: "a:",
339 },
340 {
341 name: "Basic",
342 input: Deps{
343 Output: "a",
344 Inputs: []string{"b", "c"},
345 },
346 output: "a: b c",
347 },
348 {
349 name: "Escapes",
350 input: Deps{
351 Output: `\!\@#$\%\^\&\`,
352 },
353 output: `\\!\\@\#$$\\%\\^\\&\\:`,
354 },
355 {
356 name: "Spaces",
357 input: Deps{
358 Output: "a b",
359 Inputs: []string{"c d", "e f "},
360 },
361 output: `a\ b: c\ d e\ f\ `,
362 },
363 {
364 name: "SpecialChars",
365 input: Deps{
366 Output: "C:/Program Files (x86)/Microsoft crtdefs.h",
367 Inputs: []string{
368 "en@quot.header~",
369 "t+t-x!1",
370 "openldap/slapd.d/cnconfig/cnschema/cn{0}core.ldif",
371 "Fu\303\244ball",
372 },
373 },
374 output: `C\:/Program\ Files\ (x86)/Microsoft\ crtdefs.h: en@quot.header~ t+t-x!1 openldap/slapd.d/cnconfig/cnschema/cn{0}core.ldif Fu` + "\303\244ball",
375 },
376 }
377
378 for _, tc := range testCases {
379 t.Run(tc.name, func(t *testing.T) {
380 out := tc.input.Print()
381 outStr := string(out)
382 want := tc.output + "\n"
383
384 if outStr != want {
385 t.Errorf("output doesn't match:\nwant:%q\n got:%q", want, outStr)
386 }
387 })
388 }
389}