blob: 5331e4970c614e6968185e0fd96d9f4a8b2fd9de [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 }
Colin Cross90607e92025-02-11 14:58:07 -0800324 return result.ModuleForTests(t, name, variant)
Colin Cross6ac95762021-11-09 13:17:44 -0800325 }
326
327 outputRule := func(name string) TestingBuildParams { return module(name, false).Output(name) }
328
329 installRule := func(name string) TestingBuildParams {
Cole Faust6b7075f2024-12-17 10:42:42 -0800330 return module(name, false).Output(filepath.Join("out/target/product/test_device/system", name))
Colin Cross6ac95762021-11-09 13:17:44 -0800331 }
332
333 symlinkRule := func(name string) TestingBuildParams {
Cole Faust6b7075f2024-12-17 10:42:42 -0800334 return module(name, false).Output(filepath.Join("out/target/product/test_device/system/symlinks", name))
Colin Cross6ac95762021-11-09 13:17:44 -0800335 }
336
337 hostOutputRule := func(name string) TestingBuildParams { return module(name, true).Output(name) }
338
339 hostInstallRule := func(name string) TestingBuildParams {
Cole Faust6b7075f2024-12-17 10:42:42 -0800340 return module(name, true).Output(filepath.Join("out/host/linux-x86", name))
Colin Cross6ac95762021-11-09 13:17:44 -0800341 }
342
343 hostSymlinkRule := func(name string) TestingBuildParams {
Cole Faust6b7075f2024-12-17 10:42:42 -0800344 return module(name, true).Output(filepath.Join("out/host/linux-x86/symlinks", name))
Colin Cross6ac95762021-11-09 13:17:44 -0800345 }
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 {
Colin Cross90607e92025-02-11 14:58:07 -0800437 t.Helper()
Colin Cross6ac95762021-11-09 13:17:44 -0800438 variant := "android_common"
439 if host {
440 variant = result.Config.BuildOSCommonTarget.String()
441 }
Colin Cross90607e92025-02-11 14:58:07 -0800442 return result.ModuleForTests(t, name, variant)
Colin Cross6ac95762021-11-09 13:17:44 -0800443 }
444
445 outputRule := func(name string) TestingBuildParams { return module(name, false).Output(name) }
446
Martin Stjernholm1ebef5b2022-02-10 23:34:28 +0000447 ruleForOutput := func(output string) InstallMakeRule {
Colin Cross6ac95762021-11-09 13:17:44 -0800448 for _, rule := range rules {
Martin Stjernholm1ebef5b2022-02-10 23:34:28 +0000449 if rule.Target == output {
Colin Cross6ac95762021-11-09 13:17:44 -0800450 return rule
451 }
452 }
453 t.Fatalf("no make install rule for %s", output)
Martin Stjernholm1ebef5b2022-02-10 23:34:28 +0000454 return InstallMakeRule{}
Colin Cross6ac95762021-11-09 13:17:44 -0800455 }
456
Martin Stjernholm1ebef5b2022-02-10 23:34:28 +0000457 installRule := func(name string) InstallMakeRule {
Colin Cross6ac95762021-11-09 13:17:44 -0800458 return ruleForOutput(filepath.Join("out/target/product/test_device/system", name))
459 }
460
Martin Stjernholm1ebef5b2022-02-10 23:34:28 +0000461 symlinkRule := func(name string) InstallMakeRule {
Colin Cross6ac95762021-11-09 13:17:44 -0800462 return ruleForOutput(filepath.Join("out/target/product/test_device/system/symlinks", name))
463 }
464
465 hostOutputRule := func(name string) TestingBuildParams { return module(name, true).Output(name) }
466
Martin Stjernholm1ebef5b2022-02-10 23:34:28 +0000467 hostInstallRule := func(name string) InstallMakeRule {
Colin Cross6ac95762021-11-09 13:17:44 -0800468 return ruleForOutput(filepath.Join("out/host/linux-x86", name))
469 }
470
Martin Stjernholm1ebef5b2022-02-10 23:34:28 +0000471 hostSymlinkRule := func(name string) InstallMakeRule {
Colin Cross6ac95762021-11-09 13:17:44 -0800472 return ruleForOutput(filepath.Join("out/host/linux-x86/symlinks", name))
473 }
474
Martin Stjernholm1ebef5b2022-02-10 23:34:28 +0000475 assertDeps := func(rule InstallMakeRule, deps ...string) {
Colin Cross6ac95762021-11-09 13:17:44 -0800476 t.Helper()
Martin Stjernholm1ebef5b2022-02-10 23:34:28 +0000477 AssertArrayString(t, "expected inputs", deps, rule.Deps)
Colin Cross6ac95762021-11-09 13:17:44 -0800478 }
479
Martin Stjernholm1ebef5b2022-02-10 23:34:28 +0000480 assertOrderOnlys := func(rule InstallMakeRule, orderonlys ...string) {
Colin Cross6ac95762021-11-09 13:17:44 -0800481 t.Helper()
Martin Stjernholm1ebef5b2022-02-10 23:34:28 +0000482 AssertArrayString(t, "expected orderonly dependencies", orderonlys, rule.OrderOnlyDeps)
Colin Cross6ac95762021-11-09 13:17:44 -0800483 }
484
485 // Check host install rule dependencies
486 assertDeps(hostInstallRule("foo"),
487 hostOutputRule("foo").Output.String(),
Martin Stjernholm1ebef5b2022-02-10 23:34:28 +0000488 hostInstallRule("bar").Target,
489 hostSymlinkRule("bar").Target,
490 hostInstallRule("baz").Target,
491 hostSymlinkRule("baz").Target,
492 hostInstallRule("qux").Target,
493 hostSymlinkRule("qux").Target,
Colin Cross6ac95762021-11-09 13:17:44 -0800494 )
495 assertOrderOnlys(hostInstallRule("foo"))
496
Colin Cross64002af2021-11-09 16:37:52 -0800497 // Check host symlink rule dependencies. Host symlinks must use a normal dependency, not an
498 // order-only dependency, so that the tool gets updated when the symlink is depended on.
Martin Stjernholm1ebef5b2022-02-10 23:34:28 +0000499 assertDeps(hostSymlinkRule("foo"), hostInstallRule("foo").Target)
Colin Cross64002af2021-11-09 16:37:52 -0800500 assertOrderOnlys(hostSymlinkRule("foo"))
Colin Cross6ac95762021-11-09 13:17:44 -0800501
502 // Check device install rule dependencies
503 assertDeps(installRule("foo"), outputRule("foo").Output.String())
504 assertOrderOnlys(installRule("foo"),
Martin Stjernholm1ebef5b2022-02-10 23:34:28 +0000505 installRule("bar").Target,
506 symlinkRule("bar").Target,
507 installRule("baz").Target,
508 symlinkRule("baz").Target,
509 installRule("qux").Target,
510 symlinkRule("qux").Target,
Colin Cross6ac95762021-11-09 13:17:44 -0800511 )
512
Colin Cross64002af2021-11-09 16:37:52 -0800513 // Check device symlink rule dependencies. Device symlinks could use an order-only dependency,
514 // but the current implementation uses a normal dependency.
Martin Stjernholm1ebef5b2022-02-10 23:34:28 +0000515 assertDeps(symlinkRule("foo"), installRule("foo").Target)
Colin Cross64002af2021-11-09 16:37:52 -0800516 assertOrderOnlys(symlinkRule("foo"))
Colin Cross6ac95762021-11-09 13:17:44 -0800517}
518
Liz Kammer9525e712022-01-05 13:46:24 -0500519type PropsTestModuleEmbedded struct {
520 Embedded_prop *string
521}
522
Liz Kammer898e0762022-03-22 11:27:26 -0400523type StructInSlice struct {
524 G string
525 H bool
526 I []string
527}
528
Liz Kammer9525e712022-01-05 13:46:24 -0500529type propsTestModule struct {
530 ModuleBase
531 DefaultableModuleBase
532 props struct {
533 A string `android:"arch_variant"`
534 B *bool
535 C []string
536 }
537 otherProps struct {
538 PropsTestModuleEmbedded
539
540 D *int64
541 Nested struct {
542 E *string
543 }
544 F *string `blueprint:"mutated"`
Liz Kammer898e0762022-03-22 11:27:26 -0400545
546 Slice_of_struct []StructInSlice
Liz Kammer9525e712022-01-05 13:46:24 -0500547 }
548}
549
550func propsTestModuleFactory() Module {
551 module := &propsTestModule{}
552 module.AddProperties(&module.props, &module.otherProps)
553 InitAndroidArchModule(module, HostAndDeviceSupported, MultilibBoth)
554 InitDefaultableModule(module)
555 return module
556}
557
558type propsTestModuleDefaults struct {
559 ModuleBase
560 DefaultsModuleBase
561}
562
563func propsTestModuleDefaultsFactory() Module {
564 defaults := &propsTestModuleDefaults{}
565 module := propsTestModule{}
566 defaults.AddProperties(&module.props, &module.otherProps)
567 InitDefaultsModule(defaults)
568 return defaults
569}
570
571func (p *propsTestModule) GenerateAndroidBuildActions(ctx ModuleContext) {
572 str := "abc"
573 p.otherProps.F = &str
574}
575
576func TestUsedProperties(t *testing.T) {
577 testCases := []struct {
578 desc string
579 bp string
580 expectedProps []propInfo
581 }{
582 {
583 desc: "only name",
584 bp: `test {
585 name: "foo",
586 }
587 `,
588 expectedProps: []propInfo{
Liz Kammer898e0762022-03-22 11:27:26 -0400589 propInfo{Name: "Name", Type: "string", Value: "foo"},
Liz Kammer9525e712022-01-05 13:46:24 -0500590 },
591 },
592 {
593 desc: "some props",
594 bp: `test {
595 name: "foo",
596 a: "abc",
597 b: true,
598 d: 123,
599 }
600 `,
601 expectedProps: []propInfo{
Liz Kammer898e0762022-03-22 11:27:26 -0400602 propInfo{Name: "A", Type: "string", Value: "abc"},
603 propInfo{Name: "B", Type: "bool", Value: "true"},
604 propInfo{Name: "D", Type: "int64", Value: "123"},
605 propInfo{Name: "Name", Type: "string", Value: "foo"},
Liz Kammer9525e712022-01-05 13:46:24 -0500606 },
607 },
608 {
609 desc: "unused non-pointer prop",
610 bp: `test {
611 name: "foo",
612 b: true,
613 d: 123,
614 }
615 `,
616 expectedProps: []propInfo{
617 // for non-pointer cannot distinguish between unused and intentionally set to empty
Liz Kammer898e0762022-03-22 11:27:26 -0400618 propInfo{Name: "A", Type: "string", Value: ""},
619 propInfo{Name: "B", Type: "bool", Value: "true"},
620 propInfo{Name: "D", Type: "int64", Value: "123"},
621 propInfo{Name: "Name", Type: "string", Value: "foo"},
Liz Kammer9525e712022-01-05 13:46:24 -0500622 },
623 },
624 {
625 desc: "nested props",
626 bp: `test {
627 name: "foo",
628 nested: {
629 e: "abc",
630 }
631 }
632 `,
633 expectedProps: []propInfo{
Liz Kammer898e0762022-03-22 11:27:26 -0400634 propInfo{Name: "Name", Type: "string", Value: "foo"},
635 propInfo{Name: "Nested.E", Type: "string", Value: "abc"},
Liz Kammer9525e712022-01-05 13:46:24 -0500636 },
637 },
638 {
639 desc: "arch props",
640 bp: `test {
641 name: "foo",
642 arch: {
643 x86_64: {
644 a: "abc",
645 },
646 }
647 }
648 `,
649 expectedProps: []propInfo{
Liz Kammer898e0762022-03-22 11:27:26 -0400650 propInfo{Name: "Arch.X86_64.A", Type: "string", Value: "abc"},
651 propInfo{Name: "Name", Type: "string", Value: "foo"},
Liz Kammer9525e712022-01-05 13:46:24 -0500652 },
653 },
654 {
655 desc: "embedded props",
656 bp: `test {
657 name: "foo",
658 embedded_prop: "a",
659 }
660 `,
661 expectedProps: []propInfo{
Liz Kammer898e0762022-03-22 11:27:26 -0400662 propInfo{Name: "Embedded_prop", Type: "string", Value: "a"},
663 propInfo{Name: "Name", Type: "string", Value: "foo"},
664 },
665 },
666 {
667 desc: "struct slice",
668 bp: `test {
669 name: "foo",
670 slice_of_struct: [
671 {
672 g: "abc",
673 h: false,
674 i: ["baz"],
675 },
676 {
677 g: "def",
678 h: true,
679 i: [],
680 },
681 ]
682 }
683 `,
684 expectedProps: []propInfo{
685 propInfo{Name: "Name", Type: "string", Value: "foo"},
686 propInfo{Name: "Slice_of_struct", Type: "struct slice", Values: []string{
687 `android.StructInSlice{G: abc, H: false, I: [baz]}`,
688 `android.StructInSlice{G: def, H: true, I: []}`,
689 }},
Liz Kammer9525e712022-01-05 13:46:24 -0500690 },
691 },
692 {
693 desc: "defaults",
694 bp: `
695test_defaults {
696 name: "foo_defaults",
697 a: "a",
698 b: true,
Liz Kammer898e0762022-03-22 11:27:26 -0400699 c: ["default_c"],
Liz Kammer9525e712022-01-05 13:46:24 -0500700 embedded_prop:"a",
701 arch: {
702 x86_64: {
Liz Kammer898e0762022-03-22 11:27:26 -0400703 a: "x86_64 a",
Liz Kammer9525e712022-01-05 13:46:24 -0500704 },
705 },
706}
707test {
708 name: "foo",
709 defaults: ["foo_defaults"],
Liz Kammer898e0762022-03-22 11:27:26 -0400710 c: ["c"],
Liz Kammer9525e712022-01-05 13:46:24 -0500711 nested: {
Liz Kammer898e0762022-03-22 11:27:26 -0400712 e: "nested e",
Liz Kammer9525e712022-01-05 13:46:24 -0500713 },
714 target: {
715 linux: {
716 a: "a",
717 },
718 },
719}
720 `,
721 expectedProps: []propInfo{
Liz Kammer898e0762022-03-22 11:27:26 -0400722 propInfo{Name: "A", Type: "string", Value: "a"},
723 propInfo{Name: "Arch.X86_64.A", Type: "string", Value: "x86_64 a"},
724 propInfo{Name: "B", Type: "bool", Value: "true"},
725 propInfo{Name: "C", Type: "string slice", Values: []string{"default_c", "c"}},
Cole Faust52d37c32024-08-23 16:20:58 -0700726 propInfo{Name: "Defaults", Type: "string slice", Values: []string{"foo_defaults"}},
Liz Kammer898e0762022-03-22 11:27:26 -0400727 propInfo{Name: "Embedded_prop", Type: "string", Value: "a"},
728 propInfo{Name: "Name", Type: "string", Value: "foo"},
729 propInfo{Name: "Nested.E", Type: "string", Value: "nested e"},
730 propInfo{Name: "Target.Linux.A", Type: "string", Value: "a"},
Liz Kammer9525e712022-01-05 13:46:24 -0500731 },
732 },
733 }
734
735 for _, tc := range testCases {
736 t.Run(tc.desc, func(t *testing.T) {
737 result := GroupFixturePreparers(
738 PrepareForTestWithAllowMissingDependencies,
739 PrepareForTestWithDefaults,
740 FixtureRegisterWithContext(func(ctx RegistrationContext) {
741 ctx.RegisterModuleType("test", propsTestModuleFactory)
742 ctx.RegisterModuleType("test_defaults", propsTestModuleDefaultsFactory)
743 }),
744 FixtureWithRootAndroidBp(tc.bp),
745 ).RunTest(t)
746
Colin Cross90607e92025-02-11 14:58:07 -0800747 foo := result.ModuleForTests(t, "foo", "").Module().base()
Liz Kammer9525e712022-01-05 13:46:24 -0500748
749 AssertDeepEquals(t, "foo ", tc.expectedProps, foo.propertiesWithValues())
Liz Kammer9525e712022-01-05 13:46:24 -0500750 })
751 }
752}
Bob Badour4101c712022-02-09 11:54:35 -0800753
754func TestSortedUniqueNamedPaths(t *testing.T) {
755 type np struct {
756 path, name string
757 }
758 makePaths := func(l []np) NamedPaths {
759 result := make(NamedPaths, 0, len(l))
760 for _, p := range l {
761 result = append(result, NamedPath{PathForTesting(p.path), p.name})
762 }
763 return result
764 }
765
766 tests := []struct {
767 name string
768 in []np
769 expectedOut []np
770 }{
771 {
772 name: "empty",
773 in: []np{},
774 expectedOut: []np{},
775 },
776 {
777 name: "all_same",
778 in: []np{
779 {"a.txt", "A"},
780 {"a.txt", "A"},
781 {"a.txt", "A"},
782 {"a.txt", "A"},
783 {"a.txt", "A"},
784 },
785 expectedOut: []np{
786 {"a.txt", "A"},
787 },
788 },
789 {
790 name: "same_path_different_names",
791 in: []np{
792 {"a.txt", "C"},
793 {"a.txt", "A"},
794 {"a.txt", "D"},
795 {"a.txt", "B"},
796 {"a.txt", "E"},
797 },
798 expectedOut: []np{
799 {"a.txt", "A"},
800 {"a.txt", "B"},
801 {"a.txt", "C"},
802 {"a.txt", "D"},
803 {"a.txt", "E"},
804 },
805 },
806 {
807 name: "different_paths_same_name",
808 in: []np{
809 {"b/b.txt", "A"},
810 {"a/a.txt", "A"},
811 {"a/txt", "A"},
812 {"b", "A"},
813 {"a/b/d", "A"},
814 },
815 expectedOut: []np{
816 {"a/a.txt", "A"},
817 {"a/b/d", "A"},
818 {"a/txt", "A"},
819 {"b/b.txt", "A"},
820 {"b", "A"},
821 },
822 },
823 {
824 name: "all_different",
825 in: []np{
826 {"b/b.txt", "A"},
827 {"a/a.txt", "B"},
828 {"a/txt", "D"},
829 {"b", "C"},
830 {"a/b/d", "E"},
831 },
832 expectedOut: []np{
833 {"a/a.txt", "B"},
834 {"a/b/d", "E"},
835 {"a/txt", "D"},
836 {"b/b.txt", "A"},
837 {"b", "C"},
838 },
839 },
840 {
841 name: "some_different",
842 in: []np{
843 {"b/b.txt", "A"},
844 {"a/a.txt", "B"},
845 {"a/txt", "D"},
846 {"a/b/d", "E"},
847 {"b", "C"},
848 {"a/a.txt", "B"},
849 {"a/b/d", "E"},
850 },
851 expectedOut: []np{
852 {"a/a.txt", "B"},
853 {"a/b/d", "E"},
854 {"a/txt", "D"},
855 {"b/b.txt", "A"},
856 {"b", "C"},
857 },
858 },
859 }
860 for _, tt := range tests {
861 t.Run(tt.name, func(t *testing.T) {
862 actual := SortedUniqueNamedPaths(makePaths(tt.in))
863 expected := makePaths(tt.expectedOut)
864 t.Logf("actual: %v", actual)
865 t.Logf("expected: %v", expected)
866 AssertDeepEquals(t, "SortedUniqueNamedPaths ", expected, actual)
867 })
868 }
869}
Zhenhuang Wang0ac5a432022-08-12 18:49:20 +0800870
Zhenhuang Wang409d2772022-08-22 16:00:05 +0800871func TestSetAndroidMkEntriesWithTestOptions(t *testing.T) {
Zhenhuang Wang0ac5a432022-08-12 18:49:20 +0800872 tests := []struct {
873 name string
874 testOptions CommonTestOptions
875 expected map[string][]string
876 }{
877 {
878 name: "empty",
879 testOptions: CommonTestOptions{},
880 expected: map[string][]string{},
881 },
882 {
883 name: "is unit test",
884 testOptions: CommonTestOptions{
885 Unit_test: boolPtr(true),
886 },
887 expected: map[string][]string{
888 "LOCAL_IS_UNIT_TEST": []string{"true"},
889 },
890 },
891 {
892 name: "is not unit test",
893 testOptions: CommonTestOptions{
894 Unit_test: boolPtr(false),
895 },
896 expected: map[string][]string{},
897 },
Zhenhuang Wang409d2772022-08-22 16:00:05 +0800898 {
899 name: "empty tag",
900 testOptions: CommonTestOptions{
901 Tags: []string{},
902 },
903 expected: map[string][]string{},
904 },
905 {
906 name: "single tag",
907 testOptions: CommonTestOptions{
908 Tags: []string{"tag1"},
909 },
910 expected: map[string][]string{
911 "LOCAL_TEST_OPTIONS_TAGS": []string{"tag1"},
912 },
913 },
914 {
915 name: "multiple tag",
916 testOptions: CommonTestOptions{
917 Tags: []string{"tag1", "tag2", "tag3"},
918 },
919 expected: map[string][]string{
920 "LOCAL_TEST_OPTIONS_TAGS": []string{"tag1", "tag2", "tag3"},
921 },
922 },
Zhenhuang Wang0ac5a432022-08-12 18:49:20 +0800923 }
924 for _, tt := range tests {
925 t.Run(tt.name, func(t *testing.T) {
926 actualEntries := AndroidMkEntries{
927 EntryMap: map[string][]string{},
928 }
929 tt.testOptions.SetAndroidMkEntries(&actualEntries)
930 actual := actualEntries.EntryMap
931 t.Logf("actual: %v", actual)
932 t.Logf("expected: %v", tt.expected)
933 AssertDeepEquals(t, "TestProcessCommonTestOptions ", tt.expected, actual)
934 })
935 }
936}
Colin Cross14ec66c2022-10-03 21:02:27 -0700937
Colin Cross14ec66c2022-10-03 21:02:27 -0700938type sourceProducerTestModule struct {
mrziwang1ea01e32024-07-12 12:26:34 -0700939 ModuleBase
940 props struct {
941 // A represents the source file
942 A string
943 }
Colin Cross14ec66c2022-10-03 21:02:27 -0700944}
945
mrziwang1ea01e32024-07-12 12:26:34 -0700946func sourceProducerTestModuleFactory() Module {
947 module := &sourceProducerTestModule{}
948 module.AddProperties(&module.props)
949 InitAndroidModule(module)
950 return module
Colin Cross14ec66c2022-10-03 21:02:27 -0700951}
952
mrziwang1ea01e32024-07-12 12:26:34 -0700953func (s sourceProducerTestModule) GenerateAndroidBuildActions(ModuleContext) {}
954
955func (s sourceProducerTestModule) Srcs() Paths { return PathsForTesting(s.props.A) }
956
957type outputFilesTestModule struct {
958 ModuleBase
959 props struct {
960 // A represents the tag
961 A string
962 // B represents the output file for tag A
963 B string
964 }
965}
966
967func outputFilesTestModuleFactory() Module {
968 module := &outputFilesTestModule{}
969 module.AddProperties(&module.props)
970 InitAndroidModule(module)
971 return module
972}
973
974func (o outputFilesTestModule) GenerateAndroidBuildActions(ctx ModuleContext) {
975 if o.props.A != "" || o.props.B != "" {
976 ctx.SetOutputFiles(PathsForTesting(o.props.B), o.props.A)
977 }
978 // This is to simulate the case that some module uses an object to set its
979 // OutputFilesProvider, but the object itself is empty.
980 ctx.SetOutputFiles(Paths{}, "missing")
Colin Cross14ec66c2022-10-03 21:02:27 -0700981}
982
983type pathContextAddMissingDependenciesWrapper struct {
984 PathContext
mrziwang1ea01e32024-07-12 12:26:34 -0700985 OtherModuleProviderContext
Colin Cross14ec66c2022-10-03 21:02:27 -0700986 missingDeps []string
987}
988
989func (p *pathContextAddMissingDependenciesWrapper) AddMissingDependencies(deps []string) {
990 p.missingDeps = append(p.missingDeps, deps...)
991}
992func (p *pathContextAddMissingDependenciesWrapper) OtherModuleName(module blueprint.Module) string {
993 return module.Name()
994}
995
mrziwang1ea01e32024-07-12 12:26:34 -0700996func (p *pathContextAddMissingDependenciesWrapper) Module() Module { return nil }
997
Yu Liu876b7ce2024-08-21 18:20:13 +0000998func (p *pathContextAddMissingDependenciesWrapper) GetOutputFiles() OutputFilesInfo {
999 return OutputFilesInfo{}
1000}
1001
Yu Liud3228ac2024-11-08 23:11:47 +00001002func (p *pathContextAddMissingDependenciesWrapper) EqualModules(m1, m2 Module) bool {
1003 return m1 == m2
1004}
1005
Colin Cross14ec66c2022-10-03 21:02:27 -07001006func TestOutputFileForModule(t *testing.T) {
1007 testcases := []struct {
1008 name string
mrziwang1ea01e32024-07-12 12:26:34 -07001009 bp string
Colin Cross14ec66c2022-10-03 21:02:27 -07001010 tag string
Colin Cross14ec66c2022-10-03 21:02:27 -07001011 expected string
1012 missingDeps []string
mrziwang1ea01e32024-07-12 12:26:34 -07001013 env map[string]string
1014 config func(*config)
Colin Cross14ec66c2022-10-03 21:02:27 -07001015 }{
1016 {
mrziwang1ea01e32024-07-12 12:26:34 -07001017 name: "SourceFileProducer",
1018 bp: `spt_module {
1019 name: "test_module",
1020 a: "spt.txt",
1021 }
1022 `,
1023 tag: "",
1024 expected: "spt.txt",
Colin Cross14ec66c2022-10-03 21:02:27 -07001025 },
1026 {
mrziwang1ea01e32024-07-12 12:26:34 -07001027 name: "OutputFileProviderEmptyStringTag",
1028 bp: `oft_module {
1029 name: "test_module",
1030 a: "",
1031 b: "empty.txt",
1032 }
1033 `,
1034 tag: "",
1035 expected: "empty.txt",
Colin Cross14ec66c2022-10-03 21:02:27 -07001036 },
1037 {
mrziwang1ea01e32024-07-12 12:26:34 -07001038 name: "OutputFileProviderTag",
1039 bp: `oft_module {
1040 name: "test_module",
1041 a: "foo",
1042 b: "foo.txt",
1043 }
1044 `,
Colin Cross14ec66c2022-10-03 21:02:27 -07001045 tag: "foo",
1046 expected: "foo.txt",
1047 },
1048 {
mrziwang1ea01e32024-07-12 12:26:34 -07001049 name: "OutputFileAllowMissingDependencies",
1050 bp: `oft_module {
1051 name: "test_module",
1052 }
1053 `,
1054 tag: "missing",
1055 expected: "missing_output_file/test_module",
1056 missingDeps: []string{"test_module"},
Colin Cross14ec66c2022-10-03 21:02:27 -07001057 config: func(config *config) {
1058 config.TestProductVariables.Allow_missing_dependencies = boolPtr(true)
1059 },
Colin Cross14ec66c2022-10-03 21:02:27 -07001060 },
1061 }
mrziwang1ea01e32024-07-12 12:26:34 -07001062
Colin Cross14ec66c2022-10-03 21:02:27 -07001063 for _, tt := range testcases {
mrziwang1ea01e32024-07-12 12:26:34 -07001064 t.Run(tt.name, func(t *testing.T) {
1065 result := GroupFixturePreparers(
1066 PrepareForTestWithDefaults,
1067 FixtureRegisterWithContext(func(ctx RegistrationContext) {
1068 ctx.RegisterModuleType("spt_module", sourceProducerTestModuleFactory)
1069 ctx.RegisterModuleType("oft_module", outputFilesTestModuleFactory)
1070 }),
1071 FixtureWithRootAndroidBp(tt.bp),
1072 ).RunTest(t)
1073
1074 config := TestConfig(buildDir, tt.env, tt.bp, nil)
1075 if tt.config != nil {
1076 tt.config(config.config)
1077 }
1078 ctx := &pathContextAddMissingDependenciesWrapper{
1079 PathContext: PathContextForTesting(config),
1080 OtherModuleProviderContext: result.TestContext.OtherModuleProviderAdaptor(),
1081 }
Colin Cross90607e92025-02-11 14:58:07 -08001082 got := OutputFileForModule(ctx, result.ModuleForTests(t, "test_module", "").Module(), tt.tag)
mrziwang1ea01e32024-07-12 12:26:34 -07001083 AssertPathRelativeToTopEquals(t, "expected output path", tt.expected, got)
1084 AssertArrayString(t, "expected missing deps", tt.missingDeps, ctx.missingDeps)
1085 })
Colin Cross14ec66c2022-10-03 21:02:27 -07001086 }
1087}
Kiyoung Kim55234812024-09-11 17:00:24 +09001088
1089func TestVintfFragmentModulesChecksPartition(t *testing.T) {
1090 bp := `
1091 vintf_fragment {
1092 name: "vintfModA",
1093 src: "test_vintf_file",
1094 vendor: true,
1095 }
1096 deps {
1097 name: "modA",
1098 vintf_fragment_modules: [
1099 "vintfModA",
1100 ]
1101 }
1102 `
1103
1104 testPreparer := GroupFixturePreparers(
1105 PrepareForTestWithAndroidBuildComponents,
1106 prepareForModuleTests,
1107 )
1108
1109 testPreparer.
1110 ExtendWithErrorHandler(FixtureExpectsOneErrorPattern(
1111 "Module .+ and Vintf_fragment .+ are installed to different partitions.")).
1112 RunTestWithBp(t, bp)
1113}
Spandan Dasb6ed11f2025-02-06 22:45:56 +00001114
1115func TestInvalidModuleName(t *testing.T) {
1116 bp := `
1117 deps {
1118 name: "fo o",
1119 }
1120 `
1121 prepareForModuleTests.
1122 ExtendWithErrorHandler(FixtureExpectsOneErrorPattern(`should use a valid name`)).
1123 RunTestWithBp(t, bp)
1124}