blob: 9278f1574666045dc38729984a8bfa636ae4ca8e [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 (
Vinh Tran140d5882022-06-10 14:23:27 -040018 "fmt"
Colin Cross2a076922018-10-04 23:28:25 -070019 "os"
Paul Duffin672cb9f2021-03-03 02:30:37 +000020 "regexp"
Liz Kammer796921d2023-07-11 08:21:41 -040021 "strconv"
Cole Faust78f3c3a2024-08-15 17:19:34 -070022 "strings"
Colin Cross2a076922018-10-04 23:28:25 -070023 "testing"
24
25 "android/soong/android"
Colin Crossba71a3f2019-03-18 12:12:48 -070026
27 "github.com/google/blueprint/proptools"
Colin Cross2a076922018-10-04 23:28:25 -070028)
29
Colin Cross2a076922018-10-04 23:28:25 -070030func TestMain(m *testing.M) {
Paul Duffine66946b2021-03-16 12:38:33 +000031 os.Exit(m.Run())
Colin Cross2a076922018-10-04 23:28:25 -070032}
33
Paul Duffin89648f92021-03-20 00:36:55 +000034var prepareForGenRuleTest = android.GroupFixturePreparers(
Paul Duffin672cb9f2021-03-03 02:30:37 +000035 android.PrepareForTestWithArchMutator,
36 android.PrepareForTestWithDefaults,
Paul Duffin672cb9f2021-03-03 02:30:37 +000037 android.PrepareForTestWithFilegroup,
38 PrepareForTestWithGenRuleBuildComponents,
39 android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
Martin Stjernholmdbd814d2022-01-12 23:18:30 +000040 android.RegisterPrebuiltMutators(ctx)
Paul Duffin672cb9f2021-03-03 02:30:37 +000041 ctx.RegisterModuleType("tool", toolFactory)
Martin Stjernholmdbd814d2022-01-12 23:18:30 +000042 ctx.RegisterModuleType("prebuilt_tool", prebuiltToolFactory)
Colin Crossfa65cee2021-03-22 17:05:59 -070043 ctx.RegisterModuleType("output", outputProducerFactory)
Jooyung Han8c7e3ed2021-06-28 17:35:58 +090044 ctx.RegisterModuleType("use_source", useSourceFactory)
Paul Duffin672cb9f2021-03-03 02:30:37 +000045 }),
46 android.FixtureMergeMockFs(android.MockFS{
47 "tool": nil,
48 "tool_file1": nil,
49 "tool_file2": nil,
50 "in1": nil,
51 "in2": nil,
52 "in1.txt": nil,
53 "in2.txt": nil,
54 "in3.txt": nil,
55 }),
56)
Martin Stjernholm710ec3a2020-01-16 15:12:04 +000057
Paul Duffin672cb9f2021-03-03 02:30:37 +000058func testGenruleBp() string {
59 return `
Colin Cross2a076922018-10-04 23:28:25 -070060 tool {
61 name: "tool",
62 }
63
64 filegroup {
65 name: "tool_files",
66 srcs: [
67 "tool_file1",
68 "tool_file2",
69 ],
70 }
71
72 filegroup {
73 name: "1tool_file",
74 srcs: [
75 "tool_file1",
76 ],
77 }
78
79 filegroup {
80 name: "ins",
81 srcs: [
82 "in1",
83 "in2",
84 ],
85 }
86
87 filegroup {
88 name: "1in",
89 srcs: [
90 "in1",
91 ],
92 }
93
94 filegroup {
95 name: "empty",
96 }
97 `
Colin Cross2a076922018-10-04 23:28:25 -070098}
99
100func TestGenruleCmd(t *testing.T) {
101 testcases := []struct {
Yu Liu6a7940c2023-05-09 17:12:22 -0700102 name string
103 moduleName string
104 prop string
Colin Cross2a076922018-10-04 23:28:25 -0700105
Colin Crossba71a3f2019-03-18 12:12:48 -0700106 allowMissingDependencies bool
107
Colin Cross2a076922018-10-04 23:28:25 -0700108 err string
109 expect string
110 }{
111 {
112 name: "empty location tool",
113 prop: `
114 tools: ["tool"],
115 out: ["out"],
116 cmd: "$(location) > $(out)",
117 `,
Colin Crossba9e4032020-11-24 16:32:22 -0800118 expect: "__SBOX_SANDBOX_DIR__/tools/out/bin/tool > __SBOX_SANDBOX_DIR__/out/out",
Colin Cross2a076922018-10-04 23:28:25 -0700119 },
120 {
Colin Cross08f15ab2018-10-04 23:29:14 -0700121 name: "empty location tool2",
122 prop: `
123 tools: [":tool"],
124 out: ["out"],
125 cmd: "$(location) > $(out)",
126 `,
Colin Crossba9e4032020-11-24 16:32:22 -0800127 expect: "__SBOX_SANDBOX_DIR__/tools/out/bin/tool > __SBOX_SANDBOX_DIR__/out/out",
Colin Cross08f15ab2018-10-04 23:29:14 -0700128 },
129 {
Colin Cross2a076922018-10-04 23:28:25 -0700130 name: "empty location tool file",
131 prop: `
132 tool_files: ["tool_file1"],
133 out: ["out"],
134 cmd: "$(location) > $(out)",
135 `,
Colin Crossba9e4032020-11-24 16:32:22 -0800136 expect: "__SBOX_SANDBOX_DIR__/tools/src/tool_file1 > __SBOX_SANDBOX_DIR__/out/out",
Colin Cross2a076922018-10-04 23:28:25 -0700137 },
138 {
139 name: "empty location tool file fg",
140 prop: `
141 tool_files: [":1tool_file"],
142 out: ["out"],
143 cmd: "$(location) > $(out)",
144 `,
Colin Crossba9e4032020-11-24 16:32:22 -0800145 expect: "__SBOX_SANDBOX_DIR__/tools/src/tool_file1 > __SBOX_SANDBOX_DIR__/out/out",
Colin Cross2a076922018-10-04 23:28:25 -0700146 },
147 {
148 name: "empty location tool and tool file",
149 prop: `
150 tools: ["tool"],
151 tool_files: ["tool_file1"],
152 out: ["out"],
153 cmd: "$(location) > $(out)",
154 `,
Colin Crossba9e4032020-11-24 16:32:22 -0800155 expect: "__SBOX_SANDBOX_DIR__/tools/out/bin/tool > __SBOX_SANDBOX_DIR__/out/out",
Colin Cross2a076922018-10-04 23:28:25 -0700156 },
157 {
158 name: "tool",
159 prop: `
160 tools: ["tool"],
161 out: ["out"],
162 cmd: "$(location tool) > $(out)",
163 `,
Colin Crossba9e4032020-11-24 16:32:22 -0800164 expect: "__SBOX_SANDBOX_DIR__/tools/out/bin/tool > __SBOX_SANDBOX_DIR__/out/out",
Colin Cross2a076922018-10-04 23:28:25 -0700165 },
166 {
Colin Cross08f15ab2018-10-04 23:29:14 -0700167 name: "tool2",
168 prop: `
169 tools: [":tool"],
170 out: ["out"],
171 cmd: "$(location :tool) > $(out)",
172 `,
Colin Crossba9e4032020-11-24 16:32:22 -0800173 expect: "__SBOX_SANDBOX_DIR__/tools/out/bin/tool > __SBOX_SANDBOX_DIR__/out/out",
Colin Cross08f15ab2018-10-04 23:29:14 -0700174 },
175 {
Colin Cross2a076922018-10-04 23:28:25 -0700176 name: "tool file",
177 prop: `
178 tool_files: ["tool_file1"],
179 out: ["out"],
180 cmd: "$(location tool_file1) > $(out)",
181 `,
Colin Crossba9e4032020-11-24 16:32:22 -0800182 expect: "__SBOX_SANDBOX_DIR__/tools/src/tool_file1 > __SBOX_SANDBOX_DIR__/out/out",
Colin Cross2a076922018-10-04 23:28:25 -0700183 },
184 {
185 name: "tool file fg",
186 prop: `
187 tool_files: [":1tool_file"],
188 out: ["out"],
Colin Cross08f15ab2018-10-04 23:29:14 -0700189 cmd: "$(location :1tool_file) > $(out)",
Colin Cross2a076922018-10-04 23:28:25 -0700190 `,
Colin Crossba9e4032020-11-24 16:32:22 -0800191 expect: "__SBOX_SANDBOX_DIR__/tools/src/tool_file1 > __SBOX_SANDBOX_DIR__/out/out",
Colin Cross2a076922018-10-04 23:28:25 -0700192 },
193 {
194 name: "tool files",
195 prop: `
196 tool_files: [":tool_files"],
197 out: ["out"],
Colin Cross08f15ab2018-10-04 23:29:14 -0700198 cmd: "$(locations :tool_files) > $(out)",
Colin Cross2a076922018-10-04 23:28:25 -0700199 `,
Colin Crossba9e4032020-11-24 16:32:22 -0800200 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 -0700201 },
202 {
203 name: "in1",
204 prop: `
205 srcs: ["in1"],
206 out: ["out"],
207 cmd: "cat $(in) > $(out)",
208 `,
Colin Crosse16ce362020-11-12 08:29:30 -0800209 expect: "cat in1 > __SBOX_SANDBOX_DIR__/out/out",
Colin Cross2a076922018-10-04 23:28:25 -0700210 },
211 {
212 name: "in1 fg",
213 prop: `
214 srcs: [":1in"],
215 out: ["out"],
216 cmd: "cat $(in) > $(out)",
217 `,
Colin Crosse16ce362020-11-12 08:29:30 -0800218 expect: "cat in1 > __SBOX_SANDBOX_DIR__/out/out",
Colin Cross2a076922018-10-04 23:28:25 -0700219 },
220 {
221 name: "ins",
222 prop: `
223 srcs: ["in1", "in2"],
224 out: ["out"],
225 cmd: "cat $(in) > $(out)",
226 `,
Colin Crosse16ce362020-11-12 08:29:30 -0800227 expect: "cat in1 in2 > __SBOX_SANDBOX_DIR__/out/out",
Colin Cross2a076922018-10-04 23:28:25 -0700228 },
229 {
230 name: "ins fg",
231 prop: `
232 srcs: [":ins"],
233 out: ["out"],
234 cmd: "cat $(in) > $(out)",
235 `,
Colin Crosse16ce362020-11-12 08:29:30 -0800236 expect: "cat in1 in2 > __SBOX_SANDBOX_DIR__/out/out",
Colin Cross2a076922018-10-04 23:28:25 -0700237 },
238 {
Colin Cross08f15ab2018-10-04 23:29:14 -0700239 name: "location in1",
240 prop: `
241 srcs: ["in1"],
242 out: ["out"],
243 cmd: "cat $(location in1) > $(out)",
244 `,
Colin Crosse16ce362020-11-12 08:29:30 -0800245 expect: "cat in1 > __SBOX_SANDBOX_DIR__/out/out",
Colin Cross08f15ab2018-10-04 23:29:14 -0700246 },
247 {
248 name: "location in1 fg",
249 prop: `
250 srcs: [":1in"],
251 out: ["out"],
252 cmd: "cat $(location :1in) > $(out)",
253 `,
Colin Crosse16ce362020-11-12 08:29:30 -0800254 expect: "cat in1 > __SBOX_SANDBOX_DIR__/out/out",
Colin Cross08f15ab2018-10-04 23:29:14 -0700255 },
256 {
257 name: "location ins",
258 prop: `
259 srcs: ["in1", "in2"],
260 out: ["out"],
261 cmd: "cat $(location in1) > $(out)",
262 `,
Colin Crosse16ce362020-11-12 08:29:30 -0800263 expect: "cat in1 > __SBOX_SANDBOX_DIR__/out/out",
Colin Cross08f15ab2018-10-04 23:29:14 -0700264 },
265 {
266 name: "location ins fg",
267 prop: `
268 srcs: [":ins"],
269 out: ["out"],
270 cmd: "cat $(locations :ins) > $(out)",
271 `,
Colin Crosse16ce362020-11-12 08:29:30 -0800272 expect: "cat in1 in2 > __SBOX_SANDBOX_DIR__/out/out",
Colin Cross08f15ab2018-10-04 23:29:14 -0700273 },
274 {
Colin Cross2a076922018-10-04 23:28:25 -0700275 name: "outs",
276 prop: `
277 out: ["out", "out2"],
278 cmd: "echo foo > $(out)",
279 `,
Colin Crosse16ce362020-11-12 08:29:30 -0800280 expect: "echo foo > __SBOX_SANDBOX_DIR__/out/out __SBOX_SANDBOX_DIR__/out/out2",
Colin Cross2a076922018-10-04 23:28:25 -0700281 },
282 {
Colin Cross08f15ab2018-10-04 23:29:14 -0700283 name: "location out",
284 prop: `
285 out: ["out", "out2"],
286 cmd: "echo foo > $(location out2)",
287 `,
Colin Crosse16ce362020-11-12 08:29:30 -0800288 expect: "echo foo > __SBOX_SANDBOX_DIR__/out/out2",
Colin Cross08f15ab2018-10-04 23:29:14 -0700289 },
290 {
Colin Cross2a076922018-10-04 23:28:25 -0700291 name: "gendir",
292 prop: `
293 out: ["out"],
294 cmd: "echo foo > $(genDir)/foo && cp $(genDir)/foo $(out)",
295 `,
Colin Crosse16ce362020-11-12 08:29:30 -0800296 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 -0700297 },
Colin Cross70c47412021-03-12 17:48:14 -0800298 {
299 name: "$",
300 prop: `
301 out: ["out"],
302 cmd: "echo $$ > $(out)",
303 `,
304 expect: "echo $ > __SBOX_SANDBOX_DIR__/out/out",
305 },
Colin Cross2a076922018-10-04 23:28:25 -0700306
307 {
308 name: "error empty location",
309 prop: `
310 out: ["out"],
311 cmd: "$(location) > $(out)",
312 `,
313 err: "at least one `tools` or `tool_files` is required if $(location) is used",
314 },
315 {
Colin Cross08f15ab2018-10-04 23:29:14 -0700316 name: "error empty location no files",
317 prop: `
318 tool_files: [":empty"],
319 out: ["out"],
320 cmd: "$(location) > $(out)",
321 `,
322 err: `default label ":empty" has no files`,
323 },
324 {
325 name: "error empty location multiple files",
326 prop: `
327 tool_files: [":tool_files"],
328 out: ["out"],
329 cmd: "$(location) > $(out)",
330 `,
331 err: `default label ":tool_files" has multiple files`,
332 },
333 {
Colin Cross2a076922018-10-04 23:28:25 -0700334 name: "error location",
335 prop: `
336 out: ["out"],
337 cmd: "echo foo > $(location missing)",
338 `,
Anton Hanssonbebf5262022-02-23 11:42:38 +0000339 err: `unknown location label "missing" is not in srcs, out, tools or tool_files.`,
Colin Cross2a076922018-10-04 23:28:25 -0700340 },
341 {
Colin Cross08f15ab2018-10-04 23:29:14 -0700342 name: "error locations",
343 prop: `
344 out: ["out"],
345 cmd: "echo foo > $(locations missing)",
346 `,
Anton Hanssonbebf5262022-02-23 11:42:38 +0000347 err: `unknown locations label "missing" is not in srcs, out, tools or tool_files`,
Colin Cross08f15ab2018-10-04 23:29:14 -0700348 },
349 {
350 name: "error location no files",
351 prop: `
352 out: ["out"],
353 srcs: [":empty"],
354 cmd: "echo $(location :empty) > $(out)",
355 `,
356 err: `label ":empty" has no files`,
357 },
358 {
359 name: "error locations no files",
360 prop: `
361 out: ["out"],
362 srcs: [":empty"],
363 cmd: "echo $(locations :empty) > $(out)",
364 `,
365 err: `label ":empty" has no files`,
366 },
367 {
368 name: "error location multiple files",
369 prop: `
370 out: ["out"],
371 srcs: [":ins"],
372 cmd: "echo $(location :ins) > $(out)",
373 `,
374 err: `label ":ins" has multiple files`,
375 },
376 {
Colin Cross2a076922018-10-04 23:28:25 -0700377 name: "error variable",
378 prop: `
379 out: ["out"],
380 srcs: ["in1"],
381 cmd: "echo $(foo) > $(out)",
382 `,
383 err: `unknown variable '$(foo)'`,
384 },
385 {
Colin Cross2a076922018-10-04 23:28:25 -0700386 name: "error no out",
387 prop: `
388 cmd: "echo foo > $(out)",
389 `,
390 err: "must have at least one output file",
391 },
Colin Crossba71a3f2019-03-18 12:12:48 -0700392 {
393 name: "srcs allow missing dependencies",
394 prop: `
395 srcs: [":missing"],
396 out: ["out"],
397 cmd: "cat $(location :missing) > $(out)",
398 `,
399
400 allowMissingDependencies: true,
401
Jihoon Kangc170af42022-08-20 05:26:38 +0000402 expect: "cat '***missing srcs :missing***' > __SBOX_SANDBOX_DIR__/out/out",
Colin Crossba71a3f2019-03-18 12:12:48 -0700403 },
404 {
405 name: "tool allow missing dependencies",
406 prop: `
407 tools: [":missing"],
408 out: ["out"],
409 cmd: "$(location :missing) > $(out)",
410 `,
411
412 allowMissingDependencies: true,
413
Jihoon Kangc170af42022-08-20 05:26:38 +0000414 expect: "'***missing tool :missing***' > __SBOX_SANDBOX_DIR__/out/out",
Colin Crossba71a3f2019-03-18 12:12:48 -0700415 },
Colin Cross2a076922018-10-04 23:28:25 -0700416 }
417
418 for _, test := range testcases {
419 t.Run(test.name, func(t *testing.T) {
Yu Liu6a7940c2023-05-09 17:12:22 -0700420 moduleName := "gen"
421 if test.moduleName != "" {
422 moduleName = test.moduleName
423 }
424 bp := fmt.Sprintf(`
425 genrule {
426 name: "%s",
427 %s
428 }`, moduleName, test.prop)
Paul Duffin672cb9f2021-03-03 02:30:37 +0000429 var expectedErrors []string
430 if test.err != "" {
431 expectedErrors = append(expectedErrors, regexp.QuoteMeta(test.err))
Colin Cross2a076922018-10-04 23:28:25 -0700432 }
Paul Duffin672cb9f2021-03-03 02:30:37 +0000433
Paul Duffin89648f92021-03-20 00:36:55 +0000434 result := android.GroupFixturePreparers(
435 prepareForGenRuleTest,
Paul Duffin672cb9f2021-03-03 02:30:37 +0000436 android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
437 variables.Allow_missing_dependencies = proptools.BoolPtr(test.allowMissingDependencies)
438 }),
Yu Liu6a7940c2023-05-09 17:12:22 -0700439 android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
440 variables.GenruleSandboxing = proptools.BoolPtr(true)
441 }),
Paul Duffin672cb9f2021-03-03 02:30:37 +0000442 android.FixtureModifyContext(func(ctx *android.TestContext) {
443 ctx.SetAllowMissingDependencies(test.allowMissingDependencies)
444 }),
445 ).
446 ExtendWithErrorHandler(android.FixtureExpectsAllErrorsToMatchAPattern(expectedErrors)).
447 RunTestWithBp(t, testGenruleBp()+bp)
448
449 if expectedErrors != nil {
Colin Cross2a076922018-10-04 23:28:25 -0700450 return
451 }
452
Yu Liu6a7940c2023-05-09 17:12:22 -0700453 gen := result.Module(moduleName, "").(*Module)
Paul Duffine84b1332021-03-12 11:59:43 +0000454 android.AssertStringEquals(t, "raw commands", test.expect, gen.rawCommands[0])
Colin Cross2a076922018-10-04 23:28:25 -0700455 })
456 }
Colin Cross1a527682019-09-23 15:55:30 -0700457}
458
Bill Peckhamc087be12020-02-13 15:55:10 -0800459func TestGenruleHashInputs(t *testing.T) {
460
461 // The basic idea here is to verify that the sbox command (which is
462 // in the Command field of the generate rule) contains a hash of the
463 // inputs, but only if $(in) is not referenced in the genrule cmd
464 // property.
465
466 // By including a hash of the inputs, we cause the rule to re-run if
467 // the list of inputs changes (because the sbox command changes).
468
469 // However, if the genrule cmd property already contains $(in), then
470 // the dependency is already expressed, so we don't need to include the
471 // hash in that case.
472
473 bp := `
474 genrule {
475 name: "hash0",
476 srcs: ["in1.txt", "in2.txt"],
477 out: ["out"],
478 cmd: "echo foo > $(out)",
479 }
480 genrule {
481 name: "hash1",
482 srcs: ["*.txt"],
483 out: ["out"],
484 cmd: "echo bar > $(out)",
485 }
486 genrule {
487 name: "hash2",
488 srcs: ["*.txt"],
489 out: ["out"],
490 cmd: "echo $(in) > $(out)",
491 }
492 `
493 testcases := []struct {
494 name string
495 expectedHash string
496 }{
497 {
498 name: "hash0",
Colin Cross3d680512020-11-13 16:23:53 -0800499 // sha256 value obtained from: echo -en 'in1.txt\nin2.txt' | sha256sum
500 expectedHash: "18da75b9b1cc74b09e365b4ca2e321b5d618f438cc632b387ad9dc2ab4b20e9d",
Bill Peckhamc087be12020-02-13 15:55:10 -0800501 },
502 {
503 name: "hash1",
Colin Cross3d680512020-11-13 16:23:53 -0800504 // sha256 value obtained from: echo -en 'in1.txt\nin2.txt\nin3.txt' | sha256sum
505 expectedHash: "a38d432a4b19df93140e1f1fe26c97ff0387dae01fe506412b47208f0595fb45",
Bill Peckhamc087be12020-02-13 15:55:10 -0800506 },
507 {
508 name: "hash2",
Colin Cross3d680512020-11-13 16:23:53 -0800509 // sha256 value obtained from: echo -en 'in1.txt\nin2.txt\nin3.txt' | sha256sum
510 expectedHash: "a38d432a4b19df93140e1f1fe26c97ff0387dae01fe506412b47208f0595fb45",
Bill Peckhamc087be12020-02-13 15:55:10 -0800511 },
512 }
513
Paul Duffin89648f92021-03-20 00:36:55 +0000514 result := prepareForGenRuleTest.RunTestWithBp(t, testGenruleBp()+bp)
Bill Peckhamc087be12020-02-13 15:55:10 -0800515
516 for _, test := range testcases {
517 t.Run(test.name, func(t *testing.T) {
Paul Duffine84b1332021-03-12 11:59:43 +0000518 gen := result.ModuleForTests(test.name, "")
Colin Crossf61d03d2023-11-02 16:56:39 -0700519 manifest := android.RuleBuilderSboxProtoForTests(t, result.TestContext, gen.Output("genrule.sbox.textproto"))
Colin Crosse16ce362020-11-12 08:29:30 -0800520 hash := manifest.Commands[0].GetInputHash()
Bill Peckhamc087be12020-02-13 15:55:10 -0800521
Paul Duffine84b1332021-03-12 11:59:43 +0000522 android.AssertStringEquals(t, "hash", test.expectedHash, hash)
Bill Peckhamc087be12020-02-13 15:55:10 -0800523 })
524 }
525}
526
Colin Cross1a527682019-09-23 15:55:30 -0700527func TestGenSrcs(t *testing.T) {
528 testcases := []struct {
529 name string
530 prop string
531
532 allowMissingDependencies bool
533
Liz Kammer796921d2023-07-11 08:21:41 -0400534 err string
535 cmds []string
536 deps []string
537 files []string
538 shards int
539 inputs []string
Colin Cross1a527682019-09-23 15:55:30 -0700540 }{
541 {
542 name: "gensrcs",
543 prop: `
544 tools: ["tool"],
545 srcs: ["in1.txt", "in2.txt"],
546 cmd: "$(location) $(in) > $(out)",
547 `,
548 cmds: []string{
Colin Crossba9e4032020-11-24 16:32:22 -0800549 "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 -0700550 },
Paul Duffine66946b2021-03-16 12:38:33 +0000551 deps: []string{
552 "out/soong/.intermediates/gen/gen/gensrcs/in1.h",
553 "out/soong/.intermediates/gen/gen/gensrcs/in2.h",
554 },
555 files: []string{
556 "out/soong/.intermediates/gen/gen/gensrcs/in1.h",
557 "out/soong/.intermediates/gen/gen/gensrcs/in2.h",
558 },
Colin Cross1a527682019-09-23 15:55:30 -0700559 },
560 {
561 name: "shards",
562 prop: `
563 tools: ["tool"],
564 srcs: ["in1.txt", "in2.txt", "in3.txt"],
565 cmd: "$(location) $(in) > $(out)",
566 shard_size: 2,
567 `,
568 cmds: []string{
Colin Crossba9e4032020-11-24 16:32:22 -0800569 "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'",
570 "bash -c '__SBOX_SANDBOX_DIR__/tools/out/bin/tool in3.txt > __SBOX_SANDBOX_DIR__/out/in3.h'",
Colin Cross1a527682019-09-23 15:55:30 -0700571 },
Paul Duffine66946b2021-03-16 12:38:33 +0000572 deps: []string{
573 "out/soong/.intermediates/gen/gen/gensrcs/in1.h",
574 "out/soong/.intermediates/gen/gen/gensrcs/in2.h",
575 "out/soong/.intermediates/gen/gen/gensrcs/in3.h",
576 },
577 files: []string{
578 "out/soong/.intermediates/gen/gen/gensrcs/in1.h",
579 "out/soong/.intermediates/gen/gen/gensrcs/in2.h",
580 "out/soong/.intermediates/gen/gen/gensrcs/in3.h",
581 },
Colin Cross1a527682019-09-23 15:55:30 -0700582 },
Liz Kammer81fec182023-06-09 13:33:45 -0400583 {
584 name: "data",
585 prop: `
586 tools: ["tool"],
587 srcs: ["in1.txt", "in2.txt", "in3.txt"],
588 cmd: "$(location) $(in) --extra_input=$(location baz.txt) > $(out)",
589 data: ["baz.txt"],
590 shard_size: 2,
591 `,
592 cmds: []string{
593 "bash -c '__SBOX_SANDBOX_DIR__/tools/out/bin/tool in1.txt --extra_input=baz.txt > __SBOX_SANDBOX_DIR__/out/in1.h' && bash -c '__SBOX_SANDBOX_DIR__/tools/out/bin/tool in2.txt --extra_input=baz.txt > __SBOX_SANDBOX_DIR__/out/in2.h'",
594 "bash -c '__SBOX_SANDBOX_DIR__/tools/out/bin/tool in3.txt --extra_input=baz.txt > __SBOX_SANDBOX_DIR__/out/in3.h'",
595 },
596 deps: []string{
597 "out/soong/.intermediates/gen/gen/gensrcs/in1.h",
598 "out/soong/.intermediates/gen/gen/gensrcs/in2.h",
599 "out/soong/.intermediates/gen/gen/gensrcs/in3.h",
600 },
601 files: []string{
602 "out/soong/.intermediates/gen/gen/gensrcs/in1.h",
603 "out/soong/.intermediates/gen/gen/gensrcs/in2.h",
604 "out/soong/.intermediates/gen/gen/gensrcs/in3.h",
605 },
Liz Kammer796921d2023-07-11 08:21:41 -0400606 shards: 2,
607 inputs: []string{
608 "baz.txt",
609 },
Liz Kammer81fec182023-06-09 13:33:45 -0400610 },
Colin Cross1a527682019-09-23 15:55:30 -0700611 }
612
Liz Kammer796921d2023-07-11 08:21:41 -0400613 checkInputs := func(t *testing.T, rule android.TestingBuildParams, inputs []string) {
614 t.Helper()
615 if len(inputs) == 0 {
616 return
617 }
618 inputBaseNames := map[string]bool{}
619 for _, f := range rule.Implicits {
620 inputBaseNames[f.Base()] = true
621 }
622 for _, f := range inputs {
623 if _, ok := inputBaseNames[f]; !ok {
624 t.Errorf("Expected to find input file %q for %q, but did not", f, rule.Description)
625 }
626 }
627 }
628
Colin Cross1a527682019-09-23 15:55:30 -0700629 for _, test := range testcases {
630 t.Run(test.name, func(t *testing.T) {
Colin Cross1a527682019-09-23 15:55:30 -0700631 bp := "gensrcs {\n"
632 bp += `name: "gen",` + "\n"
633 bp += `output_extension: "h",` + "\n"
634 bp += test.prop
635 bp += "}\n"
636
Paul Duffin672cb9f2021-03-03 02:30:37 +0000637 var expectedErrors []string
638 if test.err != "" {
639 expectedErrors = append(expectedErrors, regexp.QuoteMeta(test.err))
Colin Cross1a527682019-09-23 15:55:30 -0700640 }
Paul Duffin672cb9f2021-03-03 02:30:37 +0000641
Paul Duffin89648f92021-03-20 00:36:55 +0000642 result := prepareForGenRuleTest.
Paul Duffin672cb9f2021-03-03 02:30:37 +0000643 ExtendWithErrorHandler(android.FixtureExpectsAllErrorsToMatchAPattern(expectedErrors)).
644 RunTestWithBp(t, testGenruleBp()+bp)
645
Liz Kammer796921d2023-07-11 08:21:41 -0400646 mod := result.ModuleForTests("gen", "")
Paul Duffin672cb9f2021-03-03 02:30:37 +0000647 if expectedErrors != nil {
Colin Cross1a527682019-09-23 15:55:30 -0700648 return
649 }
650
Liz Kammer796921d2023-07-11 08:21:41 -0400651 if test.shards > 0 {
652 for i := 0; i < test.shards; i++ {
653 r := mod.Rule("generator" + strconv.Itoa(i))
654 checkInputs(t, r, test.inputs)
655 }
656 } else {
657 r := mod.Rule("generator")
658 checkInputs(t, r, test.inputs)
659 }
660
Paul Duffin672cb9f2021-03-03 02:30:37 +0000661 gen := result.Module("gen", "").(*Module)
Paul Duffine84b1332021-03-12 11:59:43 +0000662 android.AssertDeepEquals(t, "cmd", test.cmds, gen.rawCommands)
Colin Cross1a527682019-09-23 15:55:30 -0700663
Paul Duffine66946b2021-03-16 12:38:33 +0000664 android.AssertPathsRelativeToTopEquals(t, "deps", test.deps, gen.outputDeps)
Colin Cross1a527682019-09-23 15:55:30 -0700665
Paul Duffine66946b2021-03-16 12:38:33 +0000666 android.AssertPathsRelativeToTopEquals(t, "files", test.files, gen.outputFiles)
Colin Cross1a527682019-09-23 15:55:30 -0700667 })
668 }
Colin Cross2a076922018-10-04 23:28:25 -0700669}
670
Jaewoong Jung98716bd2018-12-10 08:13:18 -0800671func TestGenruleDefaults(t *testing.T) {
Jaewoong Jung98716bd2018-12-10 08:13:18 -0800672 bp := `
673 genrule_defaults {
674 name: "gen_defaults1",
675 cmd: "cp $(in) $(out)",
676 }
677
678 genrule_defaults {
679 name: "gen_defaults2",
680 srcs: ["in1"],
681 }
682
683 genrule {
684 name: "gen",
685 out: ["out"],
686 defaults: ["gen_defaults1", "gen_defaults2"],
687 }
688 `
Paul Duffin672cb9f2021-03-03 02:30:37 +0000689
Paul Duffin89648f92021-03-20 00:36:55 +0000690 result := prepareForGenRuleTest.RunTestWithBp(t, testGenruleBp()+bp)
Paul Duffin672cb9f2021-03-03 02:30:37 +0000691
692 gen := result.Module("gen", "").(*Module)
Jaewoong Jung98716bd2018-12-10 08:13:18 -0800693
Colin Crosse16ce362020-11-12 08:29:30 -0800694 expectedCmd := "cp in1 __SBOX_SANDBOX_DIR__/out/out"
Paul Duffine84b1332021-03-12 11:59:43 +0000695 android.AssertStringEquals(t, "cmd", expectedCmd, gen.rawCommands[0])
Jaewoong Jung98716bd2018-12-10 08:13:18 -0800696
697 expectedSrcs := []string{"in1"}
Inseob Kim2f730622024-07-23 14:03:40 +0900698 android.AssertDeepEquals(t, "srcs", expectedSrcs, gen.properties.ResolvedSrcs)
Jaewoong Jung98716bd2018-12-10 08:13:18 -0800699}
700
Colin Crossfa65cee2021-03-22 17:05:59 -0700701func TestGenruleAllowMissingDependencies(t *testing.T) {
702 bp := `
703 output {
704 name: "disabled",
705 enabled: false,
706 }
707
708 genrule {
709 name: "gen",
710 srcs: [
711 ":disabled",
712 ],
713 out: ["out"],
714 cmd: "cat $(in) > $(out)",
715 }
716 `
Paul Duffin79abe572021-03-29 02:16:14 +0100717 result := android.GroupFixturePreparers(
718 prepareForGenRuleTest,
Colin Crossfa65cee2021-03-22 17:05:59 -0700719 android.FixtureModifyConfigAndContext(
720 func(config android.Config, ctx *android.TestContext) {
721 config.TestProductVariables.Allow_missing_dependencies = proptools.BoolPtr(true)
722 ctx.SetAllowMissingDependencies(true)
723 })).RunTestWithBp(t, bp)
724
725 gen := result.ModuleForTests("gen", "").Output("out")
726 if gen.Rule != android.ErrorRule {
727 t.Errorf("Expected missing dependency error rule for gen, got %q", gen.Rule.String())
728 }
729}
730
Jooyung Han8c7e3ed2021-06-28 17:35:58 +0900731func TestGenruleOutputFiles(t *testing.T) {
732 bp := `
733 genrule {
734 name: "gen",
735 out: ["foo", "sub/bar"],
736 cmd: "echo foo > $(location foo) && echo bar > $(location sub/bar)",
737 }
738 use_source {
739 name: "gen_foo",
740 srcs: [":gen{foo}"],
741 }
742 use_source {
743 name: "gen_bar",
744 srcs: [":gen{sub/bar}"],
745 }
746 use_source {
747 name: "gen_all",
748 srcs: [":gen"],
749 }
750 `
751
752 result := prepareForGenRuleTest.RunTestWithBp(t, testGenruleBp()+bp)
753 android.AssertPathsRelativeToTopEquals(t,
754 "genrule.tag with output",
755 []string{"out/soong/.intermediates/gen/gen/foo"},
756 result.ModuleForTests("gen_foo", "").Module().(*useSource).srcs)
757 android.AssertPathsRelativeToTopEquals(t,
758 "genrule.tag with output in subdir",
759 []string{"out/soong/.intermediates/gen/gen/sub/bar"},
760 result.ModuleForTests("gen_bar", "").Module().(*useSource).srcs)
761 android.AssertPathsRelativeToTopEquals(t,
762 "genrule.tag with all",
763 []string{"out/soong/.intermediates/gen/gen/foo", "out/soong/.intermediates/gen/gen/sub/bar"},
764 result.ModuleForTests("gen_all", "").Module().(*useSource).srcs)
765}
766
Liz Kammerd38c87c2023-07-17 09:58:50 -0400767func TestGenruleInterface(t *testing.T) {
768 result := android.GroupFixturePreparers(
769 prepareForGenRuleTest,
770 android.FixtureMergeMockFs(android.MockFS{
771 "package-dir/Android.bp": []byte(`
772 genrule {
773 name: "module-name",
774 cmd: "mkdir -p $(genDir) && cat $(in) >> $(genDir)/$(out)",
775 srcs: [
776 "src/foo.proto",
777 ],
778 out: ["proto.h", "bar/proto.h"],
779 export_include_dirs: [".", "bar"],
780 }
781 `),
782 }),
783 ).RunTest(t)
784
785 exportedIncludeDirs := []string{
786 "out/soong/.intermediates/package-dir/module-name/gen/package-dir",
787 "out/soong/.intermediates/package-dir/module-name/gen",
788 "out/soong/.intermediates/package-dir/module-name/gen/package-dir/bar",
789 "out/soong/.intermediates/package-dir/module-name/gen/bar",
790 }
791 gen := result.Module("module-name", "").(*Module)
792
793 android.AssertPathsRelativeToTopEquals(
794 t,
795 "include path",
796 exportedIncludeDirs,
797 gen.GeneratedHeaderDirs(),
798 )
799 android.AssertPathsRelativeToTopEquals(
800 t,
801 "files",
802 []string{
803 "out/soong/.intermediates/package-dir/module-name/gen/proto.h",
804 "out/soong/.intermediates/package-dir/module-name/gen/bar/proto.h",
805 },
806 gen.GeneratedSourceFiles(),
807 )
808}
809
Vinh Tran370e08c2022-09-23 18:09:01 -0400810func TestGenSrcsWithNonRootAndroidBpOutputFiles(t *testing.T) {
811 result := android.GroupFixturePreparers(
812 prepareForGenRuleTest,
813 android.FixtureMergeMockFs(android.MockFS{
814 "external-protos/path/Android.bp": []byte(`
815 filegroup {
816 name: "external-protos",
817 srcs: ["baz/baz.proto", "bar.proto"],
818 }
819 `),
820 "package-dir/Android.bp": []byte(`
821 gensrcs {
822 name: "module-name",
823 cmd: "mkdir -p $(genDir) && cat $(in) >> $(genDir)/$(out)",
824 srcs: [
825 "src/foo.proto",
826 ":external-protos",
827 ],
828 output_extension: "proto.h",
829 }
830 `),
831 }),
832 ).RunTest(t)
833
834 exportedIncludeDir := "out/soong/.intermediates/package-dir/module-name/gen/gensrcs"
835 gen := result.Module("module-name", "").(*Module)
836
837 android.AssertPathsRelativeToTopEquals(
838 t,
839 "include path",
840 []string{exportedIncludeDir},
841 gen.exportedIncludeDirs,
842 )
843 android.AssertPathsRelativeToTopEquals(
844 t,
845 "files",
846 []string{
847 exportedIncludeDir + "/package-dir/src/foo.proto.h",
848 exportedIncludeDir + "/external-protos/path/baz/baz.proto.h",
849 exportedIncludeDir + "/external-protos/path/bar.proto.h",
850 },
851 gen.outputFiles,
852 )
853}
854
855func TestGenSrcsWithSrcsFromExternalPackage(t *testing.T) {
856 bp := `
857 gensrcs {
858 name: "module-name",
859 cmd: "mkdir -p $(genDir) && cat $(in) >> $(genDir)/$(out)",
860 srcs: [
861 ":external-protos",
862 ],
863 output_extension: "proto.h",
864 }
865 `
866 result := android.GroupFixturePreparers(
867 prepareForGenRuleTest,
868 android.FixtureMergeMockFs(android.MockFS{
869 "external-protos/path/Android.bp": []byte(`
870 filegroup {
871 name: "external-protos",
872 srcs: ["foo/foo.proto", "bar.proto"],
873 }
874 `),
875 }),
876 ).RunTestWithBp(t, bp)
877
878 exportedIncludeDir := "out/soong/.intermediates/module-name/gen/gensrcs"
879 gen := result.Module("module-name", "").(*Module)
880
881 android.AssertPathsRelativeToTopEquals(
882 t,
883 "include path",
884 []string{exportedIncludeDir},
885 gen.exportedIncludeDirs,
886 )
887 android.AssertPathsRelativeToTopEquals(
888 t,
889 "files",
890 []string{
891 exportedIncludeDir + "/external-protos/path/foo/foo.proto.h",
892 exportedIncludeDir + "/external-protos/path/bar.proto.h",
893 },
894 gen.outputFiles,
895 )
896}
897
yangbill6d032dd2024-04-18 03:05:49 +0000898func TestGenSrcsWithTrimExtAndOutpuExtension(t *testing.T) {
899 result := android.GroupFixturePreparers(
900 prepareForGenRuleTest,
901 android.FixtureMergeMockFs(android.MockFS{
902 "external-protos/path/Android.bp": []byte(`
903 filegroup {
904 name: "external-protos",
905 srcs: [
906 "baz.a.b.c.proto/baz.a.b.c.proto",
907 "bar.a.b.c.proto",
908 "qux.ext.a.b.c.proto",
909 ],
910 }
911 `),
912 "package-dir/Android.bp": []byte(`
913 gensrcs {
914 name: "module-name",
915 cmd: "mkdir -p $(genDir) && cat $(in) >> $(genDir)/$(out)",
916 srcs: [
917 "src/foo.a.b.c.proto",
918 ":external-protos",
919 ],
920
921 trim_extension: ".a.b.c.proto",
922 output_extension: "proto.h",
923 }
924 `),
925 }),
926 ).RunTest(t)
927
928 exportedIncludeDir := "out/soong/.intermediates/package-dir/module-name/gen/gensrcs"
929 gen := result.Module("module-name", "").(*Module)
930
931 android.AssertPathsRelativeToTopEquals(
932 t,
933 "include path",
934 []string{exportedIncludeDir},
935 gen.exportedIncludeDirs,
936 )
937 android.AssertPathsRelativeToTopEquals(
938 t,
939 "files",
940 []string{
941 exportedIncludeDir + "/package-dir/src/foo.proto.h",
942 exportedIncludeDir + "/external-protos/path/baz.a.b.c.proto/baz.proto.h",
943 exportedIncludeDir + "/external-protos/path/bar.proto.h",
944 exportedIncludeDir + "/external-protos/path/qux.ext.proto.h",
945 },
946 gen.outputFiles,
947 )
948}
949
950func TestGenSrcsWithTrimExtButNoOutpuExtension(t *testing.T) {
951 result := android.GroupFixturePreparers(
952 prepareForGenRuleTest,
953 android.FixtureMergeMockFs(android.MockFS{
954 "external-protos/path/Android.bp": []byte(`
955 filegroup {
956 name: "external-protos",
957 srcs: [
958 "baz.a.b.c.proto/baz.a.b.c.proto",
959 "bar.a.b.c.proto",
960 "qux.ext.a.b.c.proto",
961 ],
962 }
963 `),
964 "package-dir/Android.bp": []byte(`
965 gensrcs {
966 name: "module-name",
967 cmd: "mkdir -p $(genDir) && cat $(in) >> $(genDir)/$(out)",
968 srcs: [
969 "src/foo.a.b.c.proto",
970 ":external-protos",
971 ],
972
973 trim_extension: ".a.b.c.proto",
974 }
975 `),
976 }),
977 ).RunTest(t)
978
979 exportedIncludeDir := "out/soong/.intermediates/package-dir/module-name/gen/gensrcs"
980 gen := result.Module("module-name", "").(*Module)
981
982 android.AssertPathsRelativeToTopEquals(
983 t,
984 "include path",
985 []string{exportedIncludeDir},
986 gen.exportedIncludeDirs,
987 )
988 android.AssertPathsRelativeToTopEquals(
989 t,
990 "files",
991 []string{
992 exportedIncludeDir + "/package-dir/src/foo",
993 exportedIncludeDir + "/external-protos/path/baz.a.b.c.proto/baz",
994 exportedIncludeDir + "/external-protos/path/bar",
995 exportedIncludeDir + "/external-protos/path/qux.ext",
996 },
997 gen.outputFiles,
998 )
999}
1000
1001func TestGenSrcsWithOutpuExtension(t *testing.T) {
1002 result := android.GroupFixturePreparers(
1003 prepareForGenRuleTest,
1004 android.FixtureMergeMockFs(android.MockFS{
1005 "external-protos/path/Android.bp": []byte(`
1006 filegroup {
1007 name: "external-protos",
1008 srcs: ["baz/baz.a.b.c.proto", "bar.a.b.c.proto"],
1009 }
1010 `),
1011 "package-dir/Android.bp": []byte(`
1012 gensrcs {
1013 name: "module-name",
1014 cmd: "mkdir -p $(genDir) && cat $(in) >> $(genDir)/$(out)",
1015 srcs: [
1016 "src/foo.a.b.c.proto",
1017 ":external-protos",
1018 ],
1019
1020 output_extension: "proto.h",
1021 }
1022 `),
1023 }),
1024 ).RunTest(t)
1025
1026 exportedIncludeDir := "out/soong/.intermediates/package-dir/module-name/gen/gensrcs"
1027 gen := result.Module("module-name", "").(*Module)
1028
1029 android.AssertPathsRelativeToTopEquals(
1030 t,
1031 "include path",
1032 []string{exportedIncludeDir},
1033 gen.exportedIncludeDirs,
1034 )
1035 android.AssertPathsRelativeToTopEquals(
1036 t,
1037 "files",
1038 []string{
1039 exportedIncludeDir + "/package-dir/src/foo.a.b.c.proto.h",
1040 exportedIncludeDir + "/external-protos/path/baz/baz.a.b.c.proto.h",
1041 exportedIncludeDir + "/external-protos/path/bar.a.b.c.proto.h",
1042 },
1043 gen.outputFiles,
1044 )
1045}
1046
Martin Stjernholmdbd814d2022-01-12 23:18:30 +00001047func TestPrebuiltTool(t *testing.T) {
1048 testcases := []struct {
1049 name string
1050 bp string
1051 expectedToolName string
1052 }{
1053 {
1054 name: "source only",
1055 bp: `
1056 tool { name: "tool" }
1057 `,
1058 expectedToolName: "bin/tool",
1059 },
1060 {
1061 name: "prebuilt only",
1062 bp: `
1063 prebuilt_tool { name: "tool" }
1064 `,
1065 expectedToolName: "prebuilt_bin/tool",
1066 },
1067 {
1068 name: "source preferred",
1069 bp: `
1070 tool { name: "tool" }
1071 prebuilt_tool { name: "tool" }
1072 `,
1073 expectedToolName: "bin/tool",
1074 },
1075 {
1076 name: "prebuilt preferred",
1077 bp: `
1078 tool { name: "tool" }
1079 prebuilt_tool { name: "tool", prefer: true }
1080 `,
1081 expectedToolName: "prebuilt_bin/prebuilt_tool",
1082 },
1083 {
1084 name: "source disabled",
1085 bp: `
1086 tool { name: "tool", enabled: false }
1087 prebuilt_tool { name: "tool" }
1088 `,
1089 expectedToolName: "prebuilt_bin/prebuilt_tool",
1090 },
1091 }
1092
1093 for _, test := range testcases {
1094 t.Run(test.name, func(t *testing.T) {
1095 result := prepareForGenRuleTest.RunTestWithBp(t, test.bp+`
1096 genrule {
1097 name: "gen",
1098 tools: ["tool"],
1099 out: ["foo"],
1100 cmd: "$(location tool)",
1101 }
1102 `)
1103 gen := result.Module("gen", "").(*Module)
1104 expectedCmd := "__SBOX_SANDBOX_DIR__/tools/out/" + test.expectedToolName
1105 android.AssertStringEquals(t, "command", expectedCmd, gen.rawCommands[0])
1106 })
1107 }
1108}
1109
Jihoon Kangc170af42022-08-20 05:26:38 +00001110func TestGenruleWithGlobPaths(t *testing.T) {
1111 testcases := []struct {
1112 name string
1113 bp string
1114 additionalFiles android.MockFS
1115 expectedCmd string
1116 }{
1117 {
1118 name: "single file in directory with $ sign",
1119 bp: `
1120 genrule {
1121 name: "gen",
1122 srcs: ["inn*.txt"],
1123 out: ["out.txt"],
1124 cmd: "cp $(in) $(out)",
1125 }
1126 `,
1127 additionalFiles: android.MockFS{"inn$1.txt": nil},
1128 expectedCmd: "cp 'inn$1.txt' __SBOX_SANDBOX_DIR__/out/out.txt",
1129 },
1130 {
1131 name: "multiple file in directory with $ sign",
1132 bp: `
1133 genrule {
1134 name: "gen",
1135 srcs: ["inn*.txt"],
1136 out: ["."],
1137 cmd: "cp $(in) $(out)",
1138 }
1139 `,
1140 additionalFiles: android.MockFS{"inn$1.txt": nil, "inn$2.txt": nil},
1141 expectedCmd: "cp 'inn$1.txt' 'inn$2.txt' __SBOX_SANDBOX_DIR__/out",
1142 },
1143 {
1144 name: "file in directory with other shell unsafe character",
1145 bp: `
1146 genrule {
1147 name: "gen",
1148 srcs: ["inn*.txt"],
1149 out: ["out.txt"],
1150 cmd: "cp $(in) $(out)",
1151 }
1152 `,
1153 additionalFiles: android.MockFS{"inn@1.txt": nil},
1154 expectedCmd: "cp 'inn@1.txt' __SBOX_SANDBOX_DIR__/out/out.txt",
1155 },
1156 {
1157 name: "glob location param with filepath containing $",
1158 bp: `
1159 genrule {
1160 name: "gen",
1161 srcs: ["**/inn*"],
1162 out: ["."],
1163 cmd: "cp $(in) $(location **/inn*)",
1164 }
1165 `,
1166 additionalFiles: android.MockFS{"a/inn$1.txt": nil},
1167 expectedCmd: "cp 'a/inn$1.txt' 'a/inn$1.txt'",
1168 },
1169 {
1170 name: "glob locations param with filepath containing $",
1171 bp: `
1172 genrule {
1173 name: "gen",
1174 tool_files: ["**/inn*"],
1175 out: ["out.txt"],
1176 cmd: "cp $(locations **/inn*) $(out)",
1177 }
1178 `,
1179 additionalFiles: android.MockFS{"a/inn$1.txt": nil},
1180 expectedCmd: "cp '__SBOX_SANDBOX_DIR__/tools/src/a/inn$1.txt' __SBOX_SANDBOX_DIR__/out/out.txt",
1181 },
1182 }
1183
1184 for _, test := range testcases {
1185 t.Run(test.name, func(t *testing.T) {
1186 result := android.GroupFixturePreparers(
1187 prepareForGenRuleTest,
1188 android.FixtureMergeMockFs(test.additionalFiles),
1189 ).RunTestWithBp(t, test.bp)
1190 gen := result.Module("gen", "").(*Module)
1191 android.AssertStringEquals(t, "command", test.expectedCmd, gen.rawCommands[0])
1192 })
1193 }
1194}
1195
Cole Faust78f3c3a2024-08-15 17:19:34 -07001196func TestGenruleUsesOrderOnlyBuildNumberFile(t *testing.T) {
1197 testCases := []struct {
1198 name string
1199 bp string
1200 fs android.MockFS
1201 expectedError string
1202 expectedCommand string
1203 }{
1204 {
1205 name: "not allowed when not in allowlist",
1206 fs: android.MockFS{
1207 "foo/Android.bp": []byte(`
1208genrule {
1209 name: "gen",
1210 uses_order_only_build_number_file: true,
1211 cmd: "cp $(build_number_file) $(out)",
1212 out: ["out.txt"],
1213}
1214`),
1215 },
1216 expectedError: `Only allowlisted modules may use uses_order_only_build_number_file: true`,
1217 },
1218 {
1219 name: "normal",
1220 fs: android.MockFS{
1221 "build/soong/tests/Android.bp": []byte(`
1222genrule {
1223 name: "gen",
1224 uses_order_only_build_number_file: true,
1225 cmd: "cp $(build_number_file) $(out)",
1226 out: ["out.txt"],
1227}
1228`),
1229 },
1230 expectedCommand: `cp BUILD_NUMBER_FILE __SBOX_SANDBOX_DIR__/out/out.txt`,
1231 },
1232 }
1233
1234 for _, tc := range testCases {
1235 t.Run(tc.name, func(t *testing.T) {
1236 fixtures := android.GroupFixturePreparers(
1237 prepareForGenRuleTest,
1238 android.PrepareForTestWithVisibility,
1239 android.FixtureMergeMockFs(tc.fs),
1240 android.FixtureModifyConfigAndContext(func(config android.Config, ctx *android.TestContext) {
1241 config.TestProductVariables.BuildNumberFile = proptools.StringPtr("build_number.txt")
1242 }),
1243 )
1244 if tc.expectedError != "" {
1245 fixtures = fixtures.ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern(tc.expectedError))
1246 }
1247 result := fixtures.RunTest(t)
1248
1249 if tc.expectedError == "" {
1250 tc.expectedCommand = strings.ReplaceAll(tc.expectedCommand, "BUILD_NUMBER_FILE", result.Config.SoongOutDir()+"/build_number.txt")
1251 gen := result.Module("gen", "").(*Module)
1252 android.AssertStringEquals(t, "raw commands", tc.expectedCommand, gen.rawCommands[0])
1253 }
1254 })
1255 }
1256}
1257
Colin Cross2a076922018-10-04 23:28:25 -07001258type testTool struct {
1259 android.ModuleBase
1260 outputFile android.Path
1261}
1262
1263func toolFactory() android.Module {
1264 module := &testTool{}
1265 android.InitAndroidArchModule(module, android.HostSupported, android.MultilibFirst)
1266 return module
1267}
1268
Colin Cross2a076922018-10-04 23:28:25 -07001269func (t *testTool) GenerateAndroidBuildActions(ctx android.ModuleContext) {
Colin Crossba9e4032020-11-24 16:32:22 -08001270 t.outputFile = ctx.InstallFile(android.PathForModuleInstall(ctx, "bin"), ctx.ModuleName(), android.PathForOutput(ctx, ctx.ModuleName()))
Colin Cross2a076922018-10-04 23:28:25 -07001271}
1272
1273func (t *testTool) HostToolPath() android.OptionalPath {
1274 return android.OptionalPathForPath(t.outputFile)
1275}
1276
Martin Stjernholmdbd814d2022-01-12 23:18:30 +00001277type prebuiltTestTool struct {
1278 android.ModuleBase
1279 prebuilt android.Prebuilt
1280 testTool
1281}
1282
1283func (p *prebuiltTestTool) Name() string {
1284 return p.prebuilt.Name(p.ModuleBase.Name())
1285}
1286
1287func (p *prebuiltTestTool) Prebuilt() *android.Prebuilt {
1288 return &p.prebuilt
1289}
1290
1291func (t *prebuiltTestTool) GenerateAndroidBuildActions(ctx android.ModuleContext) {
1292 t.outputFile = ctx.InstallFile(android.PathForModuleInstall(ctx, "prebuilt_bin"), ctx.ModuleName(), android.PathForOutput(ctx, ctx.ModuleName()))
1293}
1294
1295func prebuiltToolFactory() android.Module {
1296 module := &prebuiltTestTool{}
1297 android.InitPrebuiltModuleWithoutSrcs(module)
1298 android.InitAndroidArchModule(module, android.HostSupported, android.MultilibFirst)
1299 return module
1300}
1301
Colin Crossfe17f6f2019-03-28 19:30:56 -07001302var _ android.HostToolProvider = (*testTool)(nil)
Martin Stjernholmdbd814d2022-01-12 23:18:30 +00001303var _ android.HostToolProvider = (*prebuiltTestTool)(nil)
Colin Crossfa65cee2021-03-22 17:05:59 -07001304
1305type testOutputProducer struct {
1306 android.ModuleBase
1307 outputFile android.Path
1308}
1309
1310func outputProducerFactory() android.Module {
1311 module := &testOutputProducer{}
1312 android.InitAndroidArchModule(module, android.HostSupported, android.MultilibFirst)
1313 return module
1314}
1315
1316func (t *testOutputProducer) GenerateAndroidBuildActions(ctx android.ModuleContext) {
1317 t.outputFile = ctx.InstallFile(android.PathForModuleInstall(ctx, "bin"), ctx.ModuleName(), android.PathForOutput(ctx, ctx.ModuleName()))
1318}
1319
Jooyung Han8c7e3ed2021-06-28 17:35:58 +09001320type useSource struct {
1321 android.ModuleBase
1322 props struct {
1323 Srcs []string `android:"path"`
1324 }
1325 srcs android.Paths
1326}
1327
1328func (s *useSource) GenerateAndroidBuildActions(ctx android.ModuleContext) {
1329 s.srcs = android.PathsForModuleSrc(ctx, s.props.Srcs)
1330}
1331
1332func useSourceFactory() android.Module {
1333 module := &useSource{}
1334 module.AddProperties(&module.props)
1335 android.InitAndroidModule(module)
1336 return module
1337}