blob: d5bf941379ed2616c32dbf69776489ee0b7b1b1c [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 Cross6ac95762021-11-09 13:17:44 -080018 "path/filepath"
19 "runtime"
Jooyung Hand48f3c32019-08-23 11:18:57 +090020 "testing"
Cole Faust9a346f62024-01-18 20:12:02 +000021
22 "github.com/google/blueprint"
Jooyung Hand48f3c32019-08-23 11:18:57 +090023)
Colin Cross41955e82019-05-29 14:40:35 -070024
25func TestSrcIsModule(t *testing.T) {
26 type args struct {
27 s string
28 }
29 tests := []struct {
30 name string
31 args args
32 wantModule string
33 }{
34 {
35 name: "file",
36 args: args{
37 s: "foo",
38 },
39 wantModule: "",
40 },
41 {
42 name: "module",
43 args: args{
44 s: ":foo",
45 },
46 wantModule: "foo",
47 },
48 {
49 name: "tag",
50 args: args{
51 s: ":foo{.bar}",
52 },
53 wantModule: "foo{.bar}",
54 },
55 {
56 name: "extra colon",
57 args: args{
58 s: ":foo:bar",
59 },
60 wantModule: "foo:bar",
61 },
Paul Duffine6ba0722021-07-12 20:12:12 +010062 {
63 name: "fully qualified",
64 args: args{
65 s: "//foo:bar",
66 },
67 wantModule: "//foo:bar",
68 },
69 {
70 name: "fully qualified with tag",
71 args: args{
72 s: "//foo:bar{.tag}",
73 },
74 wantModule: "//foo:bar{.tag}",
75 },
76 {
77 name: "invalid unqualified name",
78 args: args{
79 s: ":foo/bar",
80 },
81 wantModule: "",
82 },
Colin Cross41955e82019-05-29 14:40:35 -070083 }
84 for _, tt := range tests {
85 t.Run(tt.name, func(t *testing.T) {
86 if gotModule := SrcIsModule(tt.args.s); gotModule != tt.wantModule {
87 t.Errorf("SrcIsModule() = %v, want %v", gotModule, tt.wantModule)
88 }
89 })
90 }
91}
92
93func TestSrcIsModuleWithTag(t *testing.T) {
94 type args struct {
95 s string
96 }
97 tests := []struct {
98 name string
99 args args
100 wantModule string
101 wantTag string
102 }{
103 {
104 name: "file",
105 args: args{
106 s: "foo",
107 },
108 wantModule: "",
109 wantTag: "",
110 },
111 {
112 name: "module",
113 args: args{
114 s: ":foo",
115 },
116 wantModule: "foo",
117 wantTag: "",
118 },
119 {
120 name: "tag",
121 args: args{
122 s: ":foo{.bar}",
123 },
124 wantModule: "foo",
125 wantTag: ".bar",
126 },
127 {
128 name: "empty tag",
129 args: args{
130 s: ":foo{}",
131 },
132 wantModule: "foo",
133 wantTag: "",
134 },
135 {
136 name: "extra colon",
137 args: args{
138 s: ":foo:bar",
139 },
140 wantModule: "foo:bar",
141 },
142 {
143 name: "invalid tag",
144 args: args{
145 s: ":foo{.bar",
146 },
147 wantModule: "foo{.bar",
148 },
149 {
150 name: "invalid tag 2",
151 args: args{
152 s: ":foo.bar}",
153 },
154 wantModule: "foo.bar}",
155 },
Paul Duffine6ba0722021-07-12 20:12:12 +0100156 {
157 name: "fully qualified",
158 args: args{
159 s: "//foo:bar",
160 },
161 wantModule: "//foo:bar",
162 },
163 {
164 name: "fully qualified with tag",
165 args: args{
166 s: "//foo:bar{.tag}",
167 },
168 wantModule: "//foo:bar",
169 wantTag: ".tag",
170 },
171 {
172 name: "invalid unqualified name",
173 args: args{
174 s: ":foo/bar",
175 },
176 wantModule: "",
177 },
178 {
179 name: "invalid unqualified name with tag",
180 args: args{
181 s: ":foo/bar{.tag}",
182 },
183 wantModule: "",
184 },
Colin Cross41955e82019-05-29 14:40:35 -0700185 }
186 for _, tt := range tests {
187 t.Run(tt.name, func(t *testing.T) {
188 gotModule, gotTag := SrcIsModuleWithTag(tt.args.s)
189 if gotModule != tt.wantModule {
190 t.Errorf("SrcIsModuleWithTag() gotModule = %v, want %v", gotModule, tt.wantModule)
191 }
192 if gotTag != tt.wantTag {
193 t.Errorf("SrcIsModuleWithTag() gotTag = %v, want %v", gotTag, tt.wantTag)
194 }
195 })
196 }
197}
Jooyung Hand48f3c32019-08-23 11:18:57 +0900198
199type depsModule struct {
200 ModuleBase
201 props struct {
202 Deps []string
203 }
204}
205
206func (m *depsModule) GenerateAndroidBuildActions(ctx ModuleContext) {
Colin Cross6ac95762021-11-09 13:17:44 -0800207 outputFile := PathForModuleOut(ctx, ctx.ModuleName())
208 ctx.Build(pctx, BuildParams{
209 Rule: Touch,
210 Output: outputFile,
211 })
212 installFile := ctx.InstallFile(PathForModuleInstall(ctx), ctx.ModuleName(), outputFile)
213 ctx.InstallSymlink(PathForModuleInstall(ctx, "symlinks"), ctx.ModuleName(), installFile)
Jooyung Hand48f3c32019-08-23 11:18:57 +0900214}
215
216func (m *depsModule) DepsMutator(ctx BottomUpMutatorContext) {
Colin Cross6ac95762021-11-09 13:17:44 -0800217 ctx.AddDependency(ctx.Module(), installDepTag{}, m.props.Deps...)
Jooyung Hand48f3c32019-08-23 11:18:57 +0900218}
219
220func depsModuleFactory() Module {
221 m := &depsModule{}
222 m.AddProperties(&m.props)
Colin Cross6ac95762021-11-09 13:17:44 -0800223 InitAndroidArchModule(m, HostAndDeviceDefault, MultilibCommon)
Jooyung Hand48f3c32019-08-23 11:18:57 +0900224 return m
225}
226
Paul Duffinf62dc9b2021-03-16 19:44:51 +0000227var prepareForModuleTests = FixtureRegisterWithContext(func(ctx RegistrationContext) {
228 ctx.RegisterModuleType("deps", depsModuleFactory)
229})
230
Jooyung Hand48f3c32019-08-23 11:18:57 +0900231func TestErrorDependsOnDisabledModule(t *testing.T) {
Jooyung Hand48f3c32019-08-23 11:18:57 +0900232 bp := `
233 deps {
234 name: "foo",
235 deps: ["bar"],
236 }
237 deps {
238 name: "bar",
239 enabled: false,
240 }
241 `
242
Paul Duffin30ac3e72021-03-20 00:36:14 +0000243 prepareForModuleTests.
Paul Duffinf62dc9b2021-03-16 19:44:51 +0000244 ExtendWithErrorHandler(FixtureExpectsAtLeastOneErrorMatchingPattern(`module "foo": depends on disabled module "bar"`)).
Paul Duffin30ac3e72021-03-20 00:36:14 +0000245 RunTestWithBp(t, bp)
Jooyung Hand48f3c32019-08-23 11:18:57 +0900246}
Jingwen Chence679d22020-09-23 04:30:02 +0000247
Paul Duffin89968e32020-11-23 18:17:03 +0000248func TestDistErrorChecking(t *testing.T) {
249 bp := `
250 deps {
251 name: "foo",
252 dist: {
253 dest: "../invalid-dest",
254 dir: "../invalid-dir",
255 suffix: "invalid/suffix",
256 },
257 dists: [
258 {
259 dest: "../invalid-dest0",
260 dir: "../invalid-dir0",
261 suffix: "invalid/suffix0",
262 },
263 {
264 dest: "../invalid-dest1",
265 dir: "../invalid-dir1",
266 suffix: "invalid/suffix1",
267 },
268 ],
269 }
270 `
271
Paul Duffin89968e32020-11-23 18:17:03 +0000272 expectedErrs := []string{
273 "\\QAndroid.bp:5:13: module \"foo\": dist.dest: Path is outside directory: ../invalid-dest\\E",
274 "\\QAndroid.bp:6:12: module \"foo\": dist.dir: Path is outside directory: ../invalid-dir\\E",
275 "\\QAndroid.bp:7:15: module \"foo\": dist.suffix: Suffix may not contain a '/' character.\\E",
276 "\\QAndroid.bp:11:15: module \"foo\": dists[0].dest: Path is outside directory: ../invalid-dest0\\E",
277 "\\QAndroid.bp:12:14: module \"foo\": dists[0].dir: Path is outside directory: ../invalid-dir0\\E",
278 "\\QAndroid.bp:13:17: module \"foo\": dists[0].suffix: Suffix may not contain a '/' character.\\E",
279 "\\QAndroid.bp:16:15: module \"foo\": dists[1].dest: Path is outside directory: ../invalid-dest1\\E",
280 "\\QAndroid.bp:17:14: module \"foo\": dists[1].dir: Path is outside directory: ../invalid-dir1\\E",
281 "\\QAndroid.bp:18:17: module \"foo\": dists[1].suffix: Suffix may not contain a '/' character.\\E",
282 }
Paul Duffinf62dc9b2021-03-16 19:44:51 +0000283
Paul Duffin30ac3e72021-03-20 00:36:14 +0000284 prepareForModuleTests.
Paul Duffinf62dc9b2021-03-16 19:44:51 +0000285 ExtendWithErrorHandler(FixtureExpectsAllErrorsToMatchAPattern(expectedErrs)).
Paul Duffin30ac3e72021-03-20 00:36:14 +0000286 RunTestWithBp(t, bp)
Paul Duffin89968e32020-11-23 18:17:03 +0000287}
Colin Cross6ac95762021-11-09 13:17:44 -0800288
289func TestInstall(t *testing.T) {
290 if runtime.GOOS != "linux" {
291 t.Skip("requires linux")
292 }
293 bp := `
294 deps {
295 name: "foo",
296 deps: ["bar"],
297 }
298
299 deps {
300 name: "bar",
301 deps: ["baz", "qux"],
302 }
303
304 deps {
305 name: "baz",
306 deps: ["qux"],
307 }
308
309 deps {
310 name: "qux",
311 }
312 `
313
314 result := GroupFixturePreparers(
315 prepareForModuleTests,
316 PrepareForTestWithArchMutator,
317 ).RunTestWithBp(t, bp)
318
319 module := func(name string, host bool) TestingModule {
320 variant := "android_common"
321 if host {
322 variant = result.Config.BuildOSCommonTarget.String()
323 }
324 return result.ModuleForTests(name, variant)
325 }
326
327 outputRule := func(name string) TestingBuildParams { return module(name, false).Output(name) }
328
329 installRule := func(name string) TestingBuildParams {
330 return module(name, false).Output(filepath.Join("out/soong/target/product/test_device/system", name))
331 }
332
333 symlinkRule := func(name string) TestingBuildParams {
334 return module(name, false).Output(filepath.Join("out/soong/target/product/test_device/system/symlinks", name))
335 }
336
337 hostOutputRule := func(name string) TestingBuildParams { return module(name, true).Output(name) }
338
339 hostInstallRule := func(name string) TestingBuildParams {
340 return module(name, true).Output(filepath.Join("out/soong/host/linux-x86", name))
341 }
342
343 hostSymlinkRule := func(name string) TestingBuildParams {
344 return module(name, true).Output(filepath.Join("out/soong/host/linux-x86/symlinks", name))
345 }
346
347 assertInputs := func(params TestingBuildParams, inputs ...Path) {
348 t.Helper()
349 AssertArrayString(t, "expected inputs", Paths(inputs).Strings(),
350 append(PathsIfNonNil(params.Input), params.Inputs...).Strings())
351 }
352
353 assertImplicits := func(params TestingBuildParams, implicits ...Path) {
354 t.Helper()
355 AssertArrayString(t, "expected implicit dependencies", Paths(implicits).Strings(),
356 append(PathsIfNonNil(params.Implicit), params.Implicits...).Strings())
357 }
358
359 assertOrderOnlys := func(params TestingBuildParams, orderonlys ...Path) {
360 t.Helper()
361 AssertArrayString(t, "expected orderonly dependencies", Paths(orderonlys).Strings(),
362 params.OrderOnly.Strings())
363 }
364
365 // Check host install rule dependencies
366 assertInputs(hostInstallRule("foo"), hostOutputRule("foo").Output)
367 assertImplicits(hostInstallRule("foo"),
368 hostInstallRule("bar").Output,
369 hostSymlinkRule("bar").Output,
370 hostInstallRule("baz").Output,
371 hostSymlinkRule("baz").Output,
372 hostInstallRule("qux").Output,
373 hostSymlinkRule("qux").Output,
374 )
375 assertOrderOnlys(hostInstallRule("foo"))
376
Colin Cross64002af2021-11-09 16:37:52 -0800377 // Check host symlink rule dependencies. Host symlinks must use a normal dependency, not an
378 // order-only dependency, so that the tool gets updated when the symlink is depended on.
Colin Cross6ac95762021-11-09 13:17:44 -0800379 assertInputs(hostSymlinkRule("foo"), hostInstallRule("foo").Output)
380 assertImplicits(hostSymlinkRule("foo"))
381 assertOrderOnlys(hostSymlinkRule("foo"))
382
383 // Check device install rule dependencies
384 assertInputs(installRule("foo"), outputRule("foo").Output)
385 assertImplicits(installRule("foo"))
386 assertOrderOnlys(installRule("foo"),
387 installRule("bar").Output,
388 symlinkRule("bar").Output,
389 installRule("baz").Output,
390 symlinkRule("baz").Output,
391 installRule("qux").Output,
392 symlinkRule("qux").Output,
393 )
394
Colin Cross64002af2021-11-09 16:37:52 -0800395 // Check device symlink rule dependencies. Device symlinks could use an order-only dependency,
396 // but the current implementation uses a normal dependency.
Colin Cross6ac95762021-11-09 13:17:44 -0800397 assertInputs(symlinkRule("foo"), installRule("foo").Output)
398 assertImplicits(symlinkRule("foo"))
399 assertOrderOnlys(symlinkRule("foo"))
400}
401
Colin Crossc68db4b2021-11-11 18:59:15 -0800402func TestInstallKatiEnabled(t *testing.T) {
Colin Cross6ac95762021-11-09 13:17:44 -0800403 if runtime.GOOS != "linux" {
404 t.Skip("requires linux")
405 }
406 bp := `
407 deps {
408 name: "foo",
409 deps: ["bar"],
410 }
411
412 deps {
413 name: "bar",
414 deps: ["baz", "qux"],
415 }
416
417 deps {
418 name: "baz",
419 deps: ["qux"],
420 }
421
422 deps {
423 name: "qux",
424 }
425 `
426
427 result := GroupFixturePreparers(
428 prepareForModuleTests,
429 PrepareForTestWithArchMutator,
430 FixtureModifyConfig(SetKatiEnabledForTests),
Martin Stjernholm1ebef5b2022-02-10 23:34:28 +0000431 PrepareForTestWithMakevars,
Colin Cross6ac95762021-11-09 13:17:44 -0800432 ).RunTestWithBp(t, bp)
433
Martin Stjernholm1ebef5b2022-02-10 23:34:28 +0000434 rules := result.InstallMakeRulesForTesting(t)
Colin Cross6ac95762021-11-09 13:17:44 -0800435
436 module := func(name string, host bool) TestingModule {
437 variant := "android_common"
438 if host {
439 variant = result.Config.BuildOSCommonTarget.String()
440 }
441 return result.ModuleForTests(name, variant)
442 }
443
444 outputRule := func(name string) TestingBuildParams { return module(name, false).Output(name) }
445
Martin Stjernholm1ebef5b2022-02-10 23:34:28 +0000446 ruleForOutput := func(output string) InstallMakeRule {
Colin Cross6ac95762021-11-09 13:17:44 -0800447 for _, rule := range rules {
Martin Stjernholm1ebef5b2022-02-10 23:34:28 +0000448 if rule.Target == output {
Colin Cross6ac95762021-11-09 13:17:44 -0800449 return rule
450 }
451 }
452 t.Fatalf("no make install rule for %s", output)
Martin Stjernholm1ebef5b2022-02-10 23:34:28 +0000453 return InstallMakeRule{}
Colin Cross6ac95762021-11-09 13:17:44 -0800454 }
455
Martin Stjernholm1ebef5b2022-02-10 23:34:28 +0000456 installRule := func(name string) InstallMakeRule {
Colin Cross6ac95762021-11-09 13:17:44 -0800457 return ruleForOutput(filepath.Join("out/target/product/test_device/system", name))
458 }
459
Martin Stjernholm1ebef5b2022-02-10 23:34:28 +0000460 symlinkRule := func(name string) InstallMakeRule {
Colin Cross6ac95762021-11-09 13:17:44 -0800461 return ruleForOutput(filepath.Join("out/target/product/test_device/system/symlinks", name))
462 }
463
464 hostOutputRule := func(name string) TestingBuildParams { return module(name, true).Output(name) }
465
Martin Stjernholm1ebef5b2022-02-10 23:34:28 +0000466 hostInstallRule := func(name string) InstallMakeRule {
Colin Cross6ac95762021-11-09 13:17:44 -0800467 return ruleForOutput(filepath.Join("out/host/linux-x86", name))
468 }
469
Martin Stjernholm1ebef5b2022-02-10 23:34:28 +0000470 hostSymlinkRule := func(name string) InstallMakeRule {
Colin Cross6ac95762021-11-09 13:17:44 -0800471 return ruleForOutput(filepath.Join("out/host/linux-x86/symlinks", name))
472 }
473
Martin Stjernholm1ebef5b2022-02-10 23:34:28 +0000474 assertDeps := func(rule InstallMakeRule, deps ...string) {
Colin Cross6ac95762021-11-09 13:17:44 -0800475 t.Helper()
Martin Stjernholm1ebef5b2022-02-10 23:34:28 +0000476 AssertArrayString(t, "expected inputs", deps, rule.Deps)
Colin Cross6ac95762021-11-09 13:17:44 -0800477 }
478
Martin Stjernholm1ebef5b2022-02-10 23:34:28 +0000479 assertOrderOnlys := func(rule InstallMakeRule, orderonlys ...string) {
Colin Cross6ac95762021-11-09 13:17:44 -0800480 t.Helper()
Martin Stjernholm1ebef5b2022-02-10 23:34:28 +0000481 AssertArrayString(t, "expected orderonly dependencies", orderonlys, rule.OrderOnlyDeps)
Colin Cross6ac95762021-11-09 13:17:44 -0800482 }
483
484 // Check host install rule dependencies
485 assertDeps(hostInstallRule("foo"),
486 hostOutputRule("foo").Output.String(),
Martin Stjernholm1ebef5b2022-02-10 23:34:28 +0000487 hostInstallRule("bar").Target,
488 hostSymlinkRule("bar").Target,
489 hostInstallRule("baz").Target,
490 hostSymlinkRule("baz").Target,
491 hostInstallRule("qux").Target,
492 hostSymlinkRule("qux").Target,
Colin Cross6ac95762021-11-09 13:17:44 -0800493 )
494 assertOrderOnlys(hostInstallRule("foo"))
495
Colin Cross64002af2021-11-09 16:37:52 -0800496 // Check host symlink rule dependencies. Host symlinks must use a normal dependency, not an
497 // order-only dependency, so that the tool gets updated when the symlink is depended on.
Martin Stjernholm1ebef5b2022-02-10 23:34:28 +0000498 assertDeps(hostSymlinkRule("foo"), hostInstallRule("foo").Target)
Colin Cross64002af2021-11-09 16:37:52 -0800499 assertOrderOnlys(hostSymlinkRule("foo"))
Colin Cross6ac95762021-11-09 13:17:44 -0800500
501 // Check device install rule dependencies
502 assertDeps(installRule("foo"), outputRule("foo").Output.String())
503 assertOrderOnlys(installRule("foo"),
Martin Stjernholm1ebef5b2022-02-10 23:34:28 +0000504 installRule("bar").Target,
505 symlinkRule("bar").Target,
506 installRule("baz").Target,
507 symlinkRule("baz").Target,
508 installRule("qux").Target,
509 symlinkRule("qux").Target,
Colin Cross6ac95762021-11-09 13:17:44 -0800510 )
511
Colin Cross64002af2021-11-09 16:37:52 -0800512 // Check device symlink rule dependencies. Device symlinks could use an order-only dependency,
513 // but the current implementation uses a normal dependency.
Martin Stjernholm1ebef5b2022-02-10 23:34:28 +0000514 assertDeps(symlinkRule("foo"), installRule("foo").Target)
Colin Cross64002af2021-11-09 16:37:52 -0800515 assertOrderOnlys(symlinkRule("foo"))
Colin Cross6ac95762021-11-09 13:17:44 -0800516}
517
Liz Kammer9525e712022-01-05 13:46:24 -0500518type PropsTestModuleEmbedded struct {
519 Embedded_prop *string
520}
521
Liz Kammer898e0762022-03-22 11:27:26 -0400522type StructInSlice struct {
523 G string
524 H bool
525 I []string
526}
527
Liz Kammer9525e712022-01-05 13:46:24 -0500528type propsTestModule struct {
529 ModuleBase
530 DefaultableModuleBase
531 props struct {
532 A string `android:"arch_variant"`
533 B *bool
534 C []string
535 }
536 otherProps struct {
537 PropsTestModuleEmbedded
538
539 D *int64
540 Nested struct {
541 E *string
542 }
543 F *string `blueprint:"mutated"`
Liz Kammer898e0762022-03-22 11:27:26 -0400544
545 Slice_of_struct []StructInSlice
Liz Kammer9525e712022-01-05 13:46:24 -0500546 }
547}
548
549func propsTestModuleFactory() Module {
550 module := &propsTestModule{}
551 module.AddProperties(&module.props, &module.otherProps)
552 InitAndroidArchModule(module, HostAndDeviceSupported, MultilibBoth)
553 InitDefaultableModule(module)
554 return module
555}
556
557type propsTestModuleDefaults struct {
558 ModuleBase
559 DefaultsModuleBase
560}
561
562func propsTestModuleDefaultsFactory() Module {
563 defaults := &propsTestModuleDefaults{}
564 module := propsTestModule{}
565 defaults.AddProperties(&module.props, &module.otherProps)
566 InitDefaultsModule(defaults)
567 return defaults
568}
569
570func (p *propsTestModule) GenerateAndroidBuildActions(ctx ModuleContext) {
571 str := "abc"
572 p.otherProps.F = &str
573}
574
575func TestUsedProperties(t *testing.T) {
576 testCases := []struct {
577 desc string
578 bp string
579 expectedProps []propInfo
580 }{
581 {
582 desc: "only name",
583 bp: `test {
584 name: "foo",
585 }
586 `,
587 expectedProps: []propInfo{
Liz Kammer898e0762022-03-22 11:27:26 -0400588 propInfo{Name: "Name", Type: "string", Value: "foo"},
Liz Kammer9525e712022-01-05 13:46:24 -0500589 },
590 },
591 {
592 desc: "some props",
593 bp: `test {
594 name: "foo",
595 a: "abc",
596 b: true,
597 d: 123,
598 }
599 `,
600 expectedProps: []propInfo{
Liz Kammer898e0762022-03-22 11:27:26 -0400601 propInfo{Name: "A", Type: "string", Value: "abc"},
602 propInfo{Name: "B", Type: "bool", Value: "true"},
603 propInfo{Name: "D", Type: "int64", Value: "123"},
604 propInfo{Name: "Name", Type: "string", Value: "foo"},
Liz Kammer9525e712022-01-05 13:46:24 -0500605 },
606 },
607 {
608 desc: "unused non-pointer prop",
609 bp: `test {
610 name: "foo",
611 b: true,
612 d: 123,
613 }
614 `,
615 expectedProps: []propInfo{
616 // for non-pointer cannot distinguish between unused and intentionally set to empty
Liz Kammer898e0762022-03-22 11:27:26 -0400617 propInfo{Name: "A", Type: "string", Value: ""},
618 propInfo{Name: "B", Type: "bool", Value: "true"},
619 propInfo{Name: "D", Type: "int64", Value: "123"},
620 propInfo{Name: "Name", Type: "string", Value: "foo"},
Liz Kammer9525e712022-01-05 13:46:24 -0500621 },
622 },
623 {
624 desc: "nested props",
625 bp: `test {
626 name: "foo",
627 nested: {
628 e: "abc",
629 }
630 }
631 `,
632 expectedProps: []propInfo{
Liz Kammer898e0762022-03-22 11:27:26 -0400633 propInfo{Name: "Name", Type: "string", Value: "foo"},
634 propInfo{Name: "Nested.E", Type: "string", Value: "abc"},
Liz Kammer9525e712022-01-05 13:46:24 -0500635 },
636 },
637 {
638 desc: "arch props",
639 bp: `test {
640 name: "foo",
641 arch: {
642 x86_64: {
643 a: "abc",
644 },
645 }
646 }
647 `,
648 expectedProps: []propInfo{
Liz Kammer898e0762022-03-22 11:27:26 -0400649 propInfo{Name: "Arch.X86_64.A", Type: "string", Value: "abc"},
650 propInfo{Name: "Name", Type: "string", Value: "foo"},
Liz Kammer9525e712022-01-05 13:46:24 -0500651 },
652 },
653 {
654 desc: "embedded props",
655 bp: `test {
656 name: "foo",
657 embedded_prop: "a",
658 }
659 `,
660 expectedProps: []propInfo{
Liz Kammer898e0762022-03-22 11:27:26 -0400661 propInfo{Name: "Embedded_prop", Type: "string", Value: "a"},
662 propInfo{Name: "Name", Type: "string", Value: "foo"},
663 },
664 },
665 {
666 desc: "struct slice",
667 bp: `test {
668 name: "foo",
669 slice_of_struct: [
670 {
671 g: "abc",
672 h: false,
673 i: ["baz"],
674 },
675 {
676 g: "def",
677 h: true,
678 i: [],
679 },
680 ]
681 }
682 `,
683 expectedProps: []propInfo{
684 propInfo{Name: "Name", Type: "string", Value: "foo"},
685 propInfo{Name: "Slice_of_struct", Type: "struct slice", Values: []string{
686 `android.StructInSlice{G: abc, H: false, I: [baz]}`,
687 `android.StructInSlice{G: def, H: true, I: []}`,
688 }},
Liz Kammer9525e712022-01-05 13:46:24 -0500689 },
690 },
691 {
692 desc: "defaults",
693 bp: `
694test_defaults {
695 name: "foo_defaults",
696 a: "a",
697 b: true,
Liz Kammer898e0762022-03-22 11:27:26 -0400698 c: ["default_c"],
Liz Kammer9525e712022-01-05 13:46:24 -0500699 embedded_prop:"a",
700 arch: {
701 x86_64: {
Liz Kammer898e0762022-03-22 11:27:26 -0400702 a: "x86_64 a",
Liz Kammer9525e712022-01-05 13:46:24 -0500703 },
704 },
705}
706test {
707 name: "foo",
708 defaults: ["foo_defaults"],
Liz Kammer898e0762022-03-22 11:27:26 -0400709 c: ["c"],
Liz Kammer9525e712022-01-05 13:46:24 -0500710 nested: {
Liz Kammer898e0762022-03-22 11:27:26 -0400711 e: "nested e",
Liz Kammer9525e712022-01-05 13:46:24 -0500712 },
713 target: {
714 linux: {
715 a: "a",
716 },
717 },
718}
719 `,
720 expectedProps: []propInfo{
Liz Kammer898e0762022-03-22 11:27:26 -0400721 propInfo{Name: "A", Type: "string", Value: "a"},
722 propInfo{Name: "Arch.X86_64.A", Type: "string", Value: "x86_64 a"},
723 propInfo{Name: "B", Type: "bool", Value: "true"},
724 propInfo{Name: "C", Type: "string slice", Values: []string{"default_c", "c"}},
Cole Faust52d37c32024-08-23 16:20:58 -0700725 propInfo{Name: "Defaults", Type: "string slice", Values: []string{"foo_defaults"}},
Liz Kammer898e0762022-03-22 11:27:26 -0400726 propInfo{Name: "Embedded_prop", Type: "string", Value: "a"},
727 propInfo{Name: "Name", Type: "string", Value: "foo"},
728 propInfo{Name: "Nested.E", Type: "string", Value: "nested e"},
729 propInfo{Name: "Target.Linux.A", Type: "string", Value: "a"},
Liz Kammer9525e712022-01-05 13:46:24 -0500730 },
731 },
732 }
733
734 for _, tc := range testCases {
735 t.Run(tc.desc, func(t *testing.T) {
736 result := GroupFixturePreparers(
737 PrepareForTestWithAllowMissingDependencies,
738 PrepareForTestWithDefaults,
739 FixtureRegisterWithContext(func(ctx RegistrationContext) {
740 ctx.RegisterModuleType("test", propsTestModuleFactory)
741 ctx.RegisterModuleType("test_defaults", propsTestModuleDefaultsFactory)
742 }),
743 FixtureWithRootAndroidBp(tc.bp),
744 ).RunTest(t)
745
746 foo := result.ModuleForTests("foo", "").Module().base()
747
748 AssertDeepEquals(t, "foo ", tc.expectedProps, foo.propertiesWithValues())
Liz Kammer9525e712022-01-05 13:46:24 -0500749 })
750 }
751}
Bob Badour4101c712022-02-09 11:54:35 -0800752
753func TestSortedUniqueNamedPaths(t *testing.T) {
754 type np struct {
755 path, name string
756 }
757 makePaths := func(l []np) NamedPaths {
758 result := make(NamedPaths, 0, len(l))
759 for _, p := range l {
760 result = append(result, NamedPath{PathForTesting(p.path), p.name})
761 }
762 return result
763 }
764
765 tests := []struct {
766 name string
767 in []np
768 expectedOut []np
769 }{
770 {
771 name: "empty",
772 in: []np{},
773 expectedOut: []np{},
774 },
775 {
776 name: "all_same",
777 in: []np{
778 {"a.txt", "A"},
779 {"a.txt", "A"},
780 {"a.txt", "A"},
781 {"a.txt", "A"},
782 {"a.txt", "A"},
783 },
784 expectedOut: []np{
785 {"a.txt", "A"},
786 },
787 },
788 {
789 name: "same_path_different_names",
790 in: []np{
791 {"a.txt", "C"},
792 {"a.txt", "A"},
793 {"a.txt", "D"},
794 {"a.txt", "B"},
795 {"a.txt", "E"},
796 },
797 expectedOut: []np{
798 {"a.txt", "A"},
799 {"a.txt", "B"},
800 {"a.txt", "C"},
801 {"a.txt", "D"},
802 {"a.txt", "E"},
803 },
804 },
805 {
806 name: "different_paths_same_name",
807 in: []np{
808 {"b/b.txt", "A"},
809 {"a/a.txt", "A"},
810 {"a/txt", "A"},
811 {"b", "A"},
812 {"a/b/d", "A"},
813 },
814 expectedOut: []np{
815 {"a/a.txt", "A"},
816 {"a/b/d", "A"},
817 {"a/txt", "A"},
818 {"b/b.txt", "A"},
819 {"b", "A"},
820 },
821 },
822 {
823 name: "all_different",
824 in: []np{
825 {"b/b.txt", "A"},
826 {"a/a.txt", "B"},
827 {"a/txt", "D"},
828 {"b", "C"},
829 {"a/b/d", "E"},
830 },
831 expectedOut: []np{
832 {"a/a.txt", "B"},
833 {"a/b/d", "E"},
834 {"a/txt", "D"},
835 {"b/b.txt", "A"},
836 {"b", "C"},
837 },
838 },
839 {
840 name: "some_different",
841 in: []np{
842 {"b/b.txt", "A"},
843 {"a/a.txt", "B"},
844 {"a/txt", "D"},
845 {"a/b/d", "E"},
846 {"b", "C"},
847 {"a/a.txt", "B"},
848 {"a/b/d", "E"},
849 },
850 expectedOut: []np{
851 {"a/a.txt", "B"},
852 {"a/b/d", "E"},
853 {"a/txt", "D"},
854 {"b/b.txt", "A"},
855 {"b", "C"},
856 },
857 },
858 }
859 for _, tt := range tests {
860 t.Run(tt.name, func(t *testing.T) {
861 actual := SortedUniqueNamedPaths(makePaths(tt.in))
862 expected := makePaths(tt.expectedOut)
863 t.Logf("actual: %v", actual)
864 t.Logf("expected: %v", expected)
865 AssertDeepEquals(t, "SortedUniqueNamedPaths ", expected, actual)
866 })
867 }
868}
Zhenhuang Wang0ac5a432022-08-12 18:49:20 +0800869
Zhenhuang Wang409d2772022-08-22 16:00:05 +0800870func TestSetAndroidMkEntriesWithTestOptions(t *testing.T) {
Zhenhuang Wang0ac5a432022-08-12 18:49:20 +0800871 tests := []struct {
872 name string
873 testOptions CommonTestOptions
874 expected map[string][]string
875 }{
876 {
877 name: "empty",
878 testOptions: CommonTestOptions{},
879 expected: map[string][]string{},
880 },
881 {
882 name: "is unit test",
883 testOptions: CommonTestOptions{
884 Unit_test: boolPtr(true),
885 },
886 expected: map[string][]string{
887 "LOCAL_IS_UNIT_TEST": []string{"true"},
888 },
889 },
890 {
891 name: "is not unit test",
892 testOptions: CommonTestOptions{
893 Unit_test: boolPtr(false),
894 },
895 expected: map[string][]string{},
896 },
Zhenhuang Wang409d2772022-08-22 16:00:05 +0800897 {
898 name: "empty tag",
899 testOptions: CommonTestOptions{
900 Tags: []string{},
901 },
902 expected: map[string][]string{},
903 },
904 {
905 name: "single tag",
906 testOptions: CommonTestOptions{
907 Tags: []string{"tag1"},
908 },
909 expected: map[string][]string{
910 "LOCAL_TEST_OPTIONS_TAGS": []string{"tag1"},
911 },
912 },
913 {
914 name: "multiple tag",
915 testOptions: CommonTestOptions{
916 Tags: []string{"tag1", "tag2", "tag3"},
917 },
918 expected: map[string][]string{
919 "LOCAL_TEST_OPTIONS_TAGS": []string{"tag1", "tag2", "tag3"},
920 },
921 },
Zhenhuang Wang0ac5a432022-08-12 18:49:20 +0800922 }
923 for _, tt := range tests {
924 t.Run(tt.name, func(t *testing.T) {
925 actualEntries := AndroidMkEntries{
926 EntryMap: map[string][]string{},
927 }
928 tt.testOptions.SetAndroidMkEntries(&actualEntries)
929 actual := actualEntries.EntryMap
930 t.Logf("actual: %v", actual)
931 t.Logf("expected: %v", tt.expected)
932 AssertDeepEquals(t, "TestProcessCommonTestOptions ", tt.expected, actual)
933 })
934 }
935}
Colin Cross14ec66c2022-10-03 21:02:27 -0700936
Colin Cross14ec66c2022-10-03 21:02:27 -0700937type sourceProducerTestModule struct {
mrziwang1ea01e32024-07-12 12:26:34 -0700938 ModuleBase
939 props struct {
940 // A represents the source file
941 A string
942 }
Colin Cross14ec66c2022-10-03 21:02:27 -0700943}
944
mrziwang1ea01e32024-07-12 12:26:34 -0700945func sourceProducerTestModuleFactory() Module {
946 module := &sourceProducerTestModule{}
947 module.AddProperties(&module.props)
948 InitAndroidModule(module)
949 return module
Colin Cross14ec66c2022-10-03 21:02:27 -0700950}
951
mrziwang1ea01e32024-07-12 12:26:34 -0700952func (s sourceProducerTestModule) GenerateAndroidBuildActions(ModuleContext) {}
953
954func (s sourceProducerTestModule) Srcs() Paths { return PathsForTesting(s.props.A) }
955
956type outputFilesTestModule struct {
957 ModuleBase
958 props struct {
959 // A represents the tag
960 A string
961 // B represents the output file for tag A
962 B string
963 }
964}
965
966func outputFilesTestModuleFactory() Module {
967 module := &outputFilesTestModule{}
968 module.AddProperties(&module.props)
969 InitAndroidModule(module)
970 return module
971}
972
973func (o outputFilesTestModule) GenerateAndroidBuildActions(ctx ModuleContext) {
974 if o.props.A != "" || o.props.B != "" {
975 ctx.SetOutputFiles(PathsForTesting(o.props.B), o.props.A)
976 }
977 // This is to simulate the case that some module uses an object to set its
978 // OutputFilesProvider, but the object itself is empty.
979 ctx.SetOutputFiles(Paths{}, "missing")
Colin Cross14ec66c2022-10-03 21:02:27 -0700980}
981
982type pathContextAddMissingDependenciesWrapper struct {
983 PathContext
mrziwang1ea01e32024-07-12 12:26:34 -0700984 OtherModuleProviderContext
Colin Cross14ec66c2022-10-03 21:02:27 -0700985 missingDeps []string
986}
987
988func (p *pathContextAddMissingDependenciesWrapper) AddMissingDependencies(deps []string) {
989 p.missingDeps = append(p.missingDeps, deps...)
990}
991func (p *pathContextAddMissingDependenciesWrapper) OtherModuleName(module blueprint.Module) string {
992 return module.Name()
993}
994
mrziwang1ea01e32024-07-12 12:26:34 -0700995func (p *pathContextAddMissingDependenciesWrapper) Module() Module { return nil }
996
Yu Liu876b7ce2024-08-21 18:20:13 +0000997func (p *pathContextAddMissingDependenciesWrapper) GetOutputFiles() OutputFilesInfo {
998 return OutputFilesInfo{}
999}
1000
Yu Liud3228ac2024-11-08 23:11:47 +00001001func (p *pathContextAddMissingDependenciesWrapper) EqualModules(m1, m2 Module) bool {
1002 return m1 == m2
1003}
1004
Colin Cross14ec66c2022-10-03 21:02:27 -07001005func TestOutputFileForModule(t *testing.T) {
1006 testcases := []struct {
1007 name string
mrziwang1ea01e32024-07-12 12:26:34 -07001008 bp string
Colin Cross14ec66c2022-10-03 21:02:27 -07001009 tag string
Colin Cross14ec66c2022-10-03 21:02:27 -07001010 expected string
1011 missingDeps []string
mrziwang1ea01e32024-07-12 12:26:34 -07001012 env map[string]string
1013 config func(*config)
Colin Cross14ec66c2022-10-03 21:02:27 -07001014 }{
1015 {
mrziwang1ea01e32024-07-12 12:26:34 -07001016 name: "SourceFileProducer",
1017 bp: `spt_module {
1018 name: "test_module",
1019 a: "spt.txt",
1020 }
1021 `,
1022 tag: "",
1023 expected: "spt.txt",
Colin Cross14ec66c2022-10-03 21:02:27 -07001024 },
1025 {
mrziwang1ea01e32024-07-12 12:26:34 -07001026 name: "OutputFileProviderEmptyStringTag",
1027 bp: `oft_module {
1028 name: "test_module",
1029 a: "",
1030 b: "empty.txt",
1031 }
1032 `,
1033 tag: "",
1034 expected: "empty.txt",
Colin Cross14ec66c2022-10-03 21:02:27 -07001035 },
1036 {
mrziwang1ea01e32024-07-12 12:26:34 -07001037 name: "OutputFileProviderTag",
1038 bp: `oft_module {
1039 name: "test_module",
1040 a: "foo",
1041 b: "foo.txt",
1042 }
1043 `,
Colin Cross14ec66c2022-10-03 21:02:27 -07001044 tag: "foo",
1045 expected: "foo.txt",
1046 },
1047 {
mrziwang1ea01e32024-07-12 12:26:34 -07001048 name: "OutputFileAllowMissingDependencies",
1049 bp: `oft_module {
1050 name: "test_module",
1051 }
1052 `,
1053 tag: "missing",
1054 expected: "missing_output_file/test_module",
1055 missingDeps: []string{"test_module"},
Colin Cross14ec66c2022-10-03 21:02:27 -07001056 config: func(config *config) {
1057 config.TestProductVariables.Allow_missing_dependencies = boolPtr(true)
1058 },
Colin Cross14ec66c2022-10-03 21:02:27 -07001059 },
1060 }
mrziwang1ea01e32024-07-12 12:26:34 -07001061
Colin Cross14ec66c2022-10-03 21:02:27 -07001062 for _, tt := range testcases {
mrziwang1ea01e32024-07-12 12:26:34 -07001063 t.Run(tt.name, func(t *testing.T) {
1064 result := GroupFixturePreparers(
1065 PrepareForTestWithDefaults,
1066 FixtureRegisterWithContext(func(ctx RegistrationContext) {
1067 ctx.RegisterModuleType("spt_module", sourceProducerTestModuleFactory)
1068 ctx.RegisterModuleType("oft_module", outputFilesTestModuleFactory)
1069 }),
1070 FixtureWithRootAndroidBp(tt.bp),
1071 ).RunTest(t)
1072
1073 config := TestConfig(buildDir, tt.env, tt.bp, nil)
1074 if tt.config != nil {
1075 tt.config(config.config)
1076 }
1077 ctx := &pathContextAddMissingDependenciesWrapper{
1078 PathContext: PathContextForTesting(config),
1079 OtherModuleProviderContext: result.TestContext.OtherModuleProviderAdaptor(),
1080 }
1081 got := OutputFileForModule(ctx, result.ModuleForTests("test_module", "").Module(), tt.tag)
1082 AssertPathRelativeToTopEquals(t, "expected output path", tt.expected, got)
1083 AssertArrayString(t, "expected missing deps", tt.missingDeps, ctx.missingDeps)
1084 })
Colin Cross14ec66c2022-10-03 21:02:27 -07001085 }
1086}
Kiyoung Kim55234812024-09-11 17:00:24 +09001087
1088func TestVintfFragmentModulesChecksPartition(t *testing.T) {
1089 bp := `
1090 vintf_fragment {
1091 name: "vintfModA",
1092 src: "test_vintf_file",
1093 vendor: true,
1094 }
1095 deps {
1096 name: "modA",
1097 vintf_fragment_modules: [
1098 "vintfModA",
1099 ]
1100 }
1101 `
1102
1103 testPreparer := GroupFixturePreparers(
1104 PrepareForTestWithAndroidBuildComponents,
1105 prepareForModuleTests,
1106 )
1107
1108 testPreparer.
1109 ExtendWithErrorHandler(FixtureExpectsOneErrorPattern(
1110 "Module .+ and Vintf_fragment .+ are installed to different partitions.")).
1111 RunTestWithBp(t, bp)
1112}