1// 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 15package makedeps 16 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 // TODO(b/141372861): remove this 152 // AIDL produces a dep file with no output file for a parcelable (b/ 153 name: "AIDL parcelable", 154 input: ` : \ 155 frameworks/base/tests/net/integration/src/com/android/server/net/integrationtests/HttpResponse.aidl 156`, 157 output: Deps{ 158 Output: "", 159 Inputs: []string{ 160 "frameworks/base/tests/net/integration/src/com/android/server/net/integrationtests/HttpResponse.aidl", 161 }, 162 }, 163 }, 164 } 165 166 for _, tc := range testCases { 167 t.Run(tc.name, func(t *testing.T) { 168 out, err := Parse("test.d", bytes.NewBufferString(tc.input)) 169 if err != tc.err { 170 t.Fatalf("Unexpected error: %v (expected %v)", err, tc.err) 171 } 172 173 if out.Output != tc.output.Output { 174 t.Errorf("output file doesn't match:\n"+ 175 " str: %#v\n"+ 176 "want: %#v\n"+ 177 " got: %#v", tc.input, tc.output.Output, out.Output) 178 } 179 180 matches := true 181 if len(out.Inputs) != len(tc.output.Inputs) { 182 matches = false 183 } else { 184 for i := range out.Inputs { 185 if out.Inputs[i] != tc.output.Inputs[i] { 186 matches = false 187 } 188 } 189 } 190 if !matches { 191 t.Errorf("input files don't match:\n"+ 192 " str: %#v\n"+ 193 "want: %#v\n"+ 194 " got: %#v", tc.input, tc.output.Inputs, out.Inputs) 195 } 196 }) 197 } 198} 199 200func BenchmarkParsing(b *testing.B) { 201 // Write it out to a file to most closely match ninja's perftest 202 tmpfile, err := ioutil.TempFile("", "depfile") 203 if err != nil { 204 b.Fatal("Failed to create temp file:", err) 205 } 206 defer os.Remove(tmpfile.Name()) 207 _, err = io.WriteString(tmpfile, `out/soong/.intermediates/external/ninja/ninja/linux_glibc_x86_64/obj/external/ninja/src/ninja.o: \ 208 external/ninja/src/ninja.cc external/libcxx/include/errno.h \ 209 external/libcxx/include/__config \ 210 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/features.h \ 211 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/predefs.h \ 212 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/sys/cdefs.h \ 213 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/wordsize.h \ 214 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/gnu/stubs.h \ 215 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/gnu/stubs-64.h \ 216 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/errno.h \ 217 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/errno.h \ 218 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/linux/errno.h \ 219 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/asm/errno.h \ 220 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/asm-generic/errno.h \ 221 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/asm-generic/errno-base.h \ 222 external/libcxx/include/limits.h \ 223 prebuilts/clang/host/linux-x86/clang-4639204/lib64/clang/6.0.1/include/limits.h \ 224 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/limits.h \ 225 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/posix1_lim.h \ 226 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/local_lim.h \ 227 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/linux/limits.h \ 228 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/posix2_lim.h \ 229 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/xopen_lim.h \ 230 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/stdio_lim.h \ 231 external/libcxx/include/stdio.h \ 232 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/stdio.h \ 233 external/libcxx/include/stddef.h \ 234 prebuilts/clang/host/linux-x86/clang-4639204/lib64/clang/6.0.1/include/stddef.h \ 235 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/types.h \ 236 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/typesizes.h \ 237 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/libio.h \ 238 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/_G_config.h \ 239 external/libcxx/include/wchar.h \ 240 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/wchar.h \ 241 prebuilts/clang/host/linux-x86/clang-4639204/lib64/clang/6.0.1/include/stdarg.h \ 242 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/sys_errlist.h \ 243 external/libcxx/include/stdlib.h \ 244 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/stdlib.h \ 245 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/waitflags.h \ 246 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/waitstatus.h \ 247 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/endian.h \ 248 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/endian.h \ 249 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/byteswap.h \ 250 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/xlocale.h \ 251 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/sys/types.h \ 252 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/time.h \ 253 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/sys/select.h \ 254 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/select.h \ 255 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/sigset.h \ 256 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/time.h \ 257 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/select2.h \ 258 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/sys/sysmacros.h \ 259 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \ 260 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/alloca.h \ 261 external/libcxx/include/string.h \ 262 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/string.h \ 263 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/getopt.h \ 264 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/unistd.h \ 265 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/posix_opt.h \ 266 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/environments.h \ 267 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/confname.h \ 268 external/ninja/src/browse.h external/ninja/src/build.h \ 269 external/libcxx/include/cstdio external/libcxx/include/map \ 270 external/libcxx/include/__tree external/libcxx/include/iterator \ 271 external/libcxx/include/iosfwd \ 272 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/wchar.h \ 273 external/libcxx/include/__functional_base \ 274 external/libcxx/include/type_traits external/libcxx/include/cstddef \ 275 prebuilts/clang/host/linux-x86/clang-4639204/lib64/clang/6.0.1/include/__stddef_max_align_t.h \ 276 external/libcxx/include/__nullptr external/libcxx/include/typeinfo \ 277 external/libcxx/include/exception external/libcxx/include/cstdlib \ 278 external/libcxx/include/cstdint external/libcxx/include/stdint.h \ 279 prebuilts/clang/host/linux-x86/clang-4639204/lib64/clang/6.0.1/include/stdint.h \ 280 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/stdint.h \ 281 external/libcxx/include/new external/libcxx/include/utility \ 282 external/libcxx/include/__tuple \ 283 external/libcxx/include/initializer_list \ 284 external/libcxx/include/cstring external/libcxx/include/__debug \ 285 external/libcxx/include/memory external/libcxx/include/limits \ 286 external/libcxx/include/__undef_macros external/libcxx/include/tuple \ 287 external/libcxx/include/stdexcept external/libcxx/include/cassert \ 288 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/assert.h \ 289 external/libcxx/include/atomic external/libcxx/include/algorithm \ 290 external/libcxx/include/functional external/libcxx/include/queue \ 291 external/libcxx/include/deque external/libcxx/include/__split_buffer \ 292 external/libcxx/include/vector external/libcxx/include/__bit_reference \ 293 external/libcxx/include/climits external/libcxx/include/set \ 294 external/libcxx/include/string external/libcxx/include/string_view \ 295 external/libcxx/include/__string external/libcxx/include/cwchar \ 296 external/libcxx/include/cwctype external/libcxx/include/cctype \ 297 external/libcxx/include/ctype.h \ 298 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/ctype.h \ 299 external/libcxx/include/wctype.h \ 300 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/wctype.h \ 301 external/ninja/src/graph.h external/ninja/src/eval_env.h \ 302 external/ninja/src/string_piece.h external/ninja/src/timestamp.h \ 303 external/ninja/src/util.h external/ninja/src/exit_status.h \ 304 external/ninja/src/line_printer.h external/ninja/src/metrics.h \ 305 external/ninja/src/build_log.h external/ninja/src/hash_map.h \ 306 external/libcxx/include/unordered_map \ 307 external/libcxx/include/__hash_table external/libcxx/include/cmath \ 308 external/libcxx/include/math.h \ 309 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/math.h \ 310 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/huge_val.h \ 311 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/huge_valf.h \ 312 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/huge_vall.h \ 313 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/inf.h \ 314 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/nan.h \ 315 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/mathdef.h \ 316 prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/mathcalls.h \ 317 external/ninja/src/deps_log.h external/ninja/src/clean.h \ 318 external/ninja/src/debug_flags.h external/ninja/src/disk_interface.h \ 319 external/ninja/src/graphviz.h external/ninja/src/manifest_parser.h \ 320 external/ninja/src/lexer.h external/ninja/src/state.h \ 321 external/ninja/src/version.h`) 322 tmpfile.Close() 323 if err != nil { 324 b.Fatal("Failed to write dep file:", err) 325 } 326 b.ResetTimer() 327 328 for n := 0; n < b.N; n++ { 329 depfile, err := ioutil.ReadFile(tmpfile.Name()) 330 if err != nil { 331 b.Fatal("Failed to read dep file:", err) 332 } 333 334 _, err = Parse(tmpfile.Name(), bytes.NewBuffer(depfile)) 335 if err != nil { 336 b.Fatal("Failed to parse:", err) 337 } 338 } 339} 340 341func TestDepPrint(t *testing.T) { 342 testCases := []struct { 343 name string 344 input Deps 345 output string 346 }{ 347 { 348 name: "Empty", 349 input: Deps{ 350 Output: "a", 351 }, 352 output: "a:", 353 }, 354 { 355 name: "Basic", 356 input: Deps{ 357 Output: "a", 358 Inputs: []string{"b", "c"}, 359 }, 360 output: "a: b c", 361 }, 362 { 363 name: "Escapes", 364 input: Deps{ 365 Output: `\!\@#$\%\^\&\`, 366 }, 367 output: `\\!\\@\#$$\\%\\^\\&\\:`, 368 }, 369 { 370 name: "Spaces", 371 input: Deps{ 372 Output: "a b", 373 Inputs: []string{"c d", "e f "}, 374 }, 375 output: `a\ b: c\ d e\ f\ `, 376 }, 377 { 378 name: "SpecialChars", 379 input: Deps{ 380 Output: "C:/Program Files (x86)/Microsoft crtdefs.h", 381 Inputs: []string{ 382 "en@quot.header~", 383 "t+t-x!1", 384 "openldap/slapd.d/cnconfig/cnschema/cn{0}core.ldif", 385 "Fu\303\244ball", 386 }, 387 }, 388 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", 389 }, 390 } 391 392 for _, tc := range testCases { 393 t.Run(tc.name, func(t *testing.T) { 394 out := tc.input.Print() 395 outStr := string(out) 396 want := tc.output + "\n" 397 398 if outStr != want { 399 t.Errorf("output doesn't match:\nwant:%q\n got:%q", want, outStr) 400 } 401 }) 402 } 403} 404