blob: 1ca742213ee24df62754d61e7e0ddaf0aafb4085 [file] [log] [blame]
Colin Cross41955e82019-05-29 14:40:35 -07001// Copyright 2015 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 android
16
Jooyung Hand48f3c32019-08-23 11:18:57 +090017import (
Colin Cross14ec66c2022-10-03 21:02:27 -070018 "github.com/google/blueprint"
Colin Cross6ac95762021-11-09 13:17:44 -080019 "path/filepath"
20 "runtime"
Jooyung Hand48f3c32019-08-23 11:18:57 +090021 "testing"
22)
Colin Cross41955e82019-05-29 14:40:35 -070023
24func TestSrcIsModule(t *testing.T) {
25 type args struct {
26 s string
27 }
28 tests := []struct {
29 name string
30 args args
31 wantModule string
32 }{
33 {
34 name: "file",
35 args: args{
36 s: "foo",
37 },
38 wantModule: "",
39 },
40 {
41 name: "module",
42 args: args{
43 s: ":foo",
44 },
45 wantModule: "foo",
46 },
47 {
48 name: "tag",
49 args: args{
50 s: ":foo{.bar}",
51 },
52 wantModule: "foo{.bar}",
53 },
54 {
55 name: "extra colon",
56 args: args{
57 s: ":foo:bar",
58 },
59 wantModule: "foo:bar",
60 },
Paul Duffine6ba0722021-07-12 20:12:12 +010061 {
62 name: "fully qualified",
63 args: args{
64 s: "//foo:bar",
65 },
66 wantModule: "//foo:bar",
67 },
68 {
69 name: "fully qualified with tag",
70 args: args{
71 s: "//foo:bar{.tag}",
72 },
73 wantModule: "//foo:bar{.tag}",
74 },
75 {
76 name: "invalid unqualified name",
77 args: args{
78 s: ":foo/bar",
79 },
80 wantModule: "",
81 },
Colin Cross41955e82019-05-29 14:40:35 -070082 }
83 for _, tt := range tests {
84 t.Run(tt.name, func(t *testing.T) {
85 if gotModule := SrcIsModule(tt.args.s); gotModule != tt.wantModule {
86 t.Errorf("SrcIsModule() = %v, want %v", gotModule, tt.wantModule)
87 }
88 })
89 }
90}
91
92func TestSrcIsModuleWithTag(t *testing.T) {
93 type args struct {
94 s string
95 }
96 tests := []struct {
97 name string
98 args args
99 wantModule string
100 wantTag string
101 }{
102 {
103 name: "file",
104 args: args{
105 s: "foo",
106 },
107 wantModule: "",
108 wantTag: "",
109 },
110 {
111 name: "module",
112 args: args{
113 s: ":foo",
114 },
115 wantModule: "foo",
116 wantTag: "",
117 },
118 {
119 name: "tag",
120 args: args{
121 s: ":foo{.bar}",
122 },
123 wantModule: "foo",
124 wantTag: ".bar",
125 },
126 {
127 name: "empty tag",
128 args: args{
129 s: ":foo{}",
130 },
131 wantModule: "foo",
132 wantTag: "",
133 },
134 {
135 name: "extra colon",
136 args: args{
137 s: ":foo:bar",
138 },
139 wantModule: "foo:bar",
140 },
141 {
142 name: "invalid tag",
143 args: args{
144 s: ":foo{.bar",
145 },
146 wantModule: "foo{.bar",
147 },
148 {
149 name: "invalid tag 2",
150 args: args{
151 s: ":foo.bar}",
152 },
153 wantModule: "foo.bar}",
154 },
Paul Duffine6ba0722021-07-12 20:12:12 +0100155 {
156 name: "fully qualified",
157 args: args{
158 s: "//foo:bar",
159 },
160 wantModule: "//foo:bar",
161 },
162 {
163 name: "fully qualified with tag",
164 args: args{
165 s: "//foo:bar{.tag}",
166 },
167 wantModule: "//foo:bar",
168 wantTag: ".tag",
169 },
170 {
171 name: "invalid unqualified name",
172 args: args{
173 s: ":foo/bar",
174 },
175 wantModule: "",
176 },
177 {
178 name: "invalid unqualified name with tag",
179 args: args{
180 s: ":foo/bar{.tag}",
181 },
182 wantModule: "",
183 },
Colin Cross41955e82019-05-29 14:40:35 -0700184 }
185 for _, tt := range tests {
186 t.Run(tt.name, func(t *testing.T) {
187 gotModule, gotTag := SrcIsModuleWithTag(tt.args.s)
188 if gotModule != tt.wantModule {
189 t.Errorf("SrcIsModuleWithTag() gotModule = %v, want %v", gotModule, tt.wantModule)
190 }
191 if gotTag != tt.wantTag {
192 t.Errorf("SrcIsModuleWithTag() gotTag = %v, want %v", gotTag, tt.wantTag)
193 }
194 })
195 }
196}
Jooyung Hand48f3c32019-08-23 11:18:57 +0900197
198type depsModule struct {
199 ModuleBase
200 props struct {
201 Deps []string
202 }
203}
204
205func (m *depsModule) GenerateAndroidBuildActions(ctx ModuleContext) {
Colin Cross6ac95762021-11-09 13:17:44 -0800206 outputFile := PathForModuleOut(ctx, ctx.ModuleName())
207 ctx.Build(pctx, BuildParams{
208 Rule: Touch,
209 Output: outputFile,
210 })
211 installFile := ctx.InstallFile(PathForModuleInstall(ctx), ctx.ModuleName(), outputFile)
212 ctx.InstallSymlink(PathForModuleInstall(ctx, "symlinks"), ctx.ModuleName(), installFile)
Jooyung Hand48f3c32019-08-23 11:18:57 +0900213}
214
215func (m *depsModule) DepsMutator(ctx BottomUpMutatorContext) {
Colin Cross6ac95762021-11-09 13:17:44 -0800216 ctx.AddDependency(ctx.Module(), installDepTag{}, m.props.Deps...)
Jooyung Hand48f3c32019-08-23 11:18:57 +0900217}
218
219func depsModuleFactory() Module {
220 m := &depsModule{}
221 m.AddProperties(&m.props)
Colin Cross6ac95762021-11-09 13:17:44 -0800222 InitAndroidArchModule(m, HostAndDeviceDefault, MultilibCommon)
Jooyung Hand48f3c32019-08-23 11:18:57 +0900223 return m
224}
225
Paul Duffinf62dc9b2021-03-16 19:44:51 +0000226var prepareForModuleTests = FixtureRegisterWithContext(func(ctx RegistrationContext) {
227 ctx.RegisterModuleType("deps", depsModuleFactory)
228})
229
Jooyung Hand48f3c32019-08-23 11:18:57 +0900230func TestErrorDependsOnDisabledModule(t *testing.T) {
Jooyung Hand48f3c32019-08-23 11:18:57 +0900231 bp := `
232 deps {
233 name: "foo",
234 deps: ["bar"],
235 }
236 deps {
237 name: "bar",
238 enabled: false,
239 }
240 `
241
Paul Duffin30ac3e72021-03-20 00:36:14 +0000242 prepareForModuleTests.
Paul Duffinf62dc9b2021-03-16 19:44:51 +0000243 ExtendWithErrorHandler(FixtureExpectsAtLeastOneErrorMatchingPattern(`module "foo": depends on disabled module "bar"`)).
Paul Duffin30ac3e72021-03-20 00:36:14 +0000244 RunTestWithBp(t, bp)
Jooyung Hand48f3c32019-08-23 11:18:57 +0900245}
Jingwen Chence679d22020-09-23 04:30:02 +0000246
247func TestValidateCorrectBuildParams(t *testing.T) {
Paul Duffinf62dc9b2021-03-16 19:44:51 +0000248 config := TestConfig(t.TempDir(), nil, "", nil)
Jingwen Chence679d22020-09-23 04:30:02 +0000249 pathContext := PathContextForTesting(config)
250 bparams := convertBuildParams(BuildParams{
251 // Test with Output
252 Output: PathForOutput(pathContext, "undeclared_symlink"),
253 SymlinkOutput: PathForOutput(pathContext, "undeclared_symlink"),
254 })
255
256 err := validateBuildParams(bparams)
257 if err != nil {
258 t.Error(err)
259 }
260
261 bparams = convertBuildParams(BuildParams{
262 // Test with ImplicitOutput
263 ImplicitOutput: PathForOutput(pathContext, "undeclared_symlink"),
264 SymlinkOutput: PathForOutput(pathContext, "undeclared_symlink"),
265 })
266
267 err = validateBuildParams(bparams)
268 if err != nil {
269 t.Error(err)
270 }
271}
272
273func TestValidateIncorrectBuildParams(t *testing.T) {
Paul Duffinf62dc9b2021-03-16 19:44:51 +0000274 config := TestConfig(t.TempDir(), nil, "", nil)
Jingwen Chence679d22020-09-23 04:30:02 +0000275 pathContext := PathContextForTesting(config)
276 params := BuildParams{
277 Output: PathForOutput(pathContext, "regular_output"),
278 Outputs: PathsForOutput(pathContext, []string{"out1", "out2"}),
279 ImplicitOutput: PathForOutput(pathContext, "implicit_output"),
280 ImplicitOutputs: PathsForOutput(pathContext, []string{"i_out1", "_out2"}),
281 SymlinkOutput: PathForOutput(pathContext, "undeclared_symlink"),
282 }
283
284 bparams := convertBuildParams(params)
285 err := validateBuildParams(bparams)
286 if err != nil {
287 FailIfNoMatchingErrors(t, "undeclared_symlink is not a declared output or implicit output", []error{err})
288 } else {
289 t.Errorf("Expected build params to fail validation: %+v", bparams)
290 }
291}
Paul Duffin89968e32020-11-23 18:17:03 +0000292
293func TestDistErrorChecking(t *testing.T) {
294 bp := `
295 deps {
296 name: "foo",
297 dist: {
298 dest: "../invalid-dest",
299 dir: "../invalid-dir",
300 suffix: "invalid/suffix",
301 },
302 dists: [
303 {
304 dest: "../invalid-dest0",
305 dir: "../invalid-dir0",
306 suffix: "invalid/suffix0",
307 },
308 {
309 dest: "../invalid-dest1",
310 dir: "../invalid-dir1",
311 suffix: "invalid/suffix1",
312 },
313 ],
314 }
315 `
316
Paul Duffin89968e32020-11-23 18:17:03 +0000317 expectedErrs := []string{
318 "\\QAndroid.bp:5:13: module \"foo\": dist.dest: Path is outside directory: ../invalid-dest\\E",
319 "\\QAndroid.bp:6:12: module \"foo\": dist.dir: Path is outside directory: ../invalid-dir\\E",
320 "\\QAndroid.bp:7:15: module \"foo\": dist.suffix: Suffix may not contain a '/' character.\\E",
321 "\\QAndroid.bp:11:15: module \"foo\": dists[0].dest: Path is outside directory: ../invalid-dest0\\E",
322 "\\QAndroid.bp:12:14: module \"foo\": dists[0].dir: Path is outside directory: ../invalid-dir0\\E",
323 "\\QAndroid.bp:13:17: module \"foo\": dists[0].suffix: Suffix may not contain a '/' character.\\E",
324 "\\QAndroid.bp:16:15: module \"foo\": dists[1].dest: Path is outside directory: ../invalid-dest1\\E",
325 "\\QAndroid.bp:17:14: module \"foo\": dists[1].dir: Path is outside directory: ../invalid-dir1\\E",
326 "\\QAndroid.bp:18:17: module \"foo\": dists[1].suffix: Suffix may not contain a '/' character.\\E",
327 }
Paul Duffinf62dc9b2021-03-16 19:44:51 +0000328
Paul Duffin30ac3e72021-03-20 00:36:14 +0000329 prepareForModuleTests.
Paul Duffinf62dc9b2021-03-16 19:44:51 +0000330 ExtendWithErrorHandler(FixtureExpectsAllErrorsToMatchAPattern(expectedErrs)).
Paul Duffin30ac3e72021-03-20 00:36:14 +0000331 RunTestWithBp(t, bp)
Paul Duffin89968e32020-11-23 18:17:03 +0000332}
Colin Cross6ac95762021-11-09 13:17:44 -0800333
334func TestInstall(t *testing.T) {
335 if runtime.GOOS != "linux" {
336 t.Skip("requires linux")
337 }
338 bp := `
339 deps {
340 name: "foo",
341 deps: ["bar"],
342 }
343
344 deps {
345 name: "bar",
346 deps: ["baz", "qux"],
347 }
348
349 deps {
350 name: "baz",
351 deps: ["qux"],
352 }
353
354 deps {
355 name: "qux",
356 }
357 `
358
359 result := GroupFixturePreparers(
360 prepareForModuleTests,
361 PrepareForTestWithArchMutator,
362 ).RunTestWithBp(t, bp)
363
364 module := func(name string, host bool) TestingModule {
365 variant := "android_common"
366 if host {
367 variant = result.Config.BuildOSCommonTarget.String()
368 }
369 return result.ModuleForTests(name, variant)
370 }
371
372 outputRule := func(name string) TestingBuildParams { return module(name, false).Output(name) }
373
374 installRule := func(name string) TestingBuildParams {
375 return module(name, false).Output(filepath.Join("out/soong/target/product/test_device/system", name))
376 }
377
378 symlinkRule := func(name string) TestingBuildParams {
379 return module(name, false).Output(filepath.Join("out/soong/target/product/test_device/system/symlinks", name))
380 }
381
382 hostOutputRule := func(name string) TestingBuildParams { return module(name, true).Output(name) }
383
384 hostInstallRule := func(name string) TestingBuildParams {
385 return module(name, true).Output(filepath.Join("out/soong/host/linux-x86", name))
386 }
387
388 hostSymlinkRule := func(name string) TestingBuildParams {
389 return module(name, true).Output(filepath.Join("out/soong/host/linux-x86/symlinks", name))
390 }
391
392 assertInputs := func(params TestingBuildParams, inputs ...Path) {
393 t.Helper()
394 AssertArrayString(t, "expected inputs", Paths(inputs).Strings(),
395 append(PathsIfNonNil(params.Input), params.Inputs...).Strings())
396 }
397
398 assertImplicits := func(params TestingBuildParams, implicits ...Path) {
399 t.Helper()
400 AssertArrayString(t, "expected implicit dependencies", Paths(implicits).Strings(),
401 append(PathsIfNonNil(params.Implicit), params.Implicits...).Strings())
402 }
403
404 assertOrderOnlys := func(params TestingBuildParams, orderonlys ...Path) {
405 t.Helper()
406 AssertArrayString(t, "expected orderonly dependencies", Paths(orderonlys).Strings(),
407 params.OrderOnly.Strings())
408 }
409
410 // Check host install rule dependencies
411 assertInputs(hostInstallRule("foo"), hostOutputRule("foo").Output)
412 assertImplicits(hostInstallRule("foo"),
413 hostInstallRule("bar").Output,
414 hostSymlinkRule("bar").Output,
415 hostInstallRule("baz").Output,
416 hostSymlinkRule("baz").Output,
417 hostInstallRule("qux").Output,
418 hostSymlinkRule("qux").Output,
419 )
420 assertOrderOnlys(hostInstallRule("foo"))
421
Colin Cross64002af2021-11-09 16:37:52 -0800422 // Check host symlink rule dependencies. Host symlinks must use a normal dependency, not an
423 // order-only dependency, so that the tool gets updated when the symlink is depended on.
Colin Cross6ac95762021-11-09 13:17:44 -0800424 assertInputs(hostSymlinkRule("foo"), hostInstallRule("foo").Output)
425 assertImplicits(hostSymlinkRule("foo"))
426 assertOrderOnlys(hostSymlinkRule("foo"))
427
428 // Check device install rule dependencies
429 assertInputs(installRule("foo"), outputRule("foo").Output)
430 assertImplicits(installRule("foo"))
431 assertOrderOnlys(installRule("foo"),
432 installRule("bar").Output,
433 symlinkRule("bar").Output,
434 installRule("baz").Output,
435 symlinkRule("baz").Output,
436 installRule("qux").Output,
437 symlinkRule("qux").Output,
438 )
439
Colin Cross64002af2021-11-09 16:37:52 -0800440 // Check device symlink rule dependencies. Device symlinks could use an order-only dependency,
441 // but the current implementation uses a normal dependency.
Colin Cross6ac95762021-11-09 13:17:44 -0800442 assertInputs(symlinkRule("foo"), installRule("foo").Output)
443 assertImplicits(symlinkRule("foo"))
444 assertOrderOnlys(symlinkRule("foo"))
445}
446
Colin Crossc68db4b2021-11-11 18:59:15 -0800447func TestInstallKatiEnabled(t *testing.T) {
Colin Cross6ac95762021-11-09 13:17:44 -0800448 if runtime.GOOS != "linux" {
449 t.Skip("requires linux")
450 }
451 bp := `
452 deps {
453 name: "foo",
454 deps: ["bar"],
455 }
456
457 deps {
458 name: "bar",
459 deps: ["baz", "qux"],
460 }
461
462 deps {
463 name: "baz",
464 deps: ["qux"],
465 }
466
467 deps {
468 name: "qux",
469 }
470 `
471
472 result := GroupFixturePreparers(
473 prepareForModuleTests,
474 PrepareForTestWithArchMutator,
475 FixtureModifyConfig(SetKatiEnabledForTests),
Martin Stjernholm1ebef5b2022-02-10 23:34:28 +0000476 PrepareForTestWithMakevars,
Colin Cross6ac95762021-11-09 13:17:44 -0800477 ).RunTestWithBp(t, bp)
478
Martin Stjernholm1ebef5b2022-02-10 23:34:28 +0000479 rules := result.InstallMakeRulesForTesting(t)
Colin Cross6ac95762021-11-09 13:17:44 -0800480
481 module := func(name string, host bool) TestingModule {
482 variant := "android_common"
483 if host {
484 variant = result.Config.BuildOSCommonTarget.String()
485 }
486 return result.ModuleForTests(name, variant)
487 }
488
489 outputRule := func(name string) TestingBuildParams { return module(name, false).Output(name) }
490
Martin Stjernholm1ebef5b2022-02-10 23:34:28 +0000491 ruleForOutput := func(output string) InstallMakeRule {
Colin Cross6ac95762021-11-09 13:17:44 -0800492 for _, rule := range rules {
Martin Stjernholm1ebef5b2022-02-10 23:34:28 +0000493 if rule.Target == output {
Colin Cross6ac95762021-11-09 13:17:44 -0800494 return rule
495 }
496 }
497 t.Fatalf("no make install rule for %s", output)
Martin Stjernholm1ebef5b2022-02-10 23:34:28 +0000498 return InstallMakeRule{}
Colin Cross6ac95762021-11-09 13:17:44 -0800499 }
500
Martin Stjernholm1ebef5b2022-02-10 23:34:28 +0000501 installRule := func(name string) InstallMakeRule {
Colin Cross6ac95762021-11-09 13:17:44 -0800502 return ruleForOutput(filepath.Join("out/target/product/test_device/system", name))
503 }
504
Martin Stjernholm1ebef5b2022-02-10 23:34:28 +0000505 symlinkRule := func(name string) InstallMakeRule {
Colin Cross6ac95762021-11-09 13:17:44 -0800506 return ruleForOutput(filepath.Join("out/target/product/test_device/system/symlinks", name))
507 }
508
509 hostOutputRule := func(name string) TestingBuildParams { return module(name, true).Output(name) }
510
Martin Stjernholm1ebef5b2022-02-10 23:34:28 +0000511 hostInstallRule := func(name string) InstallMakeRule {
Colin Cross6ac95762021-11-09 13:17:44 -0800512 return ruleForOutput(filepath.Join("out/host/linux-x86", name))
513 }
514
Martin Stjernholm1ebef5b2022-02-10 23:34:28 +0000515 hostSymlinkRule := func(name string) InstallMakeRule {
Colin Cross6ac95762021-11-09 13:17:44 -0800516 return ruleForOutput(filepath.Join("out/host/linux-x86/symlinks", name))
517 }
518
Martin Stjernholm1ebef5b2022-02-10 23:34:28 +0000519 assertDeps := func(rule InstallMakeRule, deps ...string) {
Colin Cross6ac95762021-11-09 13:17:44 -0800520 t.Helper()
Martin Stjernholm1ebef5b2022-02-10 23:34:28 +0000521 AssertArrayString(t, "expected inputs", deps, rule.Deps)
Colin Cross6ac95762021-11-09 13:17:44 -0800522 }
523
Martin Stjernholm1ebef5b2022-02-10 23:34:28 +0000524 assertOrderOnlys := func(rule InstallMakeRule, orderonlys ...string) {
Colin Cross6ac95762021-11-09 13:17:44 -0800525 t.Helper()
Martin Stjernholm1ebef5b2022-02-10 23:34:28 +0000526 AssertArrayString(t, "expected orderonly dependencies", orderonlys, rule.OrderOnlyDeps)
Colin Cross6ac95762021-11-09 13:17:44 -0800527 }
528
529 // Check host install rule dependencies
530 assertDeps(hostInstallRule("foo"),
531 hostOutputRule("foo").Output.String(),
Martin Stjernholm1ebef5b2022-02-10 23:34:28 +0000532 hostInstallRule("bar").Target,
533 hostSymlinkRule("bar").Target,
534 hostInstallRule("baz").Target,
535 hostSymlinkRule("baz").Target,
536 hostInstallRule("qux").Target,
537 hostSymlinkRule("qux").Target,
Colin Cross6ac95762021-11-09 13:17:44 -0800538 )
539 assertOrderOnlys(hostInstallRule("foo"))
540
Colin Cross64002af2021-11-09 16:37:52 -0800541 // Check host symlink rule dependencies. Host symlinks must use a normal dependency, not an
542 // order-only dependency, so that the tool gets updated when the symlink is depended on.
Martin Stjernholm1ebef5b2022-02-10 23:34:28 +0000543 assertDeps(hostSymlinkRule("foo"), hostInstallRule("foo").Target)
Colin Cross64002af2021-11-09 16:37:52 -0800544 assertOrderOnlys(hostSymlinkRule("foo"))
Colin Cross6ac95762021-11-09 13:17:44 -0800545
546 // Check device install rule dependencies
547 assertDeps(installRule("foo"), outputRule("foo").Output.String())
548 assertOrderOnlys(installRule("foo"),
Martin Stjernholm1ebef5b2022-02-10 23:34:28 +0000549 installRule("bar").Target,
550 symlinkRule("bar").Target,
551 installRule("baz").Target,
552 symlinkRule("baz").Target,
553 installRule("qux").Target,
554 symlinkRule("qux").Target,
Colin Cross6ac95762021-11-09 13:17:44 -0800555 )
556
Colin Cross64002af2021-11-09 16:37:52 -0800557 // Check device symlink rule dependencies. Device symlinks could use an order-only dependency,
558 // but the current implementation uses a normal dependency.
Martin Stjernholm1ebef5b2022-02-10 23:34:28 +0000559 assertDeps(symlinkRule("foo"), installRule("foo").Target)
Colin Cross64002af2021-11-09 16:37:52 -0800560 assertOrderOnlys(symlinkRule("foo"))
Colin Cross6ac95762021-11-09 13:17:44 -0800561}
562
Liz Kammer9525e712022-01-05 13:46:24 -0500563type PropsTestModuleEmbedded struct {
564 Embedded_prop *string
565}
566
Liz Kammer898e0762022-03-22 11:27:26 -0400567type StructInSlice struct {
568 G string
569 H bool
570 I []string
571}
572
Liz Kammer9525e712022-01-05 13:46:24 -0500573type propsTestModule struct {
574 ModuleBase
575 DefaultableModuleBase
576 props struct {
577 A string `android:"arch_variant"`
578 B *bool
579 C []string
580 }
581 otherProps struct {
582 PropsTestModuleEmbedded
583
584 D *int64
585 Nested struct {
586 E *string
587 }
588 F *string `blueprint:"mutated"`
Liz Kammer898e0762022-03-22 11:27:26 -0400589
590 Slice_of_struct []StructInSlice
Liz Kammer9525e712022-01-05 13:46:24 -0500591 }
592}
593
594func propsTestModuleFactory() Module {
595 module := &propsTestModule{}
596 module.AddProperties(&module.props, &module.otherProps)
597 InitAndroidArchModule(module, HostAndDeviceSupported, MultilibBoth)
598 InitDefaultableModule(module)
599 return module
600}
601
602type propsTestModuleDefaults struct {
603 ModuleBase
604 DefaultsModuleBase
605}
606
607func propsTestModuleDefaultsFactory() Module {
608 defaults := &propsTestModuleDefaults{}
609 module := propsTestModule{}
610 defaults.AddProperties(&module.props, &module.otherProps)
611 InitDefaultsModule(defaults)
612 return defaults
613}
614
615func (p *propsTestModule) GenerateAndroidBuildActions(ctx ModuleContext) {
616 str := "abc"
617 p.otherProps.F = &str
618}
619
620func TestUsedProperties(t *testing.T) {
621 testCases := []struct {
622 desc string
623 bp string
624 expectedProps []propInfo
625 }{
626 {
627 desc: "only name",
628 bp: `test {
629 name: "foo",
630 }
631 `,
632 expectedProps: []propInfo{
Liz Kammer898e0762022-03-22 11:27:26 -0400633 propInfo{Name: "Name", Type: "string", Value: "foo"},
Liz Kammer9525e712022-01-05 13:46:24 -0500634 },
635 },
636 {
637 desc: "some props",
638 bp: `test {
639 name: "foo",
640 a: "abc",
641 b: true,
642 d: 123,
643 }
644 `,
645 expectedProps: []propInfo{
Liz Kammer898e0762022-03-22 11:27:26 -0400646 propInfo{Name: "A", Type: "string", Value: "abc"},
647 propInfo{Name: "B", Type: "bool", Value: "true"},
648 propInfo{Name: "D", Type: "int64", Value: "123"},
649 propInfo{Name: "Name", Type: "string", Value: "foo"},
Liz Kammer9525e712022-01-05 13:46:24 -0500650 },
651 },
652 {
653 desc: "unused non-pointer prop",
654 bp: `test {
655 name: "foo",
656 b: true,
657 d: 123,
658 }
659 `,
660 expectedProps: []propInfo{
661 // for non-pointer cannot distinguish between unused and intentionally set to empty
Liz Kammer898e0762022-03-22 11:27:26 -0400662 propInfo{Name: "A", Type: "string", Value: ""},
663 propInfo{Name: "B", Type: "bool", Value: "true"},
664 propInfo{Name: "D", Type: "int64", Value: "123"},
665 propInfo{Name: "Name", Type: "string", Value: "foo"},
Liz Kammer9525e712022-01-05 13:46:24 -0500666 },
667 },
668 {
669 desc: "nested props",
670 bp: `test {
671 name: "foo",
672 nested: {
673 e: "abc",
674 }
675 }
676 `,
677 expectedProps: []propInfo{
Liz Kammer898e0762022-03-22 11:27:26 -0400678 propInfo{Name: "Name", Type: "string", Value: "foo"},
679 propInfo{Name: "Nested.E", Type: "string", Value: "abc"},
Liz Kammer9525e712022-01-05 13:46:24 -0500680 },
681 },
682 {
683 desc: "arch props",
684 bp: `test {
685 name: "foo",
686 arch: {
687 x86_64: {
688 a: "abc",
689 },
690 }
691 }
692 `,
693 expectedProps: []propInfo{
Liz Kammer898e0762022-03-22 11:27:26 -0400694 propInfo{Name: "Arch.X86_64.A", Type: "string", Value: "abc"},
695 propInfo{Name: "Name", Type: "string", Value: "foo"},
Liz Kammer9525e712022-01-05 13:46:24 -0500696 },
697 },
698 {
699 desc: "embedded props",
700 bp: `test {
701 name: "foo",
702 embedded_prop: "a",
703 }
704 `,
705 expectedProps: []propInfo{
Liz Kammer898e0762022-03-22 11:27:26 -0400706 propInfo{Name: "Embedded_prop", Type: "string", Value: "a"},
707 propInfo{Name: "Name", Type: "string", Value: "foo"},
708 },
709 },
710 {
711 desc: "struct slice",
712 bp: `test {
713 name: "foo",
714 slice_of_struct: [
715 {
716 g: "abc",
717 h: false,
718 i: ["baz"],
719 },
720 {
721 g: "def",
722 h: true,
723 i: [],
724 },
725 ]
726 }
727 `,
728 expectedProps: []propInfo{
729 propInfo{Name: "Name", Type: "string", Value: "foo"},
730 propInfo{Name: "Slice_of_struct", Type: "struct slice", Values: []string{
731 `android.StructInSlice{G: abc, H: false, I: [baz]}`,
732 `android.StructInSlice{G: def, H: true, I: []}`,
733 }},
Liz Kammer9525e712022-01-05 13:46:24 -0500734 },
735 },
736 {
737 desc: "defaults",
738 bp: `
739test_defaults {
740 name: "foo_defaults",
741 a: "a",
742 b: true,
Liz Kammer898e0762022-03-22 11:27:26 -0400743 c: ["default_c"],
Liz Kammer9525e712022-01-05 13:46:24 -0500744 embedded_prop:"a",
745 arch: {
746 x86_64: {
Liz Kammer898e0762022-03-22 11:27:26 -0400747 a: "x86_64 a",
Liz Kammer9525e712022-01-05 13:46:24 -0500748 },
749 },
750}
751test {
752 name: "foo",
753 defaults: ["foo_defaults"],
Liz Kammer898e0762022-03-22 11:27:26 -0400754 c: ["c"],
Liz Kammer9525e712022-01-05 13:46:24 -0500755 nested: {
Liz Kammer898e0762022-03-22 11:27:26 -0400756 e: "nested e",
Liz Kammer9525e712022-01-05 13:46:24 -0500757 },
758 target: {
759 linux: {
760 a: "a",
761 },
762 },
763}
764 `,
765 expectedProps: []propInfo{
Liz Kammer898e0762022-03-22 11:27:26 -0400766 propInfo{Name: "A", Type: "string", Value: "a"},
767 propInfo{Name: "Arch.X86_64.A", Type: "string", Value: "x86_64 a"},
768 propInfo{Name: "B", Type: "bool", Value: "true"},
769 propInfo{Name: "C", Type: "string slice", Values: []string{"default_c", "c"}},
770 propInfo{Name: "Defaults", Type: "string slice", Values: []string{"foo_defaults"}},
771 propInfo{Name: "Embedded_prop", Type: "string", Value: "a"},
772 propInfo{Name: "Name", Type: "string", Value: "foo"},
773 propInfo{Name: "Nested.E", Type: "string", Value: "nested e"},
774 propInfo{Name: "Target.Linux.A", Type: "string", Value: "a"},
Liz Kammer9525e712022-01-05 13:46:24 -0500775 },
776 },
777 }
778
779 for _, tc := range testCases {
780 t.Run(tc.desc, func(t *testing.T) {
781 result := GroupFixturePreparers(
782 PrepareForTestWithAllowMissingDependencies,
783 PrepareForTestWithDefaults,
784 FixtureRegisterWithContext(func(ctx RegistrationContext) {
785 ctx.RegisterModuleType("test", propsTestModuleFactory)
786 ctx.RegisterModuleType("test_defaults", propsTestModuleDefaultsFactory)
787 }),
788 FixtureWithRootAndroidBp(tc.bp),
789 ).RunTest(t)
790
791 foo := result.ModuleForTests("foo", "").Module().base()
792
793 AssertDeepEquals(t, "foo ", tc.expectedProps, foo.propertiesWithValues())
794
795 })
796 }
797}
Bob Badour4101c712022-02-09 11:54:35 -0800798
799func TestSortedUniqueNamedPaths(t *testing.T) {
800 type np struct {
801 path, name string
802 }
803 makePaths := func(l []np) NamedPaths {
804 result := make(NamedPaths, 0, len(l))
805 for _, p := range l {
806 result = append(result, NamedPath{PathForTesting(p.path), p.name})
807 }
808 return result
809 }
810
811 tests := []struct {
812 name string
813 in []np
814 expectedOut []np
815 }{
816 {
817 name: "empty",
818 in: []np{},
819 expectedOut: []np{},
820 },
821 {
822 name: "all_same",
823 in: []np{
824 {"a.txt", "A"},
825 {"a.txt", "A"},
826 {"a.txt", "A"},
827 {"a.txt", "A"},
828 {"a.txt", "A"},
829 },
830 expectedOut: []np{
831 {"a.txt", "A"},
832 },
833 },
834 {
835 name: "same_path_different_names",
836 in: []np{
837 {"a.txt", "C"},
838 {"a.txt", "A"},
839 {"a.txt", "D"},
840 {"a.txt", "B"},
841 {"a.txt", "E"},
842 },
843 expectedOut: []np{
844 {"a.txt", "A"},
845 {"a.txt", "B"},
846 {"a.txt", "C"},
847 {"a.txt", "D"},
848 {"a.txt", "E"},
849 },
850 },
851 {
852 name: "different_paths_same_name",
853 in: []np{
854 {"b/b.txt", "A"},
855 {"a/a.txt", "A"},
856 {"a/txt", "A"},
857 {"b", "A"},
858 {"a/b/d", "A"},
859 },
860 expectedOut: []np{
861 {"a/a.txt", "A"},
862 {"a/b/d", "A"},
863 {"a/txt", "A"},
864 {"b/b.txt", "A"},
865 {"b", "A"},
866 },
867 },
868 {
869 name: "all_different",
870 in: []np{
871 {"b/b.txt", "A"},
872 {"a/a.txt", "B"},
873 {"a/txt", "D"},
874 {"b", "C"},
875 {"a/b/d", "E"},
876 },
877 expectedOut: []np{
878 {"a/a.txt", "B"},
879 {"a/b/d", "E"},
880 {"a/txt", "D"},
881 {"b/b.txt", "A"},
882 {"b", "C"},
883 },
884 },
885 {
886 name: "some_different",
887 in: []np{
888 {"b/b.txt", "A"},
889 {"a/a.txt", "B"},
890 {"a/txt", "D"},
891 {"a/b/d", "E"},
892 {"b", "C"},
893 {"a/a.txt", "B"},
894 {"a/b/d", "E"},
895 },
896 expectedOut: []np{
897 {"a/a.txt", "B"},
898 {"a/b/d", "E"},
899 {"a/txt", "D"},
900 {"b/b.txt", "A"},
901 {"b", "C"},
902 },
903 },
904 }
905 for _, tt := range tests {
906 t.Run(tt.name, func(t *testing.T) {
907 actual := SortedUniqueNamedPaths(makePaths(tt.in))
908 expected := makePaths(tt.expectedOut)
909 t.Logf("actual: %v", actual)
910 t.Logf("expected: %v", expected)
911 AssertDeepEquals(t, "SortedUniqueNamedPaths ", expected, actual)
912 })
913 }
914}
Zhenhuang Wang0ac5a432022-08-12 18:49:20 +0800915
Zhenhuang Wang409d2772022-08-22 16:00:05 +0800916func TestSetAndroidMkEntriesWithTestOptions(t *testing.T) {
Zhenhuang Wang0ac5a432022-08-12 18:49:20 +0800917 tests := []struct {
918 name string
919 testOptions CommonTestOptions
920 expected map[string][]string
921 }{
922 {
923 name: "empty",
924 testOptions: CommonTestOptions{},
925 expected: map[string][]string{},
926 },
927 {
928 name: "is unit test",
929 testOptions: CommonTestOptions{
930 Unit_test: boolPtr(true),
931 },
932 expected: map[string][]string{
933 "LOCAL_IS_UNIT_TEST": []string{"true"},
934 },
935 },
936 {
937 name: "is not unit test",
938 testOptions: CommonTestOptions{
939 Unit_test: boolPtr(false),
940 },
941 expected: map[string][]string{},
942 },
Zhenhuang Wang409d2772022-08-22 16:00:05 +0800943 {
944 name: "empty tag",
945 testOptions: CommonTestOptions{
946 Tags: []string{},
947 },
948 expected: map[string][]string{},
949 },
950 {
951 name: "single tag",
952 testOptions: CommonTestOptions{
953 Tags: []string{"tag1"},
954 },
955 expected: map[string][]string{
956 "LOCAL_TEST_OPTIONS_TAGS": []string{"tag1"},
957 },
958 },
959 {
960 name: "multiple tag",
961 testOptions: CommonTestOptions{
962 Tags: []string{"tag1", "tag2", "tag3"},
963 },
964 expected: map[string][]string{
965 "LOCAL_TEST_OPTIONS_TAGS": []string{"tag1", "tag2", "tag3"},
966 },
967 },
Zhenhuang Wang0ac5a432022-08-12 18:49:20 +0800968 }
969 for _, tt := range tests {
970 t.Run(tt.name, func(t *testing.T) {
971 actualEntries := AndroidMkEntries{
972 EntryMap: map[string][]string{},
973 }
974 tt.testOptions.SetAndroidMkEntries(&actualEntries)
975 actual := actualEntries.EntryMap
976 t.Logf("actual: %v", actual)
977 t.Logf("expected: %v", tt.expected)
978 AssertDeepEquals(t, "TestProcessCommonTestOptions ", tt.expected, actual)
979 })
980 }
981}
Colin Cross14ec66c2022-10-03 21:02:27 -0700982
983type fakeBlueprintModule struct{}
984
985func (fakeBlueprintModule) Name() string { return "foo" }
986
987func (fakeBlueprintModule) GenerateBuildActions(blueprint.ModuleContext) {}
988
989type sourceProducerTestModule struct {
990 fakeBlueprintModule
991 source Path
992}
993
994func (s sourceProducerTestModule) Srcs() Paths { return Paths{s.source} }
995
996type outputFileProducerTestModule struct {
997 fakeBlueprintModule
998 output map[string]Path
999 error map[string]error
1000}
1001
1002func (o outputFileProducerTestModule) OutputFiles(tag string) (Paths, error) {
1003 return PathsIfNonNil(o.output[tag]), o.error[tag]
1004}
1005
1006type pathContextAddMissingDependenciesWrapper struct {
1007 PathContext
1008 missingDeps []string
1009}
1010
1011func (p *pathContextAddMissingDependenciesWrapper) AddMissingDependencies(deps []string) {
1012 p.missingDeps = append(p.missingDeps, deps...)
1013}
1014func (p *pathContextAddMissingDependenciesWrapper) OtherModuleName(module blueprint.Module) string {
1015 return module.Name()
1016}
1017
1018func TestOutputFileForModule(t *testing.T) {
1019 testcases := []struct {
1020 name string
1021 module blueprint.Module
1022 tag string
1023 env map[string]string
1024 config func(*config)
1025 expected string
1026 missingDeps []string
1027 }{
1028 {
1029 name: "SourceFileProducer",
1030 module: &sourceProducerTestModule{source: PathForTesting("foo.txt")},
1031 expected: "foo.txt",
1032 },
1033 {
1034 name: "OutputFileProducer",
1035 module: &outputFileProducerTestModule{output: map[string]Path{"": PathForTesting("foo.txt")}},
1036 expected: "foo.txt",
1037 },
1038 {
1039 name: "OutputFileProducer_tag",
1040 module: &outputFileProducerTestModule{output: map[string]Path{"foo": PathForTesting("foo.txt")}},
1041 tag: "foo",
1042 expected: "foo.txt",
1043 },
1044 {
1045 name: "OutputFileProducer_AllowMissingDependencies",
1046 config: func(config *config) {
1047 config.TestProductVariables.Allow_missing_dependencies = boolPtr(true)
1048 },
1049 module: &outputFileProducerTestModule{},
1050 missingDeps: []string{"foo"},
1051 expected: "missing_output_file/foo",
1052 },
1053 }
1054 for _, tt := range testcases {
1055 config := TestConfig(buildDir, tt.env, "", nil)
1056 if tt.config != nil {
1057 tt.config(config.config)
1058 }
1059 ctx := &pathContextAddMissingDependenciesWrapper{
1060 PathContext: PathContextForTesting(config),
1061 }
1062 got := OutputFileForModule(ctx, tt.module, tt.tag)
1063 AssertPathRelativeToTopEquals(t, "expected source path", tt.expected, got)
1064 AssertArrayString(t, "expected missing deps", tt.missingDeps, ctx.missingDeps)
1065 }
1066}