blob: 2f5605e9474c91f541334b0a7ab4730d12635400 [file] [log] [blame]
Colin Cross2a076922018-10-04 23:28:25 -07001// 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 genrule
16
17import (
18 "io/ioutil"
19 "os"
Colin Crossba71a3f2019-03-18 12:12:48 -070020 "reflect"
Colin Cross2a076922018-10-04 23:28:25 -070021 "strings"
22 "testing"
23
24 "android/soong/android"
Colin Crossba71a3f2019-03-18 12:12:48 -070025
26 "github.com/google/blueprint/proptools"
Colin Cross2a076922018-10-04 23:28:25 -070027)
28
29var buildDir string
30
31func setUp() {
32 var err error
Colin Crossef354482018-10-23 11:27:50 -070033 buildDir, err = ioutil.TempDir("", "genrule_test")
Colin Cross2a076922018-10-04 23:28:25 -070034 if err != nil {
35 panic(err)
36 }
37}
38
39func tearDown() {
40 os.RemoveAll(buildDir)
41}
42
43func TestMain(m *testing.M) {
44 run := func() int {
45 setUp()
46 defer tearDown()
47
48 return m.Run()
49 }
50
51 os.Exit(run())
52}
53
Colin Cross98be1bb2019-12-13 20:41:13 -080054func testContext(config android.Config) *android.TestContext {
Colin Cross2a076922018-10-04 23:28:25 -070055
Colin Crossae8600b2020-10-29 17:09:13 -070056 ctx := android.NewTestArchContext(config)
Colin Cross4b49b762019-11-22 15:25:03 -080057 ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
Colin Cross4b49b762019-11-22 15:25:03 -080058 ctx.RegisterModuleType("tool", toolFactory)
Martin Stjernholm710ec3a2020-01-16 15:12:04 +000059
Colin Crosse9fe2942020-11-10 18:12:15 -080060 RegisterGenruleBuildComponents(ctx)
Martin Stjernholm710ec3a2020-01-16 15:12:04 +000061
Jaewoong Jung98716bd2018-12-10 08:13:18 -080062 ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
Colin Crossae8600b2020-10-29 17:09:13 -070063 ctx.Register()
Colin Cross2a076922018-10-04 23:28:25 -070064
Colin Cross98be1bb2019-12-13 20:41:13 -080065 return ctx
66}
67
68func testConfig(bp string, fs map[string][]byte) android.Config {
Colin Cross2a076922018-10-04 23:28:25 -070069 bp += `
70 tool {
71 name: "tool",
72 }
73
74 filegroup {
75 name: "tool_files",
76 srcs: [
77 "tool_file1",
78 "tool_file2",
79 ],
80 }
81
82 filegroup {
83 name: "1tool_file",
84 srcs: [
85 "tool_file1",
86 ],
87 }
88
89 filegroup {
90 name: "ins",
91 srcs: [
92 "in1",
93 "in2",
94 ],
95 }
96
97 filegroup {
98 name: "1in",
99 srcs: [
100 "in1",
101 ],
102 }
103
104 filegroup {
105 name: "empty",
106 }
107 `
108
109 mockFS := map[string][]byte{
Colin Cross2a076922018-10-04 23:28:25 -0700110 "tool": nil,
111 "tool_file1": nil,
112 "tool_file2": nil,
113 "in1": nil,
114 "in2": nil,
Colin Cross1a527682019-09-23 15:55:30 -0700115 "in1.txt": nil,
116 "in2.txt": nil,
117 "in3.txt": nil,
Colin Cross2a076922018-10-04 23:28:25 -0700118 }
119
120 for k, v := range fs {
121 mockFS[k] = v
122 }
123
Colin Cross98be1bb2019-12-13 20:41:13 -0800124 return android.TestArchConfig(buildDir, nil, bp, mockFS)
Colin Cross2a076922018-10-04 23:28:25 -0700125}
126
127func TestGenruleCmd(t *testing.T) {
128 testcases := []struct {
129 name string
130 prop string
131
Colin Crossba71a3f2019-03-18 12:12:48 -0700132 allowMissingDependencies bool
133
Colin Cross2a076922018-10-04 23:28:25 -0700134 err string
135 expect string
136 }{
137 {
138 name: "empty location tool",
139 prop: `
140 tools: ["tool"],
141 out: ["out"],
142 cmd: "$(location) > $(out)",
143 `,
Colin Crossba9e4032020-11-24 16:32:22 -0800144 expect: "__SBOX_SANDBOX_DIR__/tools/out/bin/tool > __SBOX_SANDBOX_DIR__/out/out",
Colin Cross2a076922018-10-04 23:28:25 -0700145 },
146 {
Colin Cross08f15ab2018-10-04 23:29:14 -0700147 name: "empty location tool2",
148 prop: `
149 tools: [":tool"],
150 out: ["out"],
151 cmd: "$(location) > $(out)",
152 `,
Colin Crossba9e4032020-11-24 16:32:22 -0800153 expect: "__SBOX_SANDBOX_DIR__/tools/out/bin/tool > __SBOX_SANDBOX_DIR__/out/out",
Colin Cross08f15ab2018-10-04 23:29:14 -0700154 },
155 {
Colin Cross2a076922018-10-04 23:28:25 -0700156 name: "empty location tool file",
157 prop: `
158 tool_files: ["tool_file1"],
159 out: ["out"],
160 cmd: "$(location) > $(out)",
161 `,
Colin Crossba9e4032020-11-24 16:32:22 -0800162 expect: "__SBOX_SANDBOX_DIR__/tools/src/tool_file1 > __SBOX_SANDBOX_DIR__/out/out",
Colin Cross2a076922018-10-04 23:28:25 -0700163 },
164 {
165 name: "empty location tool file fg",
166 prop: `
167 tool_files: [":1tool_file"],
168 out: ["out"],
169 cmd: "$(location) > $(out)",
170 `,
Colin Crossba9e4032020-11-24 16:32:22 -0800171 expect: "__SBOX_SANDBOX_DIR__/tools/src/tool_file1 > __SBOX_SANDBOX_DIR__/out/out",
Colin Cross2a076922018-10-04 23:28:25 -0700172 },
173 {
174 name: "empty location tool and tool file",
175 prop: `
176 tools: ["tool"],
177 tool_files: ["tool_file1"],
178 out: ["out"],
179 cmd: "$(location) > $(out)",
180 `,
Colin Crossba9e4032020-11-24 16:32:22 -0800181 expect: "__SBOX_SANDBOX_DIR__/tools/out/bin/tool > __SBOX_SANDBOX_DIR__/out/out",
Colin Cross2a076922018-10-04 23:28:25 -0700182 },
183 {
184 name: "tool",
185 prop: `
186 tools: ["tool"],
187 out: ["out"],
188 cmd: "$(location tool) > $(out)",
189 `,
Colin Crossba9e4032020-11-24 16:32:22 -0800190 expect: "__SBOX_SANDBOX_DIR__/tools/out/bin/tool > __SBOX_SANDBOX_DIR__/out/out",
Colin Cross2a076922018-10-04 23:28:25 -0700191 },
192 {
Colin Cross08f15ab2018-10-04 23:29:14 -0700193 name: "tool2",
194 prop: `
195 tools: [":tool"],
196 out: ["out"],
197 cmd: "$(location :tool) > $(out)",
198 `,
Colin Crossba9e4032020-11-24 16:32:22 -0800199 expect: "__SBOX_SANDBOX_DIR__/tools/out/bin/tool > __SBOX_SANDBOX_DIR__/out/out",
Colin Cross08f15ab2018-10-04 23:29:14 -0700200 },
201 {
Colin Cross2a076922018-10-04 23:28:25 -0700202 name: "tool file",
203 prop: `
204 tool_files: ["tool_file1"],
205 out: ["out"],
206 cmd: "$(location tool_file1) > $(out)",
207 `,
Colin Crossba9e4032020-11-24 16:32:22 -0800208 expect: "__SBOX_SANDBOX_DIR__/tools/src/tool_file1 > __SBOX_SANDBOX_DIR__/out/out",
Colin Cross2a076922018-10-04 23:28:25 -0700209 },
210 {
211 name: "tool file fg",
212 prop: `
213 tool_files: [":1tool_file"],
214 out: ["out"],
Colin Cross08f15ab2018-10-04 23:29:14 -0700215 cmd: "$(location :1tool_file) > $(out)",
Colin Cross2a076922018-10-04 23:28:25 -0700216 `,
Colin Crossba9e4032020-11-24 16:32:22 -0800217 expect: "__SBOX_SANDBOX_DIR__/tools/src/tool_file1 > __SBOX_SANDBOX_DIR__/out/out",
Colin Cross2a076922018-10-04 23:28:25 -0700218 },
219 {
220 name: "tool files",
221 prop: `
222 tool_files: [":tool_files"],
223 out: ["out"],
Colin Cross08f15ab2018-10-04 23:29:14 -0700224 cmd: "$(locations :tool_files) > $(out)",
Colin Cross2a076922018-10-04 23:28:25 -0700225 `,
Colin Crossba9e4032020-11-24 16:32:22 -0800226 expect: "__SBOX_SANDBOX_DIR__/tools/src/tool_file1 __SBOX_SANDBOX_DIR__/tools/src/tool_file2 > __SBOX_SANDBOX_DIR__/out/out",
Colin Cross2a076922018-10-04 23:28:25 -0700227 },
228 {
229 name: "in1",
230 prop: `
231 srcs: ["in1"],
232 out: ["out"],
233 cmd: "cat $(in) > $(out)",
234 `,
Colin Crosse16ce362020-11-12 08:29:30 -0800235 expect: "cat in1 > __SBOX_SANDBOX_DIR__/out/out",
Colin Cross2a076922018-10-04 23:28:25 -0700236 },
237 {
238 name: "in1 fg",
239 prop: `
240 srcs: [":1in"],
241 out: ["out"],
242 cmd: "cat $(in) > $(out)",
243 `,
Colin Crosse16ce362020-11-12 08:29:30 -0800244 expect: "cat in1 > __SBOX_SANDBOX_DIR__/out/out",
Colin Cross2a076922018-10-04 23:28:25 -0700245 },
246 {
247 name: "ins",
248 prop: `
249 srcs: ["in1", "in2"],
250 out: ["out"],
251 cmd: "cat $(in) > $(out)",
252 `,
Colin Crosse16ce362020-11-12 08:29:30 -0800253 expect: "cat in1 in2 > __SBOX_SANDBOX_DIR__/out/out",
Colin Cross2a076922018-10-04 23:28:25 -0700254 },
255 {
256 name: "ins fg",
257 prop: `
258 srcs: [":ins"],
259 out: ["out"],
260 cmd: "cat $(in) > $(out)",
261 `,
Colin Crosse16ce362020-11-12 08:29:30 -0800262 expect: "cat in1 in2 > __SBOX_SANDBOX_DIR__/out/out",
Colin Cross2a076922018-10-04 23:28:25 -0700263 },
264 {
Colin Cross08f15ab2018-10-04 23:29:14 -0700265 name: "location in1",
266 prop: `
267 srcs: ["in1"],
268 out: ["out"],
269 cmd: "cat $(location in1) > $(out)",
270 `,
Colin Crosse16ce362020-11-12 08:29:30 -0800271 expect: "cat in1 > __SBOX_SANDBOX_DIR__/out/out",
Colin Cross08f15ab2018-10-04 23:29:14 -0700272 },
273 {
274 name: "location in1 fg",
275 prop: `
276 srcs: [":1in"],
277 out: ["out"],
278 cmd: "cat $(location :1in) > $(out)",
279 `,
Colin Crosse16ce362020-11-12 08:29:30 -0800280 expect: "cat in1 > __SBOX_SANDBOX_DIR__/out/out",
Colin Cross08f15ab2018-10-04 23:29:14 -0700281 },
282 {
283 name: "location ins",
284 prop: `
285 srcs: ["in1", "in2"],
286 out: ["out"],
287 cmd: "cat $(location in1) > $(out)",
288 `,
Colin Crosse16ce362020-11-12 08:29:30 -0800289 expect: "cat in1 > __SBOX_SANDBOX_DIR__/out/out",
Colin Cross08f15ab2018-10-04 23:29:14 -0700290 },
291 {
292 name: "location ins fg",
293 prop: `
294 srcs: [":ins"],
295 out: ["out"],
296 cmd: "cat $(locations :ins) > $(out)",
297 `,
Colin Crosse16ce362020-11-12 08:29:30 -0800298 expect: "cat in1 in2 > __SBOX_SANDBOX_DIR__/out/out",
Colin Cross08f15ab2018-10-04 23:29:14 -0700299 },
300 {
Colin Cross2a076922018-10-04 23:28:25 -0700301 name: "outs",
302 prop: `
303 out: ["out", "out2"],
304 cmd: "echo foo > $(out)",
305 `,
Colin Crosse16ce362020-11-12 08:29:30 -0800306 expect: "echo foo > __SBOX_SANDBOX_DIR__/out/out __SBOX_SANDBOX_DIR__/out/out2",
Colin Cross2a076922018-10-04 23:28:25 -0700307 },
308 {
Colin Cross08f15ab2018-10-04 23:29:14 -0700309 name: "location out",
310 prop: `
311 out: ["out", "out2"],
312 cmd: "echo foo > $(location out2)",
313 `,
Colin Crosse16ce362020-11-12 08:29:30 -0800314 expect: "echo foo > __SBOX_SANDBOX_DIR__/out/out2",
Colin Cross08f15ab2018-10-04 23:29:14 -0700315 },
316 {
Colin Cross2a076922018-10-04 23:28:25 -0700317 name: "depfile",
318 prop: `
319 out: ["out"],
320 depfile: true,
321 cmd: "echo foo > $(out) && touch $(depfile)",
322 `,
Colin Crosse16ce362020-11-12 08:29:30 -0800323 expect: "echo foo > __SBOX_SANDBOX_DIR__/out/out && touch __SBOX_DEPFILE__",
Colin Cross2a076922018-10-04 23:28:25 -0700324 },
325 {
326 name: "gendir",
327 prop: `
328 out: ["out"],
329 cmd: "echo foo > $(genDir)/foo && cp $(genDir)/foo $(out)",
330 `,
Colin Crosse16ce362020-11-12 08:29:30 -0800331 expect: "echo foo > __SBOX_SANDBOX_DIR__/out/foo && cp __SBOX_SANDBOX_DIR__/out/foo __SBOX_SANDBOX_DIR__/out/out",
Colin Cross2a076922018-10-04 23:28:25 -0700332 },
333
334 {
335 name: "error empty location",
336 prop: `
337 out: ["out"],
338 cmd: "$(location) > $(out)",
339 `,
340 err: "at least one `tools` or `tool_files` is required if $(location) is used",
341 },
342 {
Colin Cross08f15ab2018-10-04 23:29:14 -0700343 name: "error empty location no files",
344 prop: `
345 tool_files: [":empty"],
346 out: ["out"],
347 cmd: "$(location) > $(out)",
348 `,
349 err: `default label ":empty" has no files`,
350 },
351 {
352 name: "error empty location multiple files",
353 prop: `
354 tool_files: [":tool_files"],
355 out: ["out"],
356 cmd: "$(location) > $(out)",
357 `,
358 err: `default label ":tool_files" has multiple files`,
359 },
360 {
Colin Cross2a076922018-10-04 23:28:25 -0700361 name: "error location",
362 prop: `
363 out: ["out"],
364 cmd: "echo foo > $(location missing)",
365 `,
366 err: `unknown location label "missing"`,
367 },
368 {
Colin Cross08f15ab2018-10-04 23:29:14 -0700369 name: "error locations",
370 prop: `
371 out: ["out"],
372 cmd: "echo foo > $(locations missing)",
373 `,
374 err: `unknown locations label "missing"`,
375 },
376 {
377 name: "error location no files",
378 prop: `
379 out: ["out"],
380 srcs: [":empty"],
381 cmd: "echo $(location :empty) > $(out)",
382 `,
383 err: `label ":empty" has no files`,
384 },
385 {
386 name: "error locations no files",
387 prop: `
388 out: ["out"],
389 srcs: [":empty"],
390 cmd: "echo $(locations :empty) > $(out)",
391 `,
392 err: `label ":empty" has no files`,
393 },
394 {
395 name: "error location multiple files",
396 prop: `
397 out: ["out"],
398 srcs: [":ins"],
399 cmd: "echo $(location :ins) > $(out)",
400 `,
401 err: `label ":ins" has multiple files`,
402 },
403 {
Colin Cross2a076922018-10-04 23:28:25 -0700404 name: "error variable",
405 prop: `
406 out: ["out"],
407 srcs: ["in1"],
408 cmd: "echo $(foo) > $(out)",
409 `,
410 err: `unknown variable '$(foo)'`,
411 },
412 {
413 name: "error depfile",
414 prop: `
415 out: ["out"],
416 cmd: "echo foo > $(out) && touch $(depfile)",
417 `,
418 err: "$(depfile) used without depfile property",
419 },
420 {
421 name: "error no depfile",
422 prop: `
423 out: ["out"],
424 depfile: true,
425 cmd: "echo foo > $(out)",
426 `,
427 err: "specified depfile=true but did not include a reference to '${depfile}' in cmd",
428 },
429 {
430 name: "error no out",
431 prop: `
432 cmd: "echo foo > $(out)",
433 `,
434 err: "must have at least one output file",
435 },
Colin Crossba71a3f2019-03-18 12:12:48 -0700436 {
437 name: "srcs allow missing dependencies",
438 prop: `
439 srcs: [":missing"],
440 out: ["out"],
441 cmd: "cat $(location :missing) > $(out)",
442 `,
443
444 allowMissingDependencies: true,
445
Colin Crosse16ce362020-11-12 08:29:30 -0800446 expect: "cat ***missing srcs :missing*** > __SBOX_SANDBOX_DIR__/out/out",
Colin Crossba71a3f2019-03-18 12:12:48 -0700447 },
448 {
449 name: "tool allow missing dependencies",
450 prop: `
451 tools: [":missing"],
452 out: ["out"],
453 cmd: "$(location :missing) > $(out)",
454 `,
455
456 allowMissingDependencies: true,
457
Colin Crosse16ce362020-11-12 08:29:30 -0800458 expect: "***missing tool :missing*** > __SBOX_SANDBOX_DIR__/out/out",
Colin Crossba71a3f2019-03-18 12:12:48 -0700459 },
Colin Cross2a076922018-10-04 23:28:25 -0700460 }
461
462 for _, test := range testcases {
463 t.Run(test.name, func(t *testing.T) {
Colin Cross2a076922018-10-04 23:28:25 -0700464 bp := "genrule {\n"
465 bp += "name: \"gen\",\n"
466 bp += test.prop
467 bp += "}\n"
468
Colin Cross98be1bb2019-12-13 20:41:13 -0800469 config := testConfig(bp, nil)
Colin Crossba71a3f2019-03-18 12:12:48 -0700470 config.TestProductVariables.Allow_missing_dependencies = proptools.BoolPtr(test.allowMissingDependencies)
471
Colin Cross98be1bb2019-12-13 20:41:13 -0800472 ctx := testContext(config)
Colin Crossba71a3f2019-03-18 12:12:48 -0700473 ctx.SetAllowMissingDependencies(test.allowMissingDependencies)
Colin Cross2a076922018-10-04 23:28:25 -0700474
475 _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
476 if errs == nil {
477 _, errs = ctx.PrepareBuildActions(config)
478 }
479 if errs == nil && test.err != "" {
480 t.Fatalf("want error %q, got no error", test.err)
481 } else if errs != nil && test.err == "" {
482 android.FailIfErrored(t, errs)
483 } else if test.err != "" {
484 if len(errs) != 1 {
485 t.Errorf("want 1 error, got %d errors:", len(errs))
486 for _, err := range errs {
487 t.Errorf(" %s", err.Error())
488 }
489 t.FailNow()
490 }
491 if !strings.Contains(errs[0].Error(), test.err) {
492 t.Fatalf("want %q, got %q", test.err, errs[0].Error())
493 }
494 return
495 }
496
497 gen := ctx.ModuleForTests("gen", "").Module().(*Module)
Colin Cross3d680512020-11-13 16:23:53 -0800498 if g, w := gen.rawCommands[0], test.expect; w != g {
Colin Crossba71a3f2019-03-18 12:12:48 -0700499 t.Errorf("want %q, got %q", w, g)
Colin Cross2a076922018-10-04 23:28:25 -0700500 }
501 })
502 }
Colin Cross1a527682019-09-23 15:55:30 -0700503}
504
Bill Peckhamc087be12020-02-13 15:55:10 -0800505func TestGenruleHashInputs(t *testing.T) {
506
507 // The basic idea here is to verify that the sbox command (which is
508 // in the Command field of the generate rule) contains a hash of the
509 // inputs, but only if $(in) is not referenced in the genrule cmd
510 // property.
511
512 // By including a hash of the inputs, we cause the rule to re-run if
513 // the list of inputs changes (because the sbox command changes).
514
515 // However, if the genrule cmd property already contains $(in), then
516 // the dependency is already expressed, so we don't need to include the
517 // hash in that case.
518
519 bp := `
520 genrule {
521 name: "hash0",
522 srcs: ["in1.txt", "in2.txt"],
523 out: ["out"],
524 cmd: "echo foo > $(out)",
525 }
526 genrule {
527 name: "hash1",
528 srcs: ["*.txt"],
529 out: ["out"],
530 cmd: "echo bar > $(out)",
531 }
532 genrule {
533 name: "hash2",
534 srcs: ["*.txt"],
535 out: ["out"],
536 cmd: "echo $(in) > $(out)",
537 }
538 `
539 testcases := []struct {
540 name string
541 expectedHash string
542 }{
543 {
544 name: "hash0",
Colin Cross3d680512020-11-13 16:23:53 -0800545 // sha256 value obtained from: echo -en 'in1.txt\nin2.txt' | sha256sum
546 expectedHash: "18da75b9b1cc74b09e365b4ca2e321b5d618f438cc632b387ad9dc2ab4b20e9d",
Bill Peckhamc087be12020-02-13 15:55:10 -0800547 },
548 {
549 name: "hash1",
Colin Cross3d680512020-11-13 16:23:53 -0800550 // sha256 value obtained from: echo -en 'in1.txt\nin2.txt\nin3.txt' | sha256sum
551 expectedHash: "a38d432a4b19df93140e1f1fe26c97ff0387dae01fe506412b47208f0595fb45",
Bill Peckhamc087be12020-02-13 15:55:10 -0800552 },
553 {
554 name: "hash2",
Colin Cross3d680512020-11-13 16:23:53 -0800555 // sha256 value obtained from: echo -en 'in1.txt\nin2.txt\nin3.txt' | sha256sum
556 expectedHash: "a38d432a4b19df93140e1f1fe26c97ff0387dae01fe506412b47208f0595fb45",
Bill Peckhamc087be12020-02-13 15:55:10 -0800557 },
558 }
559
560 config := testConfig(bp, nil)
561 ctx := testContext(config)
562 _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
563 if errs == nil {
564 _, errs = ctx.PrepareBuildActions(config)
565 }
566 if errs != nil {
567 t.Fatal(errs)
568 }
569
570 for _, test := range testcases {
571 t.Run(test.name, func(t *testing.T) {
572 gen := ctx.ModuleForTests(test.name, "")
Colin Crosse16ce362020-11-12 08:29:30 -0800573 manifest := android.RuleBuilderSboxProtoForTests(t, gen.Output("genrule.sbox.textproto"))
574 hash := manifest.Commands[0].GetInputHash()
Bill Peckhamc087be12020-02-13 15:55:10 -0800575
Colin Crosse16ce362020-11-12 08:29:30 -0800576 if g, w := hash, test.expectedHash; g != w {
577 t.Errorf("Expected has %q, got %q", w, g)
Bill Peckhamc087be12020-02-13 15:55:10 -0800578 }
579 })
580 }
581}
582
Colin Cross1a527682019-09-23 15:55:30 -0700583func TestGenSrcs(t *testing.T) {
584 testcases := []struct {
585 name string
586 prop string
587
588 allowMissingDependencies bool
589
590 err string
591 cmds []string
592 deps []string
593 files []string
594 }{
595 {
596 name: "gensrcs",
597 prop: `
598 tools: ["tool"],
599 srcs: ["in1.txt", "in2.txt"],
600 cmd: "$(location) $(in) > $(out)",
601 `,
602 cmds: []string{
Colin Crossba9e4032020-11-24 16:32:22 -0800603 "bash -c '__SBOX_SANDBOX_DIR__/tools/out/bin/tool in1.txt > __SBOX_SANDBOX_DIR__/out/in1.h' && bash -c '__SBOX_SANDBOX_DIR__/tools/out/bin/tool in2.txt > __SBOX_SANDBOX_DIR__/out/in2.h'",
Colin Cross1a527682019-09-23 15:55:30 -0700604 },
605 deps: []string{buildDir + "/.intermediates/gen/gen/gensrcs/in1.h", buildDir + "/.intermediates/gen/gen/gensrcs/in2.h"},
606 files: []string{buildDir + "/.intermediates/gen/gen/gensrcs/in1.h", buildDir + "/.intermediates/gen/gen/gensrcs/in2.h"},
607 },
608 {
609 name: "shards",
610 prop: `
611 tools: ["tool"],
612 srcs: ["in1.txt", "in2.txt", "in3.txt"],
613 cmd: "$(location) $(in) > $(out)",
614 shard_size: 2,
615 `,
616 cmds: []string{
Colin Crossba9e4032020-11-24 16:32:22 -0800617 "bash -c '__SBOX_SANDBOX_DIR__/tools/out/bin/tool in1.txt > __SBOX_SANDBOX_DIR__/out/in1.h' && bash -c '__SBOX_SANDBOX_DIR__/tools/out/bin/tool in2.txt > __SBOX_SANDBOX_DIR__/out/in2.h'",
618 "bash -c '__SBOX_SANDBOX_DIR__/tools/out/bin/tool in3.txt > __SBOX_SANDBOX_DIR__/out/in3.h'",
Colin Cross1a527682019-09-23 15:55:30 -0700619 },
620 deps: []string{buildDir + "/.intermediates/gen/gen/gensrcs/in1.h", buildDir + "/.intermediates/gen/gen/gensrcs/in2.h", buildDir + "/.intermediates/gen/gen/gensrcs/in3.h"},
621 files: []string{buildDir + "/.intermediates/gen/gen/gensrcs/in1.h", buildDir + "/.intermediates/gen/gen/gensrcs/in2.h", buildDir + "/.intermediates/gen/gen/gensrcs/in3.h"},
622 },
623 }
624
625 for _, test := range testcases {
626 t.Run(test.name, func(t *testing.T) {
Colin Cross1a527682019-09-23 15:55:30 -0700627 bp := "gensrcs {\n"
628 bp += `name: "gen",` + "\n"
629 bp += `output_extension: "h",` + "\n"
630 bp += test.prop
631 bp += "}\n"
632
Colin Cross98be1bb2019-12-13 20:41:13 -0800633 config := testConfig(bp, nil)
634 ctx := testContext(config)
Colin Cross1a527682019-09-23 15:55:30 -0700635
636 _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
637 if errs == nil {
638 _, errs = ctx.PrepareBuildActions(config)
639 }
640 if errs == nil && test.err != "" {
641 t.Fatalf("want error %q, got no error", test.err)
642 } else if errs != nil && test.err == "" {
643 android.FailIfErrored(t, errs)
644 } else if test.err != "" {
645 if len(errs) != 1 {
646 t.Errorf("want 1 error, got %d errors:", len(errs))
647 for _, err := range errs {
648 t.Errorf(" %s", err.Error())
649 }
650 t.FailNow()
651 }
652 if !strings.Contains(errs[0].Error(), test.err) {
653 t.Fatalf("want %q, got %q", test.err, errs[0].Error())
654 }
655 return
656 }
657
658 gen := ctx.ModuleForTests("gen", "").Module().(*Module)
659 if g, w := gen.rawCommands, test.cmds; !reflect.DeepEqual(w, g) {
660 t.Errorf("want %q, got %q", w, g)
661 }
662
663 if g, w := gen.outputDeps.Strings(), test.deps; !reflect.DeepEqual(w, g) {
664 t.Errorf("want deps %q, got %q", w, g)
665 }
666
667 if g, w := gen.outputFiles.Strings(), test.files; !reflect.DeepEqual(w, g) {
668 t.Errorf("want files %q, got %q", w, g)
669 }
670 })
671 }
Colin Cross2a076922018-10-04 23:28:25 -0700672
673}
674
Jaewoong Jung98716bd2018-12-10 08:13:18 -0800675func TestGenruleDefaults(t *testing.T) {
Jaewoong Jung98716bd2018-12-10 08:13:18 -0800676 bp := `
677 genrule_defaults {
678 name: "gen_defaults1",
679 cmd: "cp $(in) $(out)",
680 }
681
682 genrule_defaults {
683 name: "gen_defaults2",
684 srcs: ["in1"],
685 }
686
687 genrule {
688 name: "gen",
689 out: ["out"],
690 defaults: ["gen_defaults1", "gen_defaults2"],
691 }
692 `
Colin Cross98be1bb2019-12-13 20:41:13 -0800693 config := testConfig(bp, nil)
694 ctx := testContext(config)
Jaewoong Jung98716bd2018-12-10 08:13:18 -0800695 _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
696 if errs == nil {
697 _, errs = ctx.PrepareBuildActions(config)
698 }
699 if errs != nil {
700 t.Fatal(errs)
701 }
702 gen := ctx.ModuleForTests("gen", "").Module().(*Module)
703
Colin Crosse16ce362020-11-12 08:29:30 -0800704 expectedCmd := "cp in1 __SBOX_SANDBOX_DIR__/out/out"
Colin Cross1a527682019-09-23 15:55:30 -0700705 if gen.rawCommands[0] != expectedCmd {
706 t.Errorf("Expected cmd: %q, actual: %q", expectedCmd, gen.rawCommands[0])
Jaewoong Jung98716bd2018-12-10 08:13:18 -0800707 }
708
709 expectedSrcs := []string{"in1"}
710 if !reflect.DeepEqual(expectedSrcs, gen.properties.Srcs) {
711 t.Errorf("Expected srcs: %q, actual: %q", expectedSrcs, gen.properties.Srcs)
712 }
713}
714
Chris Parsonsf3c96ef2020-09-29 02:23:17 -0400715func TestGenruleWithBazel(t *testing.T) {
716 bp := `
717 genrule {
718 name: "foo",
719 out: ["one.txt", "two.txt"],
Chris Parsonsaa8be052020-10-14 16:22:37 -0400720 bazel_module: { label: "//foo/bar:bar" },
Chris Parsonsf3c96ef2020-09-29 02:23:17 -0400721 }
722 `
723
724 config := testConfig(bp, nil)
725 config.BazelContext = android.MockBazelContext{
726 AllFiles: map[string][]string{
727 "//foo/bar:bar": []string{"bazelone.txt", "bazeltwo.txt"}}}
728
729 ctx := testContext(config)
730 _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
731 if errs == nil {
732 _, errs = ctx.PrepareBuildActions(config)
733 }
734 if errs != nil {
735 t.Fatal(errs)
736 }
737 gen := ctx.ModuleForTests("foo", "").Module().(*Module)
738
Chris Parsonsdbcb1ff2020-12-10 17:19:18 -0500739 expectedOutputFiles := []string{"outputbase/execroot/__main__/bazelone.txt",
740 "outputbase/execroot/__main__/bazeltwo.txt"}
Chris Parsonsf3c96ef2020-09-29 02:23:17 -0400741 if !reflect.DeepEqual(gen.outputFiles.Strings(), expectedOutputFiles) {
742 t.Errorf("Expected output files: %q, actual: %q", expectedOutputFiles, gen.outputFiles)
743 }
744 if !reflect.DeepEqual(gen.outputDeps.Strings(), expectedOutputFiles) {
745 t.Errorf("Expected output deps: %q, actual: %q", expectedOutputFiles, gen.outputDeps)
746 }
747}
748
Colin Cross2a076922018-10-04 23:28:25 -0700749type testTool struct {
750 android.ModuleBase
751 outputFile android.Path
752}
753
754func toolFactory() android.Module {
755 module := &testTool{}
756 android.InitAndroidArchModule(module, android.HostSupported, android.MultilibFirst)
757 return module
758}
759
Colin Cross2a076922018-10-04 23:28:25 -0700760func (t *testTool) GenerateAndroidBuildActions(ctx android.ModuleContext) {
Colin Crossba9e4032020-11-24 16:32:22 -0800761 t.outputFile = ctx.InstallFile(android.PathForModuleInstall(ctx, "bin"), ctx.ModuleName(), android.PathForOutput(ctx, ctx.ModuleName()))
Colin Cross2a076922018-10-04 23:28:25 -0700762}
763
764func (t *testTool) HostToolPath() android.OptionalPath {
765 return android.OptionalPathForPath(t.outputFile)
766}
767
Colin Crossfe17f6f2019-03-28 19:30:56 -0700768var _ android.HostToolProvider = (*testTool)(nil)