• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2019 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
17import (
18	"reflect"
19	"runtime"
20	"testing"
21
22	"github.com/google/blueprint/proptools"
23)
24
25type Named struct {
26	A *string `android:"arch_variant"`
27	B *string
28}
29
30type NamedAllFiltered struct {
31	A *string
32}
33
34type NamedNoneFiltered struct {
35	A *string `android:"arch_variant"`
36}
37
38func TestFilterArchStruct(t *testing.T) {
39	tests := []struct {
40		name     string
41		in       interface{}
42		out      interface{}
43		filtered bool
44	}{
45		// Property tests
46		{
47			name: "basic",
48			in: &struct {
49				A *string `android:"arch_variant"`
50				B *string
51			}{},
52			out: &struct {
53				A *string
54			}{},
55			filtered: true,
56		},
57		{
58			name: "tags",
59			in: &struct {
60				A *string `android:"arch_variant"`
61				B *string `android:"arch_variant,path"`
62				C *string `android:"arch_variant,path,variant_prepend"`
63				D *string `android:"path,variant_prepend,arch_variant"`
64				E *string `android:"path"`
65				F *string
66			}{},
67			out: &struct {
68				A *string
69				B *string `android:"path"`
70				C *string `android:"path"`
71				D *string `android:"path"`
72			}{},
73			filtered: true,
74		},
75		{
76			name: "all filtered",
77			in: &struct {
78				A *string
79			}{},
80			out:      nil,
81			filtered: true,
82		},
83		{
84			name: "none filtered",
85			in: &struct {
86				A *string `android:"arch_variant"`
87			}{},
88			out: &struct {
89				A *string `android:"arch_variant"`
90			}{},
91			filtered: false,
92		},
93
94		// Sub-struct tests
95		{
96			name: "substruct",
97			in: &struct {
98				A struct {
99					A *string `android:"arch_variant"`
100					B *string
101				} `android:"arch_variant"`
102			}{},
103			out: &struct {
104				A struct {
105					A *string
106				}
107			}{},
108			filtered: true,
109		},
110		{
111			name: "substruct all filtered",
112			in: &struct {
113				A struct {
114					A *string
115				} `android:"arch_variant"`
116			}{},
117			out:      nil,
118			filtered: true,
119		},
120		{
121			name: "substruct none filtered",
122			in: &struct {
123				A struct {
124					A *string `android:"arch_variant"`
125				} `android:"arch_variant"`
126			}{},
127			out: &struct {
128				A struct {
129					A *string `android:"arch_variant"`
130				} `android:"arch_variant"`
131			}{},
132			filtered: false,
133		},
134
135		// Named sub-struct tests
136		{
137			name: "named substruct",
138			in: &struct {
139				A Named `android:"arch_variant"`
140			}{},
141			out: &struct {
142				A struct {
143					A *string
144				}
145			}{},
146			filtered: true,
147		},
148		{
149			name: "substruct all filtered",
150			in: &struct {
151				A NamedAllFiltered `android:"arch_variant"`
152			}{},
153			out:      nil,
154			filtered: true,
155		},
156		{
157			name: "substruct none filtered",
158			in: &struct {
159				A NamedNoneFiltered `android:"arch_variant"`
160			}{},
161			out: &struct {
162				A NamedNoneFiltered `android:"arch_variant"`
163			}{},
164			filtered: false,
165		},
166
167		// Pointer to sub-struct tests
168		{
169			name: "pointer substruct",
170			in: &struct {
171				A *struct {
172					A *string `android:"arch_variant"`
173					B *string
174				} `android:"arch_variant"`
175			}{},
176			out: &struct {
177				A *struct {
178					A *string
179				}
180			}{},
181			filtered: true,
182		},
183		{
184			name: "pointer substruct all filtered",
185			in: &struct {
186				A *struct {
187					A *string
188				} `android:"arch_variant"`
189			}{},
190			out:      nil,
191			filtered: true,
192		},
193		{
194			name: "pointer substruct none filtered",
195			in: &struct {
196				A *struct {
197					A *string `android:"arch_variant"`
198				} `android:"arch_variant"`
199			}{},
200			out: &struct {
201				A *struct {
202					A *string `android:"arch_variant"`
203				} `android:"arch_variant"`
204			}{},
205			filtered: false,
206		},
207
208		// Pointer to named sub-struct tests
209		{
210			name: "pointer named substruct",
211			in: &struct {
212				A *Named `android:"arch_variant"`
213			}{},
214			out: &struct {
215				A *struct {
216					A *string
217				}
218			}{},
219			filtered: true,
220		},
221		{
222			name: "pointer substruct all filtered",
223			in: &struct {
224				A *NamedAllFiltered `android:"arch_variant"`
225			}{},
226			out:      nil,
227			filtered: true,
228		},
229		{
230			name: "pointer substruct none filtered",
231			in: &struct {
232				A *NamedNoneFiltered `android:"arch_variant"`
233			}{},
234			out: &struct {
235				A *NamedNoneFiltered `android:"arch_variant"`
236			}{},
237			filtered: false,
238		},
239	}
240
241	for _, test := range tests {
242		t.Run(test.name, func(t *testing.T) {
243			out, filtered := proptools.FilterPropertyStruct(reflect.TypeOf(test.in), filterArchStruct)
244			if filtered != test.filtered {
245				t.Errorf("expected filtered %v, got %v", test.filtered, filtered)
246			}
247			expected := reflect.TypeOf(test.out)
248			if out != expected {
249				t.Errorf("expected type %v, got %v", expected, out)
250			}
251		})
252	}
253}
254
255type archTestModule struct {
256	ModuleBase
257	props struct {
258		Deps []string
259	}
260}
261
262func (m *archTestModule) GenerateAndroidBuildActions(ctx ModuleContext) {
263}
264
265func (m *archTestModule) DepsMutator(ctx BottomUpMutatorContext) {
266	ctx.AddDependency(ctx.Module(), nil, m.props.Deps...)
267}
268
269func archTestModuleFactory() Module {
270	m := &archTestModule{}
271	m.AddProperties(&m.props)
272	InitAndroidArchModule(m, HostAndDeviceSupported, MultilibBoth)
273	return m
274}
275
276var prepareForArchTest = GroupFixturePreparers(
277	PrepareForTestWithArchMutator,
278	FixtureRegisterWithContext(func(ctx RegistrationContext) {
279		ctx.RegisterModuleType("module", archTestModuleFactory)
280	}),
281)
282
283func TestArchMutator(t *testing.T) {
284	var buildOSVariants []string
285	var buildOS32Variants []string
286	switch runtime.GOOS {
287	case "linux":
288		buildOSVariants = []string{"linux_glibc_x86_64", "linux_glibc_x86"}
289		buildOS32Variants = []string{"linux_glibc_x86"}
290	case "darwin":
291		buildOSVariants = []string{"darwin_x86_64"}
292		buildOS32Variants = nil
293	}
294
295	bp := `
296		module {
297			name: "foo",
298		}
299
300		module {
301			name: "bar",
302			host_supported: true,
303		}
304
305		module {
306			name: "baz",
307			device_supported: false,
308		}
309
310		module {
311			name: "qux",
312			host_supported: true,
313			compile_multilib: "32",
314		}
315	`
316
317	testCases := []struct {
318		name        string
319		preparer    FixturePreparer
320		fooVariants []string
321		barVariants []string
322		bazVariants []string
323		quxVariants []string
324	}{
325		{
326			name:        "normal",
327			preparer:    nil,
328			fooVariants: []string{"android_arm64_armv8-a", "android_arm_armv7-a-neon"},
329			barVariants: append(buildOSVariants, "android_arm64_armv8-a", "android_arm_armv7-a-neon"),
330			bazVariants: nil,
331			quxVariants: append(buildOS32Variants, "android_arm_armv7-a-neon"),
332		},
333		{
334			name: "host-only",
335			preparer: FixtureModifyConfig(func(config Config) {
336				config.BuildOSTarget = Target{}
337				config.BuildOSCommonTarget = Target{}
338				config.Targets[Android] = nil
339			}),
340			fooVariants: nil,
341			barVariants: buildOSVariants,
342			bazVariants: nil,
343			quxVariants: buildOS32Variants,
344		},
345	}
346
347	enabledVariants := func(ctx *TestContext, name string) []string {
348		var ret []string
349		variants := ctx.ModuleVariantsForTests(name)
350		for _, variant := range variants {
351			m := ctx.ModuleForTests(name, variant)
352			if m.Module().Enabled() {
353				ret = append(ret, variant)
354			}
355		}
356		return ret
357	}
358
359	for _, tt := range testCases {
360		t.Run(tt.name, func(t *testing.T) {
361			result := GroupFixturePreparers(
362				prepareForArchTest,
363				// Test specific preparer
364				OptionalFixturePreparer(tt.preparer),
365				FixtureWithRootAndroidBp(bp),
366			).RunTest(t)
367			ctx := result.TestContext
368
369			if g, w := enabledVariants(ctx, "foo"), tt.fooVariants; !reflect.DeepEqual(w, g) {
370				t.Errorf("want foo variants:\n%q\ngot:\n%q\n", w, g)
371			}
372
373			if g, w := enabledVariants(ctx, "bar"), tt.barVariants; !reflect.DeepEqual(w, g) {
374				t.Errorf("want bar variants:\n%q\ngot:\n%q\n", w, g)
375			}
376
377			if g, w := enabledVariants(ctx, "baz"), tt.bazVariants; !reflect.DeepEqual(w, g) {
378				t.Errorf("want baz variants:\n%q\ngot:\n%q\n", w, g)
379			}
380
381			if g, w := enabledVariants(ctx, "qux"), tt.quxVariants; !reflect.DeepEqual(w, g) {
382				t.Errorf("want qux variants:\n%q\ngot:\n%q\n", w, g)
383			}
384		})
385	}
386}
387
388func TestArchMutatorNativeBridge(t *testing.T) {
389	bp := `
390		// This module is only enabled for x86.
391		module {
392			name: "foo",
393		}
394
395		// This module is enabled for x86 and arm (via native bridge).
396		module {
397			name: "bar",
398			native_bridge_supported: true,
399		}
400
401		// This module is enabled for arm (native_bridge) only.
402		module {
403			name: "baz",
404			native_bridge_supported: true,
405			enabled: false,
406			target: {
407				native_bridge: {
408					enabled: true,
409				}
410			}
411		}
412	`
413
414	testCases := []struct {
415		name        string
416		preparer    FixturePreparer
417		fooVariants []string
418		barVariants []string
419		bazVariants []string
420	}{
421		{
422			name:        "normal",
423			preparer:    nil,
424			fooVariants: []string{"android_x86_64_silvermont", "android_x86_silvermont"},
425			barVariants: []string{"android_x86_64_silvermont", "android_native_bridge_arm64_armv8-a", "android_x86_silvermont", "android_native_bridge_arm_armv7-a-neon"},
426			bazVariants: []string{"android_native_bridge_arm64_armv8-a", "android_native_bridge_arm_armv7-a-neon"},
427		},
428	}
429
430	enabledVariants := func(ctx *TestContext, name string) []string {
431		var ret []string
432		variants := ctx.ModuleVariantsForTests(name)
433		for _, variant := range variants {
434			m := ctx.ModuleForTests(name, variant)
435			if m.Module().Enabled() {
436				ret = append(ret, variant)
437			}
438		}
439		return ret
440	}
441
442	for _, tt := range testCases {
443		t.Run(tt.name, func(t *testing.T) {
444			result := GroupFixturePreparers(
445				prepareForArchTest,
446				// Test specific preparer
447				OptionalFixturePreparer(tt.preparer),
448				// Prepare for native bridge test
449				FixtureModifyConfig(func(config Config) {
450					config.Targets[Android] = []Target{
451						{Android, Arch{ArchType: X86_64, ArchVariant: "silvermont", Abi: []string{"arm64-v8a"}}, NativeBridgeDisabled, "", "", false},
452						{Android, Arch{ArchType: X86, ArchVariant: "silvermont", Abi: []string{"armeabi-v7a"}}, NativeBridgeDisabled, "", "", false},
453						{Android, Arch{ArchType: Arm64, ArchVariant: "armv8-a", Abi: []string{"arm64-v8a"}}, NativeBridgeEnabled, "x86_64", "arm64", false},
454						{Android, Arch{ArchType: Arm, ArchVariant: "armv7-a-neon", Abi: []string{"armeabi-v7a"}}, NativeBridgeEnabled, "x86", "arm", false},
455					}
456				}),
457				FixtureWithRootAndroidBp(bp),
458			).RunTest(t)
459
460			ctx := result.TestContext
461
462			if g, w := enabledVariants(ctx, "foo"), tt.fooVariants; !reflect.DeepEqual(w, g) {
463				t.Errorf("want foo variants:\n%q\ngot:\n%q\n", w, g)
464			}
465
466			if g, w := enabledVariants(ctx, "bar"), tt.barVariants; !reflect.DeepEqual(w, g) {
467				t.Errorf("want bar variants:\n%q\ngot:\n%q\n", w, g)
468			}
469
470			if g, w := enabledVariants(ctx, "baz"), tt.bazVariants; !reflect.DeepEqual(w, g) {
471				t.Errorf("want qux variants:\n%q\ngot:\n%q\n", w, g)
472			}
473		})
474	}
475}
476
477type testArchPropertiesModule struct {
478	ModuleBase
479	properties struct {
480		A []string `android:"arch_variant"`
481	}
482}
483
484func (testArchPropertiesModule) GenerateAndroidBuildActions(ctx ModuleContext) {}
485
486func TestArchProperties(t *testing.T) {
487	bp := `
488		module {
489			name: "foo",
490			a: ["root"],
491			arch: {
492				arm: {
493					a:  ["arm"],
494				},
495				arm64: {
496					a:  ["arm64"],
497				},
498				x86: { a:  ["x86"] },
499				x86_64: { a:  ["x86_64"] },
500			},
501			multilib: {
502				lib32: { a:  ["lib32"] },
503				lib64: { a:  ["lib64"] },
504			},
505			target: {
506				bionic: { a:  ["bionic"] },
507				host: { a: ["host"] },
508				android: { a:  ["android"] },
509				glibc: { a:  ["glibc"] },
510				musl: { a:  ["musl"] },
511				linux_bionic: { a:  ["linux_bionic"] },
512				linux: { a:  ["linux"] },
513				host_linux: { a: ["host_linux"] },
514				linux_glibc: { a:  ["linux_glibc"] },
515				linux_musl: { a:  ["linux_musl"] },
516				windows: { a:  ["windows"], enabled: true },
517				darwin: { a:  ["darwin"] },
518				not_windows: { a:  ["not_windows"] },
519				android32: { a:  ["android32"] },
520				android64: { a:  ["android64"] },
521				android_arm: { a:  ["android_arm"] },
522				android_arm64: { a:  ["android_arm64"] },
523				linux_x86: { a:  ["linux_x86"] },
524				linux_x86_64: { a:  ["linux_x86_64"] },
525				linux_glibc_x86: { a:  ["linux_glibc_x86"] },
526				linux_glibc_x86_64: { a:  ["linux_glibc_x86_64"] },
527				linux_musl_x86: { a:  ["linux_musl_x86"] },
528				linux_musl_x86_64: { a:  ["linux_musl_x86_64"] },
529				darwin_x86_64: { a:  ["darwin_x86_64"] },
530				windows_x86: { a:  ["windows_x86"] },
531				windows_x86_64: { a:  ["windows_x86_64"] },
532			},
533		}
534	`
535
536	type result struct {
537		module   string
538		variant  string
539		property []string
540	}
541
542	testCases := []struct {
543		name     string
544		goOS     string
545		preparer FixturePreparer
546		results  []result
547	}{
548		{
549			name: "default",
550			results: []result{
551				{
552					module:   "foo",
553					variant:  "android_arm64_armv8-a",
554					property: []string{"root", "linux", "bionic", "android", "android64", "arm64", "lib64", "android_arm64"},
555				},
556				{
557					module:   "foo",
558					variant:  "android_arm_armv7-a-neon",
559					property: []string{"root", "linux", "bionic", "android", "android64", "arm", "lib32", "android_arm"},
560				},
561			},
562		},
563		{
564			name: "linux",
565			goOS: "linux",
566			results: []result{
567				{
568					module:   "foo",
569					variant:  "linux_glibc_x86_64",
570					property: []string{"root", "host", "linux", "host_linux", "glibc", "linux_glibc", "not_windows", "x86_64", "lib64", "linux_x86_64", "linux_glibc_x86_64"},
571				},
572				{
573					module:   "foo",
574					variant:  "linux_glibc_x86",
575					property: []string{"root", "host", "linux", "host_linux", "glibc", "linux_glibc", "not_windows", "x86", "lib32", "linux_x86", "linux_glibc_x86"},
576				},
577			},
578		},
579		{
580			name: "windows",
581			goOS: "linux",
582			preparer: FixtureModifyConfig(func(config Config) {
583				config.Targets[Windows] = []Target{
584					{Windows, Arch{ArchType: X86_64}, NativeBridgeDisabled, "", "", true},
585					{Windows, Arch{ArchType: X86}, NativeBridgeDisabled, "", "", true},
586				}
587			}),
588			results: []result{
589				{
590					module:   "foo",
591					variant:  "windows_x86_64",
592					property: []string{"root", "host", "windows", "x86_64", "lib64", "windows_x86_64"},
593				},
594				{
595					module:   "foo",
596					variant:  "windows_x86",
597					property: []string{"root", "host", "windows", "x86", "lib32", "windows_x86"},
598				},
599			},
600		},
601		{
602			name:     "linux_musl",
603			goOS:     "linux",
604			preparer: FixtureModifyConfig(modifyTestConfigForMusl),
605			results: []result{
606				{
607					module:   "foo",
608					variant:  "linux_musl_x86_64",
609					property: []string{"root", "host", "linux", "host_linux", "musl", "linux_musl", "not_windows", "x86_64", "lib64", "linux_x86_64", "linux_musl_x86_64"},
610				},
611				{
612					module:   "foo",
613					variant:  "linux_musl_x86",
614					property: []string{"root", "host", "linux", "host_linux", "musl", "linux_musl", "not_windows", "x86", "lib32", "linux_x86", "linux_musl_x86"},
615				},
616			},
617		},
618		{
619			name: "darwin",
620			goOS: "darwin",
621			results: []result{
622				{
623					module:   "foo",
624					variant:  "darwin_x86_64",
625					property: []string{"root", "host", "darwin", "not_windows", "x86_64", "lib64", "darwin_x86_64"},
626				},
627			},
628		},
629	}
630
631	for _, tt := range testCases {
632		t.Run(tt.name, func(t *testing.T) {
633			if tt.goOS != "" && tt.goOS != runtime.GOOS {
634				t.Skipf("test requires runtime.GOOS==%s, got %s", tt.goOS, runtime.GOOS)
635			}
636			result := GroupFixturePreparers(
637				PrepareForTestWithArchMutator,
638				OptionalFixturePreparer(tt.preparer),
639				FixtureRegisterWithContext(func(ctx RegistrationContext) {
640					ctx.RegisterModuleType("module", func() Module {
641						module := &testArchPropertiesModule{}
642						module.AddProperties(&module.properties)
643						InitAndroidArchModule(module, HostAndDeviceDefault, MultilibBoth)
644						return module
645					})
646				}),
647			).RunTestWithBp(t, bp)
648
649			for _, want := range tt.results {
650				t.Run(want.module+"_"+want.variant, func(t *testing.T) {
651					got := result.ModuleForTests(want.module, want.variant).Module().(*testArchPropertiesModule).properties.A
652					AssertArrayString(t, "arch mutator property", want.property, got)
653				})
654			}
655		})
656	}
657}
658