blob: 66bb22130aabf0ab68b81f375ac66385cc32a8fb [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
56 ctx := android.NewTestArchContext()
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
60 registerGenruleBuildComponents(ctx)
61
Jaewoong Jung98716bd2018-12-10 08:13:18 -080062 ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
Colin Cross98be1bb2019-12-13 20:41:13 -080063 ctx.Register(config)
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) {
Colin Cross323dc602020-09-18 14:25:31 -0700128 t.Parallel()
Colin Cross2a076922018-10-04 23:28:25 -0700129 testcases := []struct {
130 name string
131 prop string
132
Colin Crossba71a3f2019-03-18 12:12:48 -0700133 allowMissingDependencies bool
134
Colin Cross2a076922018-10-04 23:28:25 -0700135 err string
136 expect string
137 }{
138 {
139 name: "empty location tool",
140 prop: `
141 tools: ["tool"],
142 out: ["out"],
143 cmd: "$(location) > $(out)",
144 `,
145 expect: "out/tool > __SBOX_OUT_FILES__",
146 },
147 {
Colin Cross08f15ab2018-10-04 23:29:14 -0700148 name: "empty location tool2",
149 prop: `
150 tools: [":tool"],
151 out: ["out"],
152 cmd: "$(location) > $(out)",
153 `,
154 expect: "out/tool > __SBOX_OUT_FILES__",
155 },
156 {
Colin Cross2a076922018-10-04 23:28:25 -0700157 name: "empty location tool file",
158 prop: `
159 tool_files: ["tool_file1"],
160 out: ["out"],
161 cmd: "$(location) > $(out)",
162 `,
163 expect: "tool_file1 > __SBOX_OUT_FILES__",
164 },
165 {
166 name: "empty location tool file fg",
167 prop: `
168 tool_files: [":1tool_file"],
169 out: ["out"],
170 cmd: "$(location) > $(out)",
171 `,
172 expect: "tool_file1 > __SBOX_OUT_FILES__",
173 },
174 {
175 name: "empty location tool and tool file",
176 prop: `
177 tools: ["tool"],
178 tool_files: ["tool_file1"],
179 out: ["out"],
180 cmd: "$(location) > $(out)",
181 `,
182 expect: "out/tool > __SBOX_OUT_FILES__",
183 },
184 {
185 name: "tool",
186 prop: `
187 tools: ["tool"],
188 out: ["out"],
189 cmd: "$(location tool) > $(out)",
190 `,
191 expect: "out/tool > __SBOX_OUT_FILES__",
192 },
193 {
Colin Cross08f15ab2018-10-04 23:29:14 -0700194 name: "tool2",
195 prop: `
196 tools: [":tool"],
197 out: ["out"],
198 cmd: "$(location :tool) > $(out)",
199 `,
200 expect: "out/tool > __SBOX_OUT_FILES__",
201 },
202 {
Colin Cross2a076922018-10-04 23:28:25 -0700203 name: "tool file",
204 prop: `
205 tool_files: ["tool_file1"],
206 out: ["out"],
207 cmd: "$(location tool_file1) > $(out)",
208 `,
209 expect: "tool_file1 > __SBOX_OUT_FILES__",
210 },
211 {
212 name: "tool file fg",
213 prop: `
214 tool_files: [":1tool_file"],
215 out: ["out"],
Colin Cross08f15ab2018-10-04 23:29:14 -0700216 cmd: "$(location :1tool_file) > $(out)",
Colin Cross2a076922018-10-04 23:28:25 -0700217 `,
218 expect: "tool_file1 > __SBOX_OUT_FILES__",
219 },
220 {
221 name: "tool files",
222 prop: `
223 tool_files: [":tool_files"],
224 out: ["out"],
Colin Cross08f15ab2018-10-04 23:29:14 -0700225 cmd: "$(locations :tool_files) > $(out)",
Colin Cross2a076922018-10-04 23:28:25 -0700226 `,
227 expect: "tool_file1 tool_file2 > __SBOX_OUT_FILES__",
228 },
229 {
230 name: "in1",
231 prop: `
232 srcs: ["in1"],
233 out: ["out"],
234 cmd: "cat $(in) > $(out)",
235 `,
236 expect: "cat ${in} > __SBOX_OUT_FILES__",
237 },
238 {
239 name: "in1 fg",
240 prop: `
241 srcs: [":1in"],
242 out: ["out"],
243 cmd: "cat $(in) > $(out)",
244 `,
245 expect: "cat ${in} > __SBOX_OUT_FILES__",
246 },
247 {
248 name: "ins",
249 prop: `
250 srcs: ["in1", "in2"],
251 out: ["out"],
252 cmd: "cat $(in) > $(out)",
253 `,
254 expect: "cat ${in} > __SBOX_OUT_FILES__",
255 },
256 {
257 name: "ins fg",
258 prop: `
259 srcs: [":ins"],
260 out: ["out"],
261 cmd: "cat $(in) > $(out)",
262 `,
263 expect: "cat ${in} > __SBOX_OUT_FILES__",
264 },
265 {
Colin Cross08f15ab2018-10-04 23:29:14 -0700266 name: "location in1",
267 prop: `
268 srcs: ["in1"],
269 out: ["out"],
270 cmd: "cat $(location in1) > $(out)",
271 `,
272 expect: "cat in1 > __SBOX_OUT_FILES__",
273 },
274 {
275 name: "location in1 fg",
276 prop: `
277 srcs: [":1in"],
278 out: ["out"],
279 cmd: "cat $(location :1in) > $(out)",
280 `,
281 expect: "cat in1 > __SBOX_OUT_FILES__",
282 },
283 {
284 name: "location ins",
285 prop: `
286 srcs: ["in1", "in2"],
287 out: ["out"],
288 cmd: "cat $(location in1) > $(out)",
289 `,
290 expect: "cat in1 > __SBOX_OUT_FILES__",
291 },
292 {
293 name: "location ins fg",
294 prop: `
295 srcs: [":ins"],
296 out: ["out"],
297 cmd: "cat $(locations :ins) > $(out)",
298 `,
299 expect: "cat in1 in2 > __SBOX_OUT_FILES__",
300 },
301 {
Colin Cross2a076922018-10-04 23:28:25 -0700302 name: "outs",
303 prop: `
304 out: ["out", "out2"],
305 cmd: "echo foo > $(out)",
306 `,
307 expect: "echo foo > __SBOX_OUT_FILES__",
308 },
309 {
Colin Cross08f15ab2018-10-04 23:29:14 -0700310 name: "location out",
311 prop: `
312 out: ["out", "out2"],
313 cmd: "echo foo > $(location out2)",
314 `,
315 expect: "echo foo > __SBOX_OUT_DIR__/out2",
316 },
317 {
Colin Cross2a076922018-10-04 23:28:25 -0700318 name: "depfile",
319 prop: `
320 out: ["out"],
321 depfile: true,
322 cmd: "echo foo > $(out) && touch $(depfile)",
323 `,
324 expect: "echo foo > __SBOX_OUT_FILES__ && touch __SBOX_DEPFILE__",
325 },
326 {
327 name: "gendir",
328 prop: `
329 out: ["out"],
330 cmd: "echo foo > $(genDir)/foo && cp $(genDir)/foo $(out)",
331 `,
332 expect: "echo foo > __SBOX_OUT_DIR__/foo && cp __SBOX_OUT_DIR__/foo __SBOX_OUT_FILES__",
333 },
334
335 {
336 name: "error empty location",
337 prop: `
338 out: ["out"],
339 cmd: "$(location) > $(out)",
340 `,
341 err: "at least one `tools` or `tool_files` is required if $(location) is used",
342 },
343 {
Colin Cross08f15ab2018-10-04 23:29:14 -0700344 name: "error empty location no files",
345 prop: `
346 tool_files: [":empty"],
347 out: ["out"],
348 cmd: "$(location) > $(out)",
349 `,
350 err: `default label ":empty" has no files`,
351 },
352 {
353 name: "error empty location multiple files",
354 prop: `
355 tool_files: [":tool_files"],
356 out: ["out"],
357 cmd: "$(location) > $(out)",
358 `,
359 err: `default label ":tool_files" has multiple files`,
360 },
361 {
Colin Cross2a076922018-10-04 23:28:25 -0700362 name: "error location",
363 prop: `
364 out: ["out"],
365 cmd: "echo foo > $(location missing)",
366 `,
367 err: `unknown location label "missing"`,
368 },
369 {
Colin Cross08f15ab2018-10-04 23:29:14 -0700370 name: "error locations",
371 prop: `
372 out: ["out"],
373 cmd: "echo foo > $(locations missing)",
374 `,
375 err: `unknown locations label "missing"`,
376 },
377 {
378 name: "error location no files",
379 prop: `
380 out: ["out"],
381 srcs: [":empty"],
382 cmd: "echo $(location :empty) > $(out)",
383 `,
384 err: `label ":empty" has no files`,
385 },
386 {
387 name: "error locations no files",
388 prop: `
389 out: ["out"],
390 srcs: [":empty"],
391 cmd: "echo $(locations :empty) > $(out)",
392 `,
393 err: `label ":empty" has no files`,
394 },
395 {
396 name: "error location multiple files",
397 prop: `
398 out: ["out"],
399 srcs: [":ins"],
400 cmd: "echo $(location :ins) > $(out)",
401 `,
402 err: `label ":ins" has multiple files`,
403 },
404 {
Colin Cross2a076922018-10-04 23:28:25 -0700405 name: "error variable",
406 prop: `
407 out: ["out"],
408 srcs: ["in1"],
409 cmd: "echo $(foo) > $(out)",
410 `,
411 err: `unknown variable '$(foo)'`,
412 },
413 {
414 name: "error depfile",
415 prop: `
416 out: ["out"],
417 cmd: "echo foo > $(out) && touch $(depfile)",
418 `,
419 err: "$(depfile) used without depfile property",
420 },
421 {
422 name: "error no depfile",
423 prop: `
424 out: ["out"],
425 depfile: true,
426 cmd: "echo foo > $(out)",
427 `,
428 err: "specified depfile=true but did not include a reference to '${depfile}' in cmd",
429 },
430 {
431 name: "error no out",
432 prop: `
433 cmd: "echo foo > $(out)",
434 `,
435 err: "must have at least one output file",
436 },
Colin Crossba71a3f2019-03-18 12:12:48 -0700437 {
438 name: "srcs allow missing dependencies",
439 prop: `
440 srcs: [":missing"],
441 out: ["out"],
442 cmd: "cat $(location :missing) > $(out)",
443 `,
444
445 allowMissingDependencies: true,
446
447 expect: "cat ***missing srcs :missing*** > __SBOX_OUT_FILES__",
448 },
449 {
450 name: "tool allow missing dependencies",
451 prop: `
452 tools: [":missing"],
453 out: ["out"],
454 cmd: "$(location :missing) > $(out)",
455 `,
456
457 allowMissingDependencies: true,
458
459 expect: "***missing tool :missing*** > __SBOX_OUT_FILES__",
460 },
Colin Cross2a076922018-10-04 23:28:25 -0700461 }
462
463 for _, test := range testcases {
464 t.Run(test.name, func(t *testing.T) {
Colin Cross2a076922018-10-04 23:28:25 -0700465 bp := "genrule {\n"
466 bp += "name: \"gen\",\n"
467 bp += test.prop
468 bp += "}\n"
469
Colin Cross98be1bb2019-12-13 20:41:13 -0800470 config := testConfig(bp, nil)
Colin Crossba71a3f2019-03-18 12:12:48 -0700471 config.TestProductVariables.Allow_missing_dependencies = proptools.BoolPtr(test.allowMissingDependencies)
472
Colin Cross98be1bb2019-12-13 20:41:13 -0800473 ctx := testContext(config)
Colin Crossba71a3f2019-03-18 12:12:48 -0700474 ctx.SetAllowMissingDependencies(test.allowMissingDependencies)
Colin Cross2a076922018-10-04 23:28:25 -0700475
476 _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
477 if errs == nil {
478 _, errs = ctx.PrepareBuildActions(config)
479 }
480 if errs == nil && test.err != "" {
481 t.Fatalf("want error %q, got no error", test.err)
482 } else if errs != nil && test.err == "" {
483 android.FailIfErrored(t, errs)
484 } else if test.err != "" {
485 if len(errs) != 1 {
486 t.Errorf("want 1 error, got %d errors:", len(errs))
487 for _, err := range errs {
488 t.Errorf(" %s", err.Error())
489 }
490 t.FailNow()
491 }
492 if !strings.Contains(errs[0].Error(), test.err) {
493 t.Fatalf("want %q, got %q", test.err, errs[0].Error())
494 }
495 return
496 }
497
498 gen := ctx.ModuleForTests("gen", "").Module().(*Module)
Colin Cross1a527682019-09-23 15:55:30 -0700499 if g, w := gen.rawCommands[0], "'"+test.expect+"'"; w != g {
Colin Crossba71a3f2019-03-18 12:12:48 -0700500 t.Errorf("want %q, got %q", w, g)
Colin Cross2a076922018-10-04 23:28:25 -0700501 }
502 })
503 }
Colin Cross1a527682019-09-23 15:55:30 -0700504}
505
Bill Peckhamc087be12020-02-13 15:55:10 -0800506func TestGenruleHashInputs(t *testing.T) {
Colin Cross323dc602020-09-18 14:25:31 -0700507 t.Parallel()
Bill Peckhamc087be12020-02-13 15:55:10 -0800508
509 // The basic idea here is to verify that the sbox command (which is
510 // in the Command field of the generate rule) contains a hash of the
511 // inputs, but only if $(in) is not referenced in the genrule cmd
512 // property.
513
514 // By including a hash of the inputs, we cause the rule to re-run if
515 // the list of inputs changes (because the sbox command changes).
516
517 // However, if the genrule cmd property already contains $(in), then
518 // the dependency is already expressed, so we don't need to include the
519 // hash in that case.
520
521 bp := `
522 genrule {
523 name: "hash0",
524 srcs: ["in1.txt", "in2.txt"],
525 out: ["out"],
526 cmd: "echo foo > $(out)",
527 }
528 genrule {
529 name: "hash1",
530 srcs: ["*.txt"],
531 out: ["out"],
532 cmd: "echo bar > $(out)",
533 }
534 genrule {
535 name: "hash2",
536 srcs: ["*.txt"],
537 out: ["out"],
538 cmd: "echo $(in) > $(out)",
539 }
540 `
541 testcases := []struct {
542 name string
543 expectedHash string
544 }{
545 {
546 name: "hash0",
547 // sha256 value obtained from: echo -n 'in1.txtin2.txt' | sha256sum
548 expectedHash: "031097e11e0a8c822c960eb9742474f46336360a515744000d086d94335a9cb9",
549 },
550 {
551 name: "hash1",
552 // sha256 value obtained from: echo -n 'in1.txtin2.txtin3.txt' | sha256sum
553 expectedHash: "de5d22a4a7ab50d250cc59fcdf7a7e0775790d270bfca3a7a9e1f18a70dd996c",
554 },
555 {
556 name: "hash2",
557 // $(in) is present, option should not appear
558 expectedHash: "",
559 },
560 }
561
562 config := testConfig(bp, nil)
563 ctx := testContext(config)
564 _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
565 if errs == nil {
566 _, errs = ctx.PrepareBuildActions(config)
567 }
568 if errs != nil {
569 t.Fatal(errs)
570 }
571
572 for _, test := range testcases {
573 t.Run(test.name, func(t *testing.T) {
574 gen := ctx.ModuleForTests(test.name, "")
575 command := gen.Rule("generator").RuleParams.Command
576
577 if len(test.expectedHash) > 0 {
578 // We add spaces before and after to make sure that
579 // this option doesn't abutt another sbox option.
580 expectedInputHashOption := " --input-hash " + test.expectedHash + " "
581
582 if !strings.Contains(command, expectedInputHashOption) {
583 t.Errorf("Expected command \"%s\" to contain \"%s\"", command, expectedInputHashOption)
584 }
585 } else {
586 if strings.Contains(command, "--input-hash") {
587 t.Errorf("Unexpected \"--input-hash\" found in command: \"%s\"", command)
588 }
589 }
590 })
591 }
592}
593
Colin Cross1a527682019-09-23 15:55:30 -0700594func TestGenSrcs(t *testing.T) {
Colin Cross323dc602020-09-18 14:25:31 -0700595 t.Parallel()
Colin Cross1a527682019-09-23 15:55:30 -0700596 testcases := []struct {
597 name string
598 prop string
599
600 allowMissingDependencies bool
601
602 err string
603 cmds []string
604 deps []string
605 files []string
606 }{
607 {
608 name: "gensrcs",
609 prop: `
610 tools: ["tool"],
611 srcs: ["in1.txt", "in2.txt"],
612 cmd: "$(location) $(in) > $(out)",
613 `,
614 cmds: []string{
615 "'bash -c '\\''out/tool in1.txt > __SBOX_OUT_DIR__/in1.h'\\'' && bash -c '\\''out/tool in2.txt > __SBOX_OUT_DIR__/in2.h'\\'''",
616 },
617 deps: []string{buildDir + "/.intermediates/gen/gen/gensrcs/in1.h", buildDir + "/.intermediates/gen/gen/gensrcs/in2.h"},
618 files: []string{buildDir + "/.intermediates/gen/gen/gensrcs/in1.h", buildDir + "/.intermediates/gen/gen/gensrcs/in2.h"},
619 },
620 {
621 name: "shards",
622 prop: `
623 tools: ["tool"],
624 srcs: ["in1.txt", "in2.txt", "in3.txt"],
625 cmd: "$(location) $(in) > $(out)",
626 shard_size: 2,
627 `,
628 cmds: []string{
629 "'bash -c '\\''out/tool in1.txt > __SBOX_OUT_DIR__/in1.h'\\'' && bash -c '\\''out/tool in2.txt > __SBOX_OUT_DIR__/in2.h'\\'''",
630 "'bash -c '\\''out/tool in3.txt > __SBOX_OUT_DIR__/in3.h'\\'''",
631 },
632 deps: []string{buildDir + "/.intermediates/gen/gen/gensrcs/in1.h", buildDir + "/.intermediates/gen/gen/gensrcs/in2.h", buildDir + "/.intermediates/gen/gen/gensrcs/in3.h"},
633 files: []string{buildDir + "/.intermediates/gen/gen/gensrcs/in1.h", buildDir + "/.intermediates/gen/gen/gensrcs/in2.h", buildDir + "/.intermediates/gen/gen/gensrcs/in3.h"},
634 },
635 }
636
637 for _, test := range testcases {
638 t.Run(test.name, func(t *testing.T) {
Colin Cross1a527682019-09-23 15:55:30 -0700639 bp := "gensrcs {\n"
640 bp += `name: "gen",` + "\n"
641 bp += `output_extension: "h",` + "\n"
642 bp += test.prop
643 bp += "}\n"
644
Colin Cross98be1bb2019-12-13 20:41:13 -0800645 config := testConfig(bp, nil)
646 ctx := testContext(config)
Colin Cross1a527682019-09-23 15:55:30 -0700647
648 _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
649 if errs == nil {
650 _, errs = ctx.PrepareBuildActions(config)
651 }
652 if errs == nil && test.err != "" {
653 t.Fatalf("want error %q, got no error", test.err)
654 } else if errs != nil && test.err == "" {
655 android.FailIfErrored(t, errs)
656 } else if test.err != "" {
657 if len(errs) != 1 {
658 t.Errorf("want 1 error, got %d errors:", len(errs))
659 for _, err := range errs {
660 t.Errorf(" %s", err.Error())
661 }
662 t.FailNow()
663 }
664 if !strings.Contains(errs[0].Error(), test.err) {
665 t.Fatalf("want %q, got %q", test.err, errs[0].Error())
666 }
667 return
668 }
669
670 gen := ctx.ModuleForTests("gen", "").Module().(*Module)
671 if g, w := gen.rawCommands, test.cmds; !reflect.DeepEqual(w, g) {
672 t.Errorf("want %q, got %q", w, g)
673 }
674
675 if g, w := gen.outputDeps.Strings(), test.deps; !reflect.DeepEqual(w, g) {
676 t.Errorf("want deps %q, got %q", w, g)
677 }
678
679 if g, w := gen.outputFiles.Strings(), test.files; !reflect.DeepEqual(w, g) {
680 t.Errorf("want files %q, got %q", w, g)
681 }
682 })
683 }
Colin Cross2a076922018-10-04 23:28:25 -0700684
685}
686
Jaewoong Jung98716bd2018-12-10 08:13:18 -0800687func TestGenruleDefaults(t *testing.T) {
Colin Cross323dc602020-09-18 14:25:31 -0700688 t.Parallel()
Jaewoong Jung98716bd2018-12-10 08:13:18 -0800689 bp := `
690 genrule_defaults {
691 name: "gen_defaults1",
692 cmd: "cp $(in) $(out)",
693 }
694
695 genrule_defaults {
696 name: "gen_defaults2",
697 srcs: ["in1"],
698 }
699
700 genrule {
701 name: "gen",
702 out: ["out"],
703 defaults: ["gen_defaults1", "gen_defaults2"],
704 }
705 `
Colin Cross98be1bb2019-12-13 20:41:13 -0800706 config := testConfig(bp, nil)
707 ctx := testContext(config)
Jaewoong Jung98716bd2018-12-10 08:13:18 -0800708 _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
709 if errs == nil {
710 _, errs = ctx.PrepareBuildActions(config)
711 }
712 if errs != nil {
713 t.Fatal(errs)
714 }
715 gen := ctx.ModuleForTests("gen", "").Module().(*Module)
716
717 expectedCmd := "'cp ${in} __SBOX_OUT_FILES__'"
Colin Cross1a527682019-09-23 15:55:30 -0700718 if gen.rawCommands[0] != expectedCmd {
719 t.Errorf("Expected cmd: %q, actual: %q", expectedCmd, gen.rawCommands[0])
Jaewoong Jung98716bd2018-12-10 08:13:18 -0800720 }
721
722 expectedSrcs := []string{"in1"}
723 if !reflect.DeepEqual(expectedSrcs, gen.properties.Srcs) {
724 t.Errorf("Expected srcs: %q, actual: %q", expectedSrcs, gen.properties.Srcs)
725 }
726}
727
Colin Cross2a076922018-10-04 23:28:25 -0700728type testTool struct {
729 android.ModuleBase
730 outputFile android.Path
731}
732
733func toolFactory() android.Module {
734 module := &testTool{}
735 android.InitAndroidArchModule(module, android.HostSupported, android.MultilibFirst)
736 return module
737}
738
Colin Cross2a076922018-10-04 23:28:25 -0700739func (t *testTool) GenerateAndroidBuildActions(ctx android.ModuleContext) {
740 t.outputFile = android.PathForTesting("out", ctx.ModuleName())
741}
742
743func (t *testTool) HostToolPath() android.OptionalPath {
744 return android.OptionalPathForPath(t.outputFile)
745}
746
Colin Crossfe17f6f2019-03-28 19:30:56 -0700747var _ android.HostToolProvider = (*testTool)(nil)