blob: 04c97fd64b4285c9e965f2e60d7698b411933a0c [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 (
Colin Cross2a076922018-10-04 23:28:25 -070018 "os"
Paul Duffin672cb9f2021-03-03 02:30:37 +000019 "regexp"
Colin Cross2a076922018-10-04 23:28:25 -070020 "testing"
21
22 "android/soong/android"
Colin Crossba71a3f2019-03-18 12:12:48 -070023
24 "github.com/google/blueprint/proptools"
Colin Cross2a076922018-10-04 23:28:25 -070025)
26
Colin Cross2a076922018-10-04 23:28:25 -070027func TestMain(m *testing.M) {
Paul Duffine66946b2021-03-16 12:38:33 +000028 os.Exit(m.Run())
Colin Cross2a076922018-10-04 23:28:25 -070029}
30
Paul Duffin89648f92021-03-20 00:36:55 +000031var prepareForGenRuleTest = android.GroupFixturePreparers(
Paul Duffin672cb9f2021-03-03 02:30:37 +000032 android.PrepareForTestWithArchMutator,
33 android.PrepareForTestWithDefaults,
Paul Duffin672cb9f2021-03-03 02:30:37 +000034 android.PrepareForTestWithFilegroup,
35 PrepareForTestWithGenRuleBuildComponents,
36 android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
Martin Stjernholmdbd814d2022-01-12 23:18:30 +000037 android.RegisterPrebuiltMutators(ctx)
Paul Duffin672cb9f2021-03-03 02:30:37 +000038 ctx.RegisterModuleType("tool", toolFactory)
Martin Stjernholmdbd814d2022-01-12 23:18:30 +000039 ctx.RegisterModuleType("prebuilt_tool", prebuiltToolFactory)
Colin Crossfa65cee2021-03-22 17:05:59 -070040 ctx.RegisterModuleType("output", outputProducerFactory)
Jooyung Han8c7e3ed2021-06-28 17:35:58 +090041 ctx.RegisterModuleType("use_source", useSourceFactory)
Paul Duffin672cb9f2021-03-03 02:30:37 +000042 }),
43 android.FixtureMergeMockFs(android.MockFS{
44 "tool": nil,
45 "tool_file1": nil,
46 "tool_file2": nil,
47 "in1": nil,
48 "in2": nil,
49 "in1.txt": nil,
50 "in2.txt": nil,
51 "in3.txt": nil,
52 }),
53)
Martin Stjernholm710ec3a2020-01-16 15:12:04 +000054
Paul Duffin672cb9f2021-03-03 02:30:37 +000055func testGenruleBp() string {
56 return `
Colin Cross2a076922018-10-04 23:28:25 -070057 tool {
58 name: "tool",
59 }
60
61 filegroup {
62 name: "tool_files",
63 srcs: [
64 "tool_file1",
65 "tool_file2",
66 ],
67 }
68
69 filegroup {
70 name: "1tool_file",
71 srcs: [
72 "tool_file1",
73 ],
74 }
75
76 filegroup {
77 name: "ins",
78 srcs: [
79 "in1",
80 "in2",
81 ],
82 }
83
84 filegroup {
85 name: "1in",
86 srcs: [
87 "in1",
88 ],
89 }
90
91 filegroup {
92 name: "empty",
93 }
94 `
Colin Cross2a076922018-10-04 23:28:25 -070095}
96
97func TestGenruleCmd(t *testing.T) {
98 testcases := []struct {
99 name string
100 prop string
101
Colin Crossba71a3f2019-03-18 12:12:48 -0700102 allowMissingDependencies bool
103
Colin Cross2a076922018-10-04 23:28:25 -0700104 err string
105 expect string
106 }{
107 {
108 name: "empty location tool",
109 prop: `
110 tools: ["tool"],
111 out: ["out"],
112 cmd: "$(location) > $(out)",
113 `,
Colin Crossba9e4032020-11-24 16:32:22 -0800114 expect: "__SBOX_SANDBOX_DIR__/tools/out/bin/tool > __SBOX_SANDBOX_DIR__/out/out",
Colin Cross2a076922018-10-04 23:28:25 -0700115 },
116 {
Colin Cross08f15ab2018-10-04 23:29:14 -0700117 name: "empty location tool2",
118 prop: `
119 tools: [":tool"],
120 out: ["out"],
121 cmd: "$(location) > $(out)",
122 `,
Colin Crossba9e4032020-11-24 16:32:22 -0800123 expect: "__SBOX_SANDBOX_DIR__/tools/out/bin/tool > __SBOX_SANDBOX_DIR__/out/out",
Colin Cross08f15ab2018-10-04 23:29:14 -0700124 },
125 {
Colin Cross2a076922018-10-04 23:28:25 -0700126 name: "empty location tool file",
127 prop: `
128 tool_files: ["tool_file1"],
129 out: ["out"],
130 cmd: "$(location) > $(out)",
131 `,
Colin Crossba9e4032020-11-24 16:32:22 -0800132 expect: "__SBOX_SANDBOX_DIR__/tools/src/tool_file1 > __SBOX_SANDBOX_DIR__/out/out",
Colin Cross2a076922018-10-04 23:28:25 -0700133 },
134 {
135 name: "empty location tool file fg",
136 prop: `
137 tool_files: [":1tool_file"],
138 out: ["out"],
139 cmd: "$(location) > $(out)",
140 `,
Colin Crossba9e4032020-11-24 16:32:22 -0800141 expect: "__SBOX_SANDBOX_DIR__/tools/src/tool_file1 > __SBOX_SANDBOX_DIR__/out/out",
Colin Cross2a076922018-10-04 23:28:25 -0700142 },
143 {
144 name: "empty location tool and tool file",
145 prop: `
146 tools: ["tool"],
147 tool_files: ["tool_file1"],
148 out: ["out"],
149 cmd: "$(location) > $(out)",
150 `,
Colin Crossba9e4032020-11-24 16:32:22 -0800151 expect: "__SBOX_SANDBOX_DIR__/tools/out/bin/tool > __SBOX_SANDBOX_DIR__/out/out",
Colin Cross2a076922018-10-04 23:28:25 -0700152 },
153 {
154 name: "tool",
155 prop: `
156 tools: ["tool"],
157 out: ["out"],
158 cmd: "$(location tool) > $(out)",
159 `,
Colin Crossba9e4032020-11-24 16:32:22 -0800160 expect: "__SBOX_SANDBOX_DIR__/tools/out/bin/tool > __SBOX_SANDBOX_DIR__/out/out",
Colin Cross2a076922018-10-04 23:28:25 -0700161 },
162 {
Colin Cross08f15ab2018-10-04 23:29:14 -0700163 name: "tool2",
164 prop: `
165 tools: [":tool"],
166 out: ["out"],
167 cmd: "$(location :tool) > $(out)",
168 `,
Colin Crossba9e4032020-11-24 16:32:22 -0800169 expect: "__SBOX_SANDBOX_DIR__/tools/out/bin/tool > __SBOX_SANDBOX_DIR__/out/out",
Colin Cross08f15ab2018-10-04 23:29:14 -0700170 },
171 {
Colin Cross2a076922018-10-04 23:28:25 -0700172 name: "tool file",
173 prop: `
174 tool_files: ["tool_file1"],
175 out: ["out"],
176 cmd: "$(location tool_file1) > $(out)",
177 `,
Colin Crossba9e4032020-11-24 16:32:22 -0800178 expect: "__SBOX_SANDBOX_DIR__/tools/src/tool_file1 > __SBOX_SANDBOX_DIR__/out/out",
Colin Cross2a076922018-10-04 23:28:25 -0700179 },
180 {
181 name: "tool file fg",
182 prop: `
183 tool_files: [":1tool_file"],
184 out: ["out"],
Colin Cross08f15ab2018-10-04 23:29:14 -0700185 cmd: "$(location :1tool_file) > $(out)",
Colin Cross2a076922018-10-04 23:28:25 -0700186 `,
Colin Crossba9e4032020-11-24 16:32:22 -0800187 expect: "__SBOX_SANDBOX_DIR__/tools/src/tool_file1 > __SBOX_SANDBOX_DIR__/out/out",
Colin Cross2a076922018-10-04 23:28:25 -0700188 },
189 {
190 name: "tool files",
191 prop: `
192 tool_files: [":tool_files"],
193 out: ["out"],
Colin Cross08f15ab2018-10-04 23:29:14 -0700194 cmd: "$(locations :tool_files) > $(out)",
Colin Cross2a076922018-10-04 23:28:25 -0700195 `,
Colin Crossba9e4032020-11-24 16:32:22 -0800196 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 -0700197 },
198 {
199 name: "in1",
200 prop: `
201 srcs: ["in1"],
202 out: ["out"],
203 cmd: "cat $(in) > $(out)",
204 `,
Colin Crosse16ce362020-11-12 08:29:30 -0800205 expect: "cat in1 > __SBOX_SANDBOX_DIR__/out/out",
Colin Cross2a076922018-10-04 23:28:25 -0700206 },
207 {
208 name: "in1 fg",
209 prop: `
210 srcs: [":1in"],
211 out: ["out"],
212 cmd: "cat $(in) > $(out)",
213 `,
Colin Crosse16ce362020-11-12 08:29:30 -0800214 expect: "cat in1 > __SBOX_SANDBOX_DIR__/out/out",
Colin Cross2a076922018-10-04 23:28:25 -0700215 },
216 {
217 name: "ins",
218 prop: `
219 srcs: ["in1", "in2"],
220 out: ["out"],
221 cmd: "cat $(in) > $(out)",
222 `,
Colin Crosse16ce362020-11-12 08:29:30 -0800223 expect: "cat in1 in2 > __SBOX_SANDBOX_DIR__/out/out",
Colin Cross2a076922018-10-04 23:28:25 -0700224 },
225 {
226 name: "ins fg",
227 prop: `
228 srcs: [":ins"],
229 out: ["out"],
230 cmd: "cat $(in) > $(out)",
231 `,
Colin Crosse16ce362020-11-12 08:29:30 -0800232 expect: "cat in1 in2 > __SBOX_SANDBOX_DIR__/out/out",
Colin Cross2a076922018-10-04 23:28:25 -0700233 },
234 {
Colin Cross08f15ab2018-10-04 23:29:14 -0700235 name: "location in1",
236 prop: `
237 srcs: ["in1"],
238 out: ["out"],
239 cmd: "cat $(location in1) > $(out)",
240 `,
Colin Crosse16ce362020-11-12 08:29:30 -0800241 expect: "cat in1 > __SBOX_SANDBOX_DIR__/out/out",
Colin Cross08f15ab2018-10-04 23:29:14 -0700242 },
243 {
244 name: "location in1 fg",
245 prop: `
246 srcs: [":1in"],
247 out: ["out"],
248 cmd: "cat $(location :1in) > $(out)",
249 `,
Colin Crosse16ce362020-11-12 08:29:30 -0800250 expect: "cat in1 > __SBOX_SANDBOX_DIR__/out/out",
Colin Cross08f15ab2018-10-04 23:29:14 -0700251 },
252 {
253 name: "location ins",
254 prop: `
255 srcs: ["in1", "in2"],
256 out: ["out"],
257 cmd: "cat $(location in1) > $(out)",
258 `,
Colin Crosse16ce362020-11-12 08:29:30 -0800259 expect: "cat in1 > __SBOX_SANDBOX_DIR__/out/out",
Colin Cross08f15ab2018-10-04 23:29:14 -0700260 },
261 {
262 name: "location ins fg",
263 prop: `
264 srcs: [":ins"],
265 out: ["out"],
266 cmd: "cat $(locations :ins) > $(out)",
267 `,
Colin Crosse16ce362020-11-12 08:29:30 -0800268 expect: "cat in1 in2 > __SBOX_SANDBOX_DIR__/out/out",
Colin Cross08f15ab2018-10-04 23:29:14 -0700269 },
270 {
Colin Cross2a076922018-10-04 23:28:25 -0700271 name: "outs",
272 prop: `
273 out: ["out", "out2"],
274 cmd: "echo foo > $(out)",
275 `,
Colin Crosse16ce362020-11-12 08:29:30 -0800276 expect: "echo foo > __SBOX_SANDBOX_DIR__/out/out __SBOX_SANDBOX_DIR__/out/out2",
Colin Cross2a076922018-10-04 23:28:25 -0700277 },
278 {
Colin Cross08f15ab2018-10-04 23:29:14 -0700279 name: "location out",
280 prop: `
281 out: ["out", "out2"],
282 cmd: "echo foo > $(location out2)",
283 `,
Colin Crosse16ce362020-11-12 08:29:30 -0800284 expect: "echo foo > __SBOX_SANDBOX_DIR__/out/out2",
Colin Cross08f15ab2018-10-04 23:29:14 -0700285 },
286 {
Colin Cross2a076922018-10-04 23:28:25 -0700287 name: "depfile",
288 prop: `
289 out: ["out"],
290 depfile: true,
291 cmd: "echo foo > $(out) && touch $(depfile)",
292 `,
Colin Crosse16ce362020-11-12 08:29:30 -0800293 expect: "echo foo > __SBOX_SANDBOX_DIR__/out/out && touch __SBOX_DEPFILE__",
Colin Cross2a076922018-10-04 23:28:25 -0700294 },
295 {
296 name: "gendir",
297 prop: `
298 out: ["out"],
299 cmd: "echo foo > $(genDir)/foo && cp $(genDir)/foo $(out)",
300 `,
Colin Crosse16ce362020-11-12 08:29:30 -0800301 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 -0700302 },
Colin Cross70c47412021-03-12 17:48:14 -0800303 {
304 name: "$",
305 prop: `
306 out: ["out"],
307 cmd: "echo $$ > $(out)",
308 `,
309 expect: "echo $ > __SBOX_SANDBOX_DIR__/out/out",
310 },
Colin Cross2a076922018-10-04 23:28:25 -0700311
312 {
313 name: "error empty location",
314 prop: `
315 out: ["out"],
316 cmd: "$(location) > $(out)",
317 `,
318 err: "at least one `tools` or `tool_files` is required if $(location) is used",
319 },
320 {
Colin Cross08f15ab2018-10-04 23:29:14 -0700321 name: "error empty location no files",
322 prop: `
323 tool_files: [":empty"],
324 out: ["out"],
325 cmd: "$(location) > $(out)",
326 `,
327 err: `default label ":empty" has no files`,
328 },
329 {
330 name: "error empty location multiple files",
331 prop: `
332 tool_files: [":tool_files"],
333 out: ["out"],
334 cmd: "$(location) > $(out)",
335 `,
336 err: `default label ":tool_files" has multiple files`,
337 },
338 {
Colin Cross2a076922018-10-04 23:28:25 -0700339 name: "error location",
340 prop: `
341 out: ["out"],
342 cmd: "echo foo > $(location missing)",
343 `,
344 err: `unknown location label "missing"`,
345 },
346 {
Colin Cross08f15ab2018-10-04 23:29:14 -0700347 name: "error locations",
348 prop: `
349 out: ["out"],
350 cmd: "echo foo > $(locations missing)",
351 `,
352 err: `unknown locations label "missing"`,
353 },
354 {
355 name: "error location no files",
356 prop: `
357 out: ["out"],
358 srcs: [":empty"],
359 cmd: "echo $(location :empty) > $(out)",
360 `,
361 err: `label ":empty" has no files`,
362 },
363 {
364 name: "error locations no files",
365 prop: `
366 out: ["out"],
367 srcs: [":empty"],
368 cmd: "echo $(locations :empty) > $(out)",
369 `,
370 err: `label ":empty" has no files`,
371 },
372 {
373 name: "error location multiple files",
374 prop: `
375 out: ["out"],
376 srcs: [":ins"],
377 cmd: "echo $(location :ins) > $(out)",
378 `,
379 err: `label ":ins" has multiple files`,
380 },
381 {
Colin Cross2a076922018-10-04 23:28:25 -0700382 name: "error variable",
383 prop: `
384 out: ["out"],
385 srcs: ["in1"],
386 cmd: "echo $(foo) > $(out)",
387 `,
388 err: `unknown variable '$(foo)'`,
389 },
390 {
391 name: "error depfile",
392 prop: `
393 out: ["out"],
394 cmd: "echo foo > $(out) && touch $(depfile)",
395 `,
396 err: "$(depfile) used without depfile property",
397 },
398 {
399 name: "error no depfile",
400 prop: `
401 out: ["out"],
402 depfile: true,
403 cmd: "echo foo > $(out)",
404 `,
405 err: "specified depfile=true but did not include a reference to '${depfile}' in cmd",
406 },
407 {
408 name: "error no out",
409 prop: `
410 cmd: "echo foo > $(out)",
411 `,
412 err: "must have at least one output file",
413 },
Colin Crossba71a3f2019-03-18 12:12:48 -0700414 {
415 name: "srcs allow missing dependencies",
416 prop: `
417 srcs: [":missing"],
418 out: ["out"],
419 cmd: "cat $(location :missing) > $(out)",
420 `,
421
422 allowMissingDependencies: true,
423
Colin Crosse16ce362020-11-12 08:29:30 -0800424 expect: "cat ***missing srcs :missing*** > __SBOX_SANDBOX_DIR__/out/out",
Colin Crossba71a3f2019-03-18 12:12:48 -0700425 },
426 {
427 name: "tool allow missing dependencies",
428 prop: `
429 tools: [":missing"],
430 out: ["out"],
431 cmd: "$(location :missing) > $(out)",
432 `,
433
434 allowMissingDependencies: true,
435
Colin Crosse16ce362020-11-12 08:29:30 -0800436 expect: "***missing tool :missing*** > __SBOX_SANDBOX_DIR__/out/out",
Colin Crossba71a3f2019-03-18 12:12:48 -0700437 },
Colin Cross2a076922018-10-04 23:28:25 -0700438 }
439
440 for _, test := range testcases {
441 t.Run(test.name, func(t *testing.T) {
Colin Cross2a076922018-10-04 23:28:25 -0700442 bp := "genrule {\n"
443 bp += "name: \"gen\",\n"
444 bp += test.prop
445 bp += "}\n"
446
Paul Duffin672cb9f2021-03-03 02:30:37 +0000447 var expectedErrors []string
448 if test.err != "" {
449 expectedErrors = append(expectedErrors, regexp.QuoteMeta(test.err))
Colin Cross2a076922018-10-04 23:28:25 -0700450 }
Paul Duffin672cb9f2021-03-03 02:30:37 +0000451
Paul Duffin89648f92021-03-20 00:36:55 +0000452 result := android.GroupFixturePreparers(
453 prepareForGenRuleTest,
Paul Duffin672cb9f2021-03-03 02:30:37 +0000454 android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
455 variables.Allow_missing_dependencies = proptools.BoolPtr(test.allowMissingDependencies)
456 }),
457 android.FixtureModifyContext(func(ctx *android.TestContext) {
458 ctx.SetAllowMissingDependencies(test.allowMissingDependencies)
459 }),
460 ).
461 ExtendWithErrorHandler(android.FixtureExpectsAllErrorsToMatchAPattern(expectedErrors)).
462 RunTestWithBp(t, testGenruleBp()+bp)
463
464 if expectedErrors != nil {
Colin Cross2a076922018-10-04 23:28:25 -0700465 return
466 }
467
Paul Duffin672cb9f2021-03-03 02:30:37 +0000468 gen := result.Module("gen", "").(*Module)
Paul Duffine84b1332021-03-12 11:59:43 +0000469 android.AssertStringEquals(t, "raw commands", test.expect, gen.rawCommands[0])
Colin Cross2a076922018-10-04 23:28:25 -0700470 })
471 }
Colin Cross1a527682019-09-23 15:55:30 -0700472}
473
Bill Peckhamc087be12020-02-13 15:55:10 -0800474func TestGenruleHashInputs(t *testing.T) {
475
476 // The basic idea here is to verify that the sbox command (which is
477 // in the Command field of the generate rule) contains a hash of the
478 // inputs, but only if $(in) is not referenced in the genrule cmd
479 // property.
480
481 // By including a hash of the inputs, we cause the rule to re-run if
482 // the list of inputs changes (because the sbox command changes).
483
484 // However, if the genrule cmd property already contains $(in), then
485 // the dependency is already expressed, so we don't need to include the
486 // hash in that case.
487
488 bp := `
489 genrule {
490 name: "hash0",
491 srcs: ["in1.txt", "in2.txt"],
492 out: ["out"],
493 cmd: "echo foo > $(out)",
494 }
495 genrule {
496 name: "hash1",
497 srcs: ["*.txt"],
498 out: ["out"],
499 cmd: "echo bar > $(out)",
500 }
501 genrule {
502 name: "hash2",
503 srcs: ["*.txt"],
504 out: ["out"],
505 cmd: "echo $(in) > $(out)",
506 }
507 `
508 testcases := []struct {
509 name string
510 expectedHash string
511 }{
512 {
513 name: "hash0",
Colin Cross3d680512020-11-13 16:23:53 -0800514 // sha256 value obtained from: echo -en 'in1.txt\nin2.txt' | sha256sum
515 expectedHash: "18da75b9b1cc74b09e365b4ca2e321b5d618f438cc632b387ad9dc2ab4b20e9d",
Bill Peckhamc087be12020-02-13 15:55:10 -0800516 },
517 {
518 name: "hash1",
Colin Cross3d680512020-11-13 16:23:53 -0800519 // sha256 value obtained from: echo -en 'in1.txt\nin2.txt\nin3.txt' | sha256sum
520 expectedHash: "a38d432a4b19df93140e1f1fe26c97ff0387dae01fe506412b47208f0595fb45",
Bill Peckhamc087be12020-02-13 15:55:10 -0800521 },
522 {
523 name: "hash2",
Colin Cross3d680512020-11-13 16:23:53 -0800524 // sha256 value obtained from: echo -en 'in1.txt\nin2.txt\nin3.txt' | sha256sum
525 expectedHash: "a38d432a4b19df93140e1f1fe26c97ff0387dae01fe506412b47208f0595fb45",
Bill Peckhamc087be12020-02-13 15:55:10 -0800526 },
527 }
528
Paul Duffin89648f92021-03-20 00:36:55 +0000529 result := prepareForGenRuleTest.RunTestWithBp(t, testGenruleBp()+bp)
Bill Peckhamc087be12020-02-13 15:55:10 -0800530
531 for _, test := range testcases {
532 t.Run(test.name, func(t *testing.T) {
Paul Duffine84b1332021-03-12 11:59:43 +0000533 gen := result.ModuleForTests(test.name, "")
Colin Crosse16ce362020-11-12 08:29:30 -0800534 manifest := android.RuleBuilderSboxProtoForTests(t, gen.Output("genrule.sbox.textproto"))
535 hash := manifest.Commands[0].GetInputHash()
Bill Peckhamc087be12020-02-13 15:55:10 -0800536
Paul Duffine84b1332021-03-12 11:59:43 +0000537 android.AssertStringEquals(t, "hash", test.expectedHash, hash)
Bill Peckhamc087be12020-02-13 15:55:10 -0800538 })
539 }
540}
541
Colin Cross1a527682019-09-23 15:55:30 -0700542func TestGenSrcs(t *testing.T) {
543 testcases := []struct {
544 name string
545 prop string
546
547 allowMissingDependencies bool
548
549 err string
550 cmds []string
551 deps []string
552 files []string
553 }{
554 {
555 name: "gensrcs",
556 prop: `
557 tools: ["tool"],
558 srcs: ["in1.txt", "in2.txt"],
559 cmd: "$(location) $(in) > $(out)",
560 `,
561 cmds: []string{
Colin Crossba9e4032020-11-24 16:32:22 -0800562 "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 -0700563 },
Paul Duffine66946b2021-03-16 12:38:33 +0000564 deps: []string{
565 "out/soong/.intermediates/gen/gen/gensrcs/in1.h",
566 "out/soong/.intermediates/gen/gen/gensrcs/in2.h",
567 },
568 files: []string{
569 "out/soong/.intermediates/gen/gen/gensrcs/in1.h",
570 "out/soong/.intermediates/gen/gen/gensrcs/in2.h",
571 },
Colin Cross1a527682019-09-23 15:55:30 -0700572 },
573 {
574 name: "shards",
575 prop: `
576 tools: ["tool"],
577 srcs: ["in1.txt", "in2.txt", "in3.txt"],
578 cmd: "$(location) $(in) > $(out)",
579 shard_size: 2,
580 `,
581 cmds: []string{
Colin Crossba9e4032020-11-24 16:32:22 -0800582 "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'",
583 "bash -c '__SBOX_SANDBOX_DIR__/tools/out/bin/tool in3.txt > __SBOX_SANDBOX_DIR__/out/in3.h'",
Colin Cross1a527682019-09-23 15:55:30 -0700584 },
Paul Duffine66946b2021-03-16 12:38:33 +0000585 deps: []string{
586 "out/soong/.intermediates/gen/gen/gensrcs/in1.h",
587 "out/soong/.intermediates/gen/gen/gensrcs/in2.h",
588 "out/soong/.intermediates/gen/gen/gensrcs/in3.h",
589 },
590 files: []string{
591 "out/soong/.intermediates/gen/gen/gensrcs/in1.h",
592 "out/soong/.intermediates/gen/gen/gensrcs/in2.h",
593 "out/soong/.intermediates/gen/gen/gensrcs/in3.h",
594 },
Colin Cross1a527682019-09-23 15:55:30 -0700595 },
596 }
597
598 for _, test := range testcases {
599 t.Run(test.name, func(t *testing.T) {
Colin Cross1a527682019-09-23 15:55:30 -0700600 bp := "gensrcs {\n"
601 bp += `name: "gen",` + "\n"
602 bp += `output_extension: "h",` + "\n"
603 bp += test.prop
604 bp += "}\n"
605
Paul Duffin672cb9f2021-03-03 02:30:37 +0000606 var expectedErrors []string
607 if test.err != "" {
608 expectedErrors = append(expectedErrors, regexp.QuoteMeta(test.err))
Colin Cross1a527682019-09-23 15:55:30 -0700609 }
Paul Duffin672cb9f2021-03-03 02:30:37 +0000610
Paul Duffin89648f92021-03-20 00:36:55 +0000611 result := prepareForGenRuleTest.
Paul Duffin672cb9f2021-03-03 02:30:37 +0000612 ExtendWithErrorHandler(android.FixtureExpectsAllErrorsToMatchAPattern(expectedErrors)).
613 RunTestWithBp(t, testGenruleBp()+bp)
614
615 if expectedErrors != nil {
Colin Cross1a527682019-09-23 15:55:30 -0700616 return
617 }
618
Paul Duffin672cb9f2021-03-03 02:30:37 +0000619 gen := result.Module("gen", "").(*Module)
Paul Duffine84b1332021-03-12 11:59:43 +0000620 android.AssertDeepEquals(t, "cmd", test.cmds, gen.rawCommands)
Colin Cross1a527682019-09-23 15:55:30 -0700621
Paul Duffine66946b2021-03-16 12:38:33 +0000622 android.AssertPathsRelativeToTopEquals(t, "deps", test.deps, gen.outputDeps)
Colin Cross1a527682019-09-23 15:55:30 -0700623
Paul Duffine66946b2021-03-16 12:38:33 +0000624 android.AssertPathsRelativeToTopEquals(t, "files", test.files, gen.outputFiles)
Colin Cross1a527682019-09-23 15:55:30 -0700625 })
626 }
Colin Cross2a076922018-10-04 23:28:25 -0700627}
628
Jaewoong Jung98716bd2018-12-10 08:13:18 -0800629func TestGenruleDefaults(t *testing.T) {
Jaewoong Jung98716bd2018-12-10 08:13:18 -0800630 bp := `
631 genrule_defaults {
632 name: "gen_defaults1",
633 cmd: "cp $(in) $(out)",
634 }
635
636 genrule_defaults {
637 name: "gen_defaults2",
638 srcs: ["in1"],
639 }
640
641 genrule {
642 name: "gen",
643 out: ["out"],
644 defaults: ["gen_defaults1", "gen_defaults2"],
645 }
646 `
Paul Duffin672cb9f2021-03-03 02:30:37 +0000647
Paul Duffin89648f92021-03-20 00:36:55 +0000648 result := prepareForGenRuleTest.RunTestWithBp(t, testGenruleBp()+bp)
Paul Duffin672cb9f2021-03-03 02:30:37 +0000649
650 gen := result.Module("gen", "").(*Module)
Jaewoong Jung98716bd2018-12-10 08:13:18 -0800651
Colin Crosse16ce362020-11-12 08:29:30 -0800652 expectedCmd := "cp in1 __SBOX_SANDBOX_DIR__/out/out"
Paul Duffine84b1332021-03-12 11:59:43 +0000653 android.AssertStringEquals(t, "cmd", expectedCmd, gen.rawCommands[0])
Jaewoong Jung98716bd2018-12-10 08:13:18 -0800654
655 expectedSrcs := []string{"in1"}
Paul Duffine84b1332021-03-12 11:59:43 +0000656 android.AssertDeepEquals(t, "srcs", expectedSrcs, gen.properties.Srcs)
Jaewoong Jung98716bd2018-12-10 08:13:18 -0800657}
658
Colin Crossfa65cee2021-03-22 17:05:59 -0700659func TestGenruleAllowMissingDependencies(t *testing.T) {
660 bp := `
661 output {
662 name: "disabled",
663 enabled: false,
664 }
665
666 genrule {
667 name: "gen",
668 srcs: [
669 ":disabled",
670 ],
671 out: ["out"],
672 cmd: "cat $(in) > $(out)",
673 }
674 `
Paul Duffin79abe572021-03-29 02:16:14 +0100675 result := android.GroupFixturePreparers(
676 prepareForGenRuleTest,
Colin Crossfa65cee2021-03-22 17:05:59 -0700677 android.FixtureModifyConfigAndContext(
678 func(config android.Config, ctx *android.TestContext) {
679 config.TestProductVariables.Allow_missing_dependencies = proptools.BoolPtr(true)
680 ctx.SetAllowMissingDependencies(true)
681 })).RunTestWithBp(t, bp)
682
683 gen := result.ModuleForTests("gen", "").Output("out")
684 if gen.Rule != android.ErrorRule {
685 t.Errorf("Expected missing dependency error rule for gen, got %q", gen.Rule.String())
686 }
687}
688
Jooyung Han8c7e3ed2021-06-28 17:35:58 +0900689func TestGenruleOutputFiles(t *testing.T) {
690 bp := `
691 genrule {
692 name: "gen",
693 out: ["foo", "sub/bar"],
694 cmd: "echo foo > $(location foo) && echo bar > $(location sub/bar)",
695 }
696 use_source {
697 name: "gen_foo",
698 srcs: [":gen{foo}"],
699 }
700 use_source {
701 name: "gen_bar",
702 srcs: [":gen{sub/bar}"],
703 }
704 use_source {
705 name: "gen_all",
706 srcs: [":gen"],
707 }
708 `
709
710 result := prepareForGenRuleTest.RunTestWithBp(t, testGenruleBp()+bp)
711 android.AssertPathsRelativeToTopEquals(t,
712 "genrule.tag with output",
713 []string{"out/soong/.intermediates/gen/gen/foo"},
714 result.ModuleForTests("gen_foo", "").Module().(*useSource).srcs)
715 android.AssertPathsRelativeToTopEquals(t,
716 "genrule.tag with output in subdir",
717 []string{"out/soong/.intermediates/gen/gen/sub/bar"},
718 result.ModuleForTests("gen_bar", "").Module().(*useSource).srcs)
719 android.AssertPathsRelativeToTopEquals(t,
720 "genrule.tag with all",
721 []string{"out/soong/.intermediates/gen/gen/foo", "out/soong/.intermediates/gen/gen/sub/bar"},
722 result.ModuleForTests("gen_all", "").Module().(*useSource).srcs)
723}
724
Martin Stjernholmdbd814d2022-01-12 23:18:30 +0000725func TestPrebuiltTool(t *testing.T) {
726 testcases := []struct {
727 name string
728 bp string
729 expectedToolName string
730 }{
731 {
732 name: "source only",
733 bp: `
734 tool { name: "tool" }
735 `,
736 expectedToolName: "bin/tool",
737 },
738 {
739 name: "prebuilt only",
740 bp: `
741 prebuilt_tool { name: "tool" }
742 `,
743 expectedToolName: "prebuilt_bin/tool",
744 },
745 {
746 name: "source preferred",
747 bp: `
748 tool { name: "tool" }
749 prebuilt_tool { name: "tool" }
750 `,
751 expectedToolName: "bin/tool",
752 },
753 {
754 name: "prebuilt preferred",
755 bp: `
756 tool { name: "tool" }
757 prebuilt_tool { name: "tool", prefer: true }
758 `,
759 expectedToolName: "prebuilt_bin/prebuilt_tool",
760 },
761 {
762 name: "source disabled",
763 bp: `
764 tool { name: "tool", enabled: false }
765 prebuilt_tool { name: "tool" }
766 `,
767 expectedToolName: "prebuilt_bin/prebuilt_tool",
768 },
769 }
770
771 for _, test := range testcases {
772 t.Run(test.name, func(t *testing.T) {
773 result := prepareForGenRuleTest.RunTestWithBp(t, test.bp+`
774 genrule {
775 name: "gen",
776 tools: ["tool"],
777 out: ["foo"],
778 cmd: "$(location tool)",
779 }
780 `)
781 gen := result.Module("gen", "").(*Module)
782 expectedCmd := "__SBOX_SANDBOX_DIR__/tools/out/" + test.expectedToolName
783 android.AssertStringEquals(t, "command", expectedCmd, gen.rawCommands[0])
784 })
785 }
786}
787
Chris Parsonsf3c96ef2020-09-29 02:23:17 -0400788func TestGenruleWithBazel(t *testing.T) {
789 bp := `
790 genrule {
791 name: "foo",
792 out: ["one.txt", "two.txt"],
Chris Parsonsaa8be052020-10-14 16:22:37 -0400793 bazel_module: { label: "//foo/bar:bar" },
Chris Parsonsf3c96ef2020-09-29 02:23:17 -0400794 }
795 `
796
Paul Duffin89648f92021-03-20 00:36:55 +0000797 result := android.GroupFixturePreparers(
798 prepareForGenRuleTest, android.FixtureModifyConfig(func(config android.Config) {
799 config.BazelContext = android.MockBazelContext{
Liz Kammera92e8442021-04-07 20:25:21 -0400800 OutputBaseDir: "outputbase",
801 LabelToOutputFiles: map[string][]string{
Paul Duffin89648f92021-03-20 00:36:55 +0000802 "//foo/bar:bar": []string{"bazelone.txt", "bazeltwo.txt"}}}
803 })).RunTestWithBp(t, testGenruleBp()+bp)
Chris Parsonsf3c96ef2020-09-29 02:23:17 -0400804
Paul Duffin672cb9f2021-03-03 02:30:37 +0000805 gen := result.Module("foo", "").(*Module)
Chris Parsonsf3c96ef2020-09-29 02:23:17 -0400806
Chris Parsonsdbcb1ff2020-12-10 17:19:18 -0500807 expectedOutputFiles := []string{"outputbase/execroot/__main__/bazelone.txt",
808 "outputbase/execroot/__main__/bazeltwo.txt"}
Paul Duffine84b1332021-03-12 11:59:43 +0000809 android.AssertDeepEquals(t, "output files", expectedOutputFiles, gen.outputFiles.Strings())
810 android.AssertDeepEquals(t, "output deps", expectedOutputFiles, gen.outputDeps.Strings())
Chris Parsonsf3c96ef2020-09-29 02:23:17 -0400811}
812
Colin Cross2a076922018-10-04 23:28:25 -0700813type testTool struct {
814 android.ModuleBase
815 outputFile android.Path
816}
817
818func toolFactory() android.Module {
819 module := &testTool{}
820 android.InitAndroidArchModule(module, android.HostSupported, android.MultilibFirst)
821 return module
822}
823
Colin Cross2a076922018-10-04 23:28:25 -0700824func (t *testTool) GenerateAndroidBuildActions(ctx android.ModuleContext) {
Colin Crossba9e4032020-11-24 16:32:22 -0800825 t.outputFile = ctx.InstallFile(android.PathForModuleInstall(ctx, "bin"), ctx.ModuleName(), android.PathForOutput(ctx, ctx.ModuleName()))
Colin Cross2a076922018-10-04 23:28:25 -0700826}
827
828func (t *testTool) HostToolPath() android.OptionalPath {
829 return android.OptionalPathForPath(t.outputFile)
830}
831
Martin Stjernholmdbd814d2022-01-12 23:18:30 +0000832type prebuiltTestTool struct {
833 android.ModuleBase
834 prebuilt android.Prebuilt
835 testTool
836}
837
838func (p *prebuiltTestTool) Name() string {
839 return p.prebuilt.Name(p.ModuleBase.Name())
840}
841
842func (p *prebuiltTestTool) Prebuilt() *android.Prebuilt {
843 return &p.prebuilt
844}
845
846func (t *prebuiltTestTool) GenerateAndroidBuildActions(ctx android.ModuleContext) {
847 t.outputFile = ctx.InstallFile(android.PathForModuleInstall(ctx, "prebuilt_bin"), ctx.ModuleName(), android.PathForOutput(ctx, ctx.ModuleName()))
848}
849
850func prebuiltToolFactory() android.Module {
851 module := &prebuiltTestTool{}
852 android.InitPrebuiltModuleWithoutSrcs(module)
853 android.InitAndroidArchModule(module, android.HostSupported, android.MultilibFirst)
854 return module
855}
856
Colin Crossfe17f6f2019-03-28 19:30:56 -0700857var _ android.HostToolProvider = (*testTool)(nil)
Martin Stjernholmdbd814d2022-01-12 23:18:30 +0000858var _ android.HostToolProvider = (*prebuiltTestTool)(nil)
Colin Crossfa65cee2021-03-22 17:05:59 -0700859
860type testOutputProducer struct {
861 android.ModuleBase
862 outputFile android.Path
863}
864
865func outputProducerFactory() android.Module {
866 module := &testOutputProducer{}
867 android.InitAndroidArchModule(module, android.HostSupported, android.MultilibFirst)
868 return module
869}
870
871func (t *testOutputProducer) GenerateAndroidBuildActions(ctx android.ModuleContext) {
872 t.outputFile = ctx.InstallFile(android.PathForModuleInstall(ctx, "bin"), ctx.ModuleName(), android.PathForOutput(ctx, ctx.ModuleName()))
873}
874
875func (t *testOutputProducer) OutputFiles(tag string) (android.Paths, error) {
876 return android.Paths{t.outputFile}, nil
877}
878
879var _ android.OutputFileProducer = (*testOutputProducer)(nil)
Jooyung Han8c7e3ed2021-06-28 17:35:58 +0900880
881type useSource struct {
882 android.ModuleBase
883 props struct {
884 Srcs []string `android:"path"`
885 }
886 srcs android.Paths
887}
888
889func (s *useSource) GenerateAndroidBuildActions(ctx android.ModuleContext) {
890 s.srcs = android.PathsForModuleSrc(ctx, s.props.Srcs)
891}
892
893func useSourceFactory() android.Module {
894 module := &useSource{}
895 module.AddProperties(&module.props)
896 android.InitAndroidModule(module)
897 return module
898}