| // Copyright 2019 Google Inc. All rights reserved. | 
 | // | 
 | // Licensed under the Apache License, Version 2.0 (the "License"); | 
 | // you may not use this file except in compliance with the License. | 
 | // You may obtain a copy of the License at | 
 | // | 
 | //     http://www.apache.org/licenses/LICENSE-2.0 | 
 | // | 
 | // Unless required by applicable law or agreed to in writing, software | 
 | // distributed under the License is distributed on an "AS IS" BASIS, | 
 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 | // See the License for the specific language governing permissions and | 
 | // limitations under the License. | 
 |  | 
 | package android | 
 |  | 
 | import ( | 
 | 	"reflect" | 
 | 	"runtime" | 
 | 	"testing" | 
 |  | 
 | 	"github.com/google/blueprint/proptools" | 
 | ) | 
 |  | 
 | type Named struct { | 
 | 	A *string `android:"arch_variant"` | 
 | 	B *string | 
 | } | 
 |  | 
 | type NamedAllFiltered struct { | 
 | 	A *string | 
 | } | 
 |  | 
 | type NamedNoneFiltered struct { | 
 | 	A *string `android:"arch_variant"` | 
 | } | 
 |  | 
 | func TestFilterArchStruct(t *testing.T) { | 
 | 	tests := []struct { | 
 | 		name     string | 
 | 		in       interface{} | 
 | 		out      interface{} | 
 | 		filtered bool | 
 | 	}{ | 
 | 		// Property tests | 
 | 		{ | 
 | 			name: "basic", | 
 | 			in: &struct { | 
 | 				A *string `android:"arch_variant"` | 
 | 				B *string | 
 | 			}{}, | 
 | 			out: &struct { | 
 | 				A *string | 
 | 			}{}, | 
 | 			filtered: true, | 
 | 		}, | 
 | 		{ | 
 | 			name: "tags", | 
 | 			in: &struct { | 
 | 				A *string `android:"arch_variant"` | 
 | 				B *string `android:"arch_variant,path"` | 
 | 				C *string `android:"arch_variant,path,variant_prepend"` | 
 | 				D *string `android:"path,variant_prepend,arch_variant"` | 
 | 				E *string `android:"path"` | 
 | 				F *string | 
 | 			}{}, | 
 | 			out: &struct { | 
 | 				A *string | 
 | 				B *string | 
 | 				C *string | 
 | 				D *string | 
 | 			}{}, | 
 | 			filtered: true, | 
 | 		}, | 
 | 		{ | 
 | 			name: "all filtered", | 
 | 			in: &struct { | 
 | 				A *string | 
 | 			}{}, | 
 | 			out:      nil, | 
 | 			filtered: true, | 
 | 		}, | 
 | 		{ | 
 | 			name: "none filtered", | 
 | 			in: &struct { | 
 | 				A *string `android:"arch_variant"` | 
 | 			}{}, | 
 | 			out: &struct { | 
 | 				A *string `android:"arch_variant"` | 
 | 			}{}, | 
 | 			filtered: false, | 
 | 		}, | 
 |  | 
 | 		// Sub-struct tests | 
 | 		{ | 
 | 			name: "substruct", | 
 | 			in: &struct { | 
 | 				A struct { | 
 | 					A *string `android:"arch_variant"` | 
 | 					B *string | 
 | 				} `android:"arch_variant"` | 
 | 			}{}, | 
 | 			out: &struct { | 
 | 				A struct { | 
 | 					A *string | 
 | 				} | 
 | 			}{}, | 
 | 			filtered: true, | 
 | 		}, | 
 | 		{ | 
 | 			name: "substruct all filtered", | 
 | 			in: &struct { | 
 | 				A struct { | 
 | 					A *string | 
 | 				} `android:"arch_variant"` | 
 | 			}{}, | 
 | 			out:      nil, | 
 | 			filtered: true, | 
 | 		}, | 
 | 		{ | 
 | 			name: "substruct none filtered", | 
 | 			in: &struct { | 
 | 				A struct { | 
 | 					A *string `android:"arch_variant"` | 
 | 				} `android:"arch_variant"` | 
 | 			}{}, | 
 | 			out: &struct { | 
 | 				A struct { | 
 | 					A *string `android:"arch_variant"` | 
 | 				} `android:"arch_variant"` | 
 | 			}{}, | 
 | 			filtered: false, | 
 | 		}, | 
 |  | 
 | 		// Named sub-struct tests | 
 | 		{ | 
 | 			name: "named substruct", | 
 | 			in: &struct { | 
 | 				A Named `android:"arch_variant"` | 
 | 			}{}, | 
 | 			out: &struct { | 
 | 				A struct { | 
 | 					A *string | 
 | 				} | 
 | 			}{}, | 
 | 			filtered: true, | 
 | 		}, | 
 | 		{ | 
 | 			name: "substruct all filtered", | 
 | 			in: &struct { | 
 | 				A NamedAllFiltered `android:"arch_variant"` | 
 | 			}{}, | 
 | 			out:      nil, | 
 | 			filtered: true, | 
 | 		}, | 
 | 		{ | 
 | 			name: "substruct none filtered", | 
 | 			in: &struct { | 
 | 				A NamedNoneFiltered `android:"arch_variant"` | 
 | 			}{}, | 
 | 			out: &struct { | 
 | 				A NamedNoneFiltered `android:"arch_variant"` | 
 | 			}{}, | 
 | 			filtered: false, | 
 | 		}, | 
 |  | 
 | 		// Pointer to sub-struct tests | 
 | 		{ | 
 | 			name: "pointer substruct", | 
 | 			in: &struct { | 
 | 				A *struct { | 
 | 					A *string `android:"arch_variant"` | 
 | 					B *string | 
 | 				} `android:"arch_variant"` | 
 | 			}{}, | 
 | 			out: &struct { | 
 | 				A *struct { | 
 | 					A *string | 
 | 				} | 
 | 			}{}, | 
 | 			filtered: true, | 
 | 		}, | 
 | 		{ | 
 | 			name: "pointer substruct all filtered", | 
 | 			in: &struct { | 
 | 				A *struct { | 
 | 					A *string | 
 | 				} `android:"arch_variant"` | 
 | 			}{}, | 
 | 			out:      nil, | 
 | 			filtered: true, | 
 | 		}, | 
 | 		{ | 
 | 			name: "pointer substruct none filtered", | 
 | 			in: &struct { | 
 | 				A *struct { | 
 | 					A *string `android:"arch_variant"` | 
 | 				} `android:"arch_variant"` | 
 | 			}{}, | 
 | 			out: &struct { | 
 | 				A *struct { | 
 | 					A *string `android:"arch_variant"` | 
 | 				} `android:"arch_variant"` | 
 | 			}{}, | 
 | 			filtered: false, | 
 | 		}, | 
 |  | 
 | 		// Pointer to named sub-struct tests | 
 | 		{ | 
 | 			name: "pointer named substruct", | 
 | 			in: &struct { | 
 | 				A *Named `android:"arch_variant"` | 
 | 			}{}, | 
 | 			out: &struct { | 
 | 				A *struct { | 
 | 					A *string | 
 | 				} | 
 | 			}{}, | 
 | 			filtered: true, | 
 | 		}, | 
 | 		{ | 
 | 			name: "pointer substruct all filtered", | 
 | 			in: &struct { | 
 | 				A *NamedAllFiltered `android:"arch_variant"` | 
 | 			}{}, | 
 | 			out:      nil, | 
 | 			filtered: true, | 
 | 		}, | 
 | 		{ | 
 | 			name: "pointer substruct none filtered", | 
 | 			in: &struct { | 
 | 				A *NamedNoneFiltered `android:"arch_variant"` | 
 | 			}{}, | 
 | 			out: &struct { | 
 | 				A *NamedNoneFiltered `android:"arch_variant"` | 
 | 			}{}, | 
 | 			filtered: false, | 
 | 		}, | 
 | 	} | 
 |  | 
 | 	for _, test := range tests { | 
 | 		t.Run(test.name, func(t *testing.T) { | 
 | 			out, filtered := proptools.FilterPropertyStruct(reflect.TypeOf(test.in), filterArchStruct) | 
 | 			if filtered != test.filtered { | 
 | 				t.Errorf("expected filtered %v, got %v", test.filtered, filtered) | 
 | 			} | 
 | 			expected := reflect.TypeOf(test.out) | 
 | 			if out != expected { | 
 | 				t.Errorf("expected type %v, got %v", expected, out) | 
 | 			} | 
 | 		}) | 
 | 	} | 
 | } | 
 |  | 
 | type archTestModule struct { | 
 | 	ModuleBase | 
 | 	props struct { | 
 | 		Deps []string | 
 | 	} | 
 | } | 
 |  | 
 | func (m *archTestMultiTargetsModule) GenerateAndroidBuildActions(ctx ModuleContext) { | 
 | } | 
 |  | 
 | func (m *archTestMultiTargetsModule) DepsMutator(ctx BottomUpMutatorContext) { | 
 | 	ctx.AddDependency(ctx.Module(), nil, m.props.Deps...) | 
 | } | 
 |  | 
 | func archTestMultiTargetsModuleFactory() Module { | 
 | 	m := &archTestMultiTargetsModule{} | 
 | 	m.AddProperties(&m.props) | 
 | 	InitAndroidMultiTargetsArchModule(m, HostAndDeviceSupported, MultilibCommon) | 
 | 	return m | 
 | } | 
 |  | 
 | type archTestMultiTargetsModule struct { | 
 | 	ModuleBase | 
 | 	props struct { | 
 | 		Deps []string | 
 | 	} | 
 | } | 
 |  | 
 | func (m *archTestModule) GenerateAndroidBuildActions(ctx ModuleContext) { | 
 | } | 
 |  | 
 | func (m *archTestModule) DepsMutator(ctx BottomUpMutatorContext) { | 
 | 	ctx.AddDependency(ctx.Module(), nil, m.props.Deps...) | 
 | } | 
 |  | 
 | func archTestModuleFactory() Module { | 
 | 	m := &archTestModule{} | 
 | 	m.AddProperties(&m.props) | 
 | 	InitAndroidArchModule(m, HostAndDeviceSupported, MultilibBoth) | 
 | 	return m | 
 | } | 
 |  | 
 | var prepareForArchTest = GroupFixturePreparers( | 
 | 	PrepareForTestWithArchMutator, | 
 | 	FixtureRegisterWithContext(func(ctx RegistrationContext) { | 
 | 		ctx.RegisterModuleType("module", archTestModuleFactory) | 
 | 		ctx.RegisterModuleType("multi_targets_module", archTestMultiTargetsModuleFactory) | 
 | 	}), | 
 | ) | 
 |  | 
 | func TestArchMutator(t *testing.T) { | 
 | 	var buildOSVariants []string | 
 | 	var buildOS64Variants []string | 
 | 	var buildOS32Variants []string | 
 | 	var buildOSCommonVariant string | 
 |  | 
 | 	switch runtime.GOOS { | 
 | 	case "linux": | 
 | 		buildOSVariants = []string{"linux_glibc_x86_64", "linux_glibc_x86"} | 
 | 		buildOS64Variants = []string{"linux_glibc_x86_64"} | 
 | 		buildOS32Variants = []string{"linux_glibc_x86"} | 
 | 		buildOSCommonVariant = "linux_glibc_common" | 
 | 	case "darwin": | 
 | 		buildOSVariants = []string{"darwin_x86_64"} | 
 | 		buildOS64Variants = []string{"darwin_x86_64"} | 
 | 		buildOS32Variants = nil | 
 | 		buildOSCommonVariant = "darwin_common" | 
 | 	} | 
 |  | 
 | 	bp := ` | 
 | 		module { | 
 | 			name: "foo", | 
 | 		} | 
 |  | 
 | 		module { | 
 | 			name: "bar", | 
 | 			host_supported: true, | 
 | 		} | 
 |  | 
 | 		module { | 
 | 			name: "baz", | 
 | 			device_supported: false, | 
 | 		} | 
 |  | 
 | 		module { | 
 | 			name: "qux", | 
 | 			host_supported: true, | 
 | 			compile_multilib: "32", | 
 | 		} | 
 |  | 
 | 		module { | 
 | 			name: "first", | 
 | 			host_supported: true, | 
 | 			compile_multilib: "first", | 
 | 		} | 
 |  | 
 | 		multi_targets_module { | 
 | 			name: "multi_targets", | 
 | 			host_supported: true, | 
 | 		} | 
 | 	` | 
 |  | 
 | 	testCases := []struct { | 
 | 		name          string | 
 | 		preparer      FixturePreparer | 
 | 		fooVariants   []string | 
 | 		barVariants   []string | 
 | 		bazVariants   []string | 
 | 		quxVariants   []string | 
 | 		firstVariants []string | 
 |  | 
 | 		multiTargetVariants    []string | 
 | 		multiTargetVariantsMap map[string][]string | 
 |  | 
 | 		goOS string | 
 | 	}{ | 
 | 		{ | 
 | 			name:                "normal", | 
 | 			preparer:            nil, | 
 | 			fooVariants:         []string{"android_arm64_armv8-a", "android_arm_armv7-a-neon"}, | 
 | 			barVariants:         append(buildOSVariants, "android_arm64_armv8-a", "android_arm_armv7-a-neon"), | 
 | 			bazVariants:         nil, | 
 | 			quxVariants:         append(buildOS32Variants, "android_arm_armv7-a-neon"), | 
 | 			firstVariants:       append(buildOS64Variants, "android_arm64_armv8-a"), | 
 | 			multiTargetVariants: []string{buildOSCommonVariant, "android_common"}, | 
 | 			multiTargetVariantsMap: map[string][]string{ | 
 | 				buildOSCommonVariant: buildOS64Variants, | 
 | 				"android_common":     {"android_arm64_armv8-a"}, | 
 | 			}}, | 
 | 		{ | 
 | 			name: "host-only", | 
 | 			preparer: FixtureModifyConfig(func(config Config) { | 
 | 				config.BuildOSTarget = Target{} | 
 | 				config.BuildOSCommonTarget = Target{} | 
 | 				config.Targets[Android] = nil | 
 | 			}), | 
 | 			fooVariants:         nil, | 
 | 			barVariants:         buildOSVariants, | 
 | 			bazVariants:         nil, | 
 | 			quxVariants:         buildOS32Variants, | 
 | 			firstVariants:       buildOS64Variants, | 
 | 			multiTargetVariants: []string{buildOSCommonVariant}, | 
 | 			multiTargetVariantsMap: map[string][]string{ | 
 | 				buildOSCommonVariant: buildOS64Variants, | 
 | 			}, | 
 | 		}, | 
 | 		{ | 
 | 			name: "same arch host and host cross", | 
 | 			preparer: FixtureModifyConfig(func(config Config) { | 
 | 				ModifyTestConfigForMusl(config) | 
 | 				modifyTestConfigForMuslArm64HostCross(config) | 
 | 			}), | 
 | 			fooVariants:         []string{"android_arm64_armv8-a", "android_arm_armv7-a-neon"}, | 
 | 			barVariants:         []string{"linux_musl_x86_64", "linux_musl_arm64", "linux_musl_x86", "android_arm64_armv8-a", "android_arm_armv7-a-neon"}, | 
 | 			bazVariants:         nil, | 
 | 			quxVariants:         []string{"linux_musl_x86", "android_arm_armv7-a-neon"}, | 
 | 			firstVariants:       []string{"linux_musl_x86_64", "linux_musl_arm64", "android_arm64_armv8-a"}, | 
 | 			multiTargetVariants: []string{"linux_musl_common", "android_common"}, | 
 | 			multiTargetVariantsMap: map[string][]string{ | 
 | 				"linux_musl_common": {"linux_musl_x86_64"}, | 
 | 				"android_common":    {"android_arm64_armv8-a"}, | 
 | 			}, | 
 | 			goOS: "linux", | 
 | 		}, | 
 | 	} | 
 |  | 
 | 	enabledVariants := func(ctx *TestContext, name string) []string { | 
 | 		var ret []string | 
 | 		variants := ctx.ModuleVariantsForTests(name) | 
 | 		for _, variant := range variants { | 
 | 			m := ctx.ModuleForTests(name, variant) | 
 | 			if m.Module().Enabled() { | 
 | 				ret = append(ret, variant) | 
 | 			} | 
 | 		} | 
 | 		return ret | 
 | 	} | 
 |  | 
 | 	moduleMultiTargets := func(ctx *TestContext, name string, variant string) []string { | 
 | 		var ret []string | 
 | 		targets := ctx.ModuleForTests(name, variant).Module().MultiTargets() | 
 | 		for _, t := range targets { | 
 | 			ret = append(ret, t.String()) | 
 | 		} | 
 | 		return ret | 
 | 	} | 
 |  | 
 | 	for _, tt := range testCases { | 
 | 		t.Run(tt.name, func(t *testing.T) { | 
 | 			if tt.goOS != runtime.GOOS { | 
 | 				t.Skipf("requries runtime.GOOS %s", tt.goOS) | 
 | 			} | 
 |  | 
 | 			result := GroupFixturePreparers( | 
 | 				prepareForArchTest, | 
 | 				// Test specific preparer | 
 | 				OptionalFixturePreparer(tt.preparer), | 
 | 				FixtureWithRootAndroidBp(bp), | 
 | 			).RunTest(t) | 
 | 			ctx := result.TestContext | 
 |  | 
 | 			if g, w := enabledVariants(ctx, "foo"), tt.fooVariants; !reflect.DeepEqual(w, g) { | 
 | 				t.Errorf("want foo variants:\n%q\ngot:\n%q\n", w, g) | 
 | 			} | 
 |  | 
 | 			if g, w := enabledVariants(ctx, "bar"), tt.barVariants; !reflect.DeepEqual(w, g) { | 
 | 				t.Errorf("want bar variants:\n%q\ngot:\n%q\n", w, g) | 
 | 			} | 
 |  | 
 | 			if g, w := enabledVariants(ctx, "baz"), tt.bazVariants; !reflect.DeepEqual(w, g) { | 
 | 				t.Errorf("want baz variants:\n%q\ngot:\n%q\n", w, g) | 
 | 			} | 
 |  | 
 | 			if g, w := enabledVariants(ctx, "qux"), tt.quxVariants; !reflect.DeepEqual(w, g) { | 
 | 				t.Errorf("want qux variants:\n%q\ngot:\n%q\n", w, g) | 
 | 			} | 
 | 			if g, w := enabledVariants(ctx, "first"), tt.firstVariants; !reflect.DeepEqual(w, g) { | 
 | 				t.Errorf("want first variants:\n%q\ngot:\n%q\n", w, g) | 
 | 			} | 
 |  | 
 | 			if g, w := enabledVariants(ctx, "multi_targets"), tt.multiTargetVariants; !reflect.DeepEqual(w, g) { | 
 | 				t.Fatalf("want multi_target variants:\n%q\ngot:\n%q\n", w, g) | 
 | 			} | 
 |  | 
 | 			for _, variant := range tt.multiTargetVariants { | 
 | 				targets := moduleMultiTargets(ctx, "multi_targets", variant) | 
 | 				if g, w := targets, tt.multiTargetVariantsMap[variant]; !reflect.DeepEqual(w, g) { | 
 | 					t.Errorf("want ctx.MultiTarget() for %q:\n%q\ngot:\n%q\n", variant, w, g) | 
 | 				} | 
 | 			} | 
 | 		}) | 
 | 	} | 
 | } | 
 |  | 
 | func TestArchMutatorNativeBridge(t *testing.T) { | 
 | 	bp := ` | 
 | 		// This module is only enabled for x86. | 
 | 		module { | 
 | 			name: "foo", | 
 | 		} | 
 |  | 
 | 		// This module is enabled for x86 and arm (via native bridge). | 
 | 		module { | 
 | 			name: "bar", | 
 | 			native_bridge_supported: true, | 
 | 		} | 
 |  | 
 | 		// This module is enabled for arm (native_bridge) only. | 
 | 		module { | 
 | 			name: "baz", | 
 | 			native_bridge_supported: true, | 
 | 			enabled: false, | 
 | 			target: { | 
 | 				native_bridge: { | 
 | 					enabled: true, | 
 | 				} | 
 | 			} | 
 | 		} | 
 | 	` | 
 |  | 
 | 	testCases := []struct { | 
 | 		name        string | 
 | 		preparer    FixturePreparer | 
 | 		fooVariants []string | 
 | 		barVariants []string | 
 | 		bazVariants []string | 
 | 	}{ | 
 | 		{ | 
 | 			name:        "normal", | 
 | 			preparer:    nil, | 
 | 			fooVariants: []string{"android_x86_64_silvermont", "android_x86_silvermont"}, | 
 | 			barVariants: []string{"android_x86_64_silvermont", "android_native_bridge_arm64_armv8-a", "android_x86_silvermont", "android_native_bridge_arm_armv7-a-neon"}, | 
 | 			bazVariants: []string{"android_native_bridge_arm64_armv8-a", "android_native_bridge_arm_armv7-a-neon"}, | 
 | 		}, | 
 | 	} | 
 |  | 
 | 	enabledVariants := func(ctx *TestContext, name string) []string { | 
 | 		var ret []string | 
 | 		variants := ctx.ModuleVariantsForTests(name) | 
 | 		for _, variant := range variants { | 
 | 			m := ctx.ModuleForTests(name, variant) | 
 | 			if m.Module().Enabled() { | 
 | 				ret = append(ret, variant) | 
 | 			} | 
 | 		} | 
 | 		return ret | 
 | 	} | 
 |  | 
 | 	for _, tt := range testCases { | 
 | 		t.Run(tt.name, func(t *testing.T) { | 
 | 			result := GroupFixturePreparers( | 
 | 				prepareForArchTest, | 
 | 				// Test specific preparer | 
 | 				OptionalFixturePreparer(tt.preparer), | 
 | 				// Prepare for native bridge test | 
 | 				FixtureModifyConfig(func(config Config) { | 
 | 					config.Targets[Android] = []Target{ | 
 | 						{Android, Arch{ArchType: X86_64, ArchVariant: "silvermont", Abi: []string{"arm64-v8a"}}, NativeBridgeDisabled, "", "", false}, | 
 | 						{Android, Arch{ArchType: X86, ArchVariant: "silvermont", Abi: []string{"armeabi-v7a"}}, NativeBridgeDisabled, "", "", false}, | 
 | 						{Android, Arch{ArchType: Arm64, ArchVariant: "armv8-a", Abi: []string{"arm64-v8a"}}, NativeBridgeEnabled, "x86_64", "arm64", false}, | 
 | 						{Android, Arch{ArchType: Arm, ArchVariant: "armv7-a-neon", Abi: []string{"armeabi-v7a"}}, NativeBridgeEnabled, "x86", "arm", false}, | 
 | 					} | 
 | 				}), | 
 | 				FixtureWithRootAndroidBp(bp), | 
 | 			).RunTest(t) | 
 |  | 
 | 			ctx := result.TestContext | 
 |  | 
 | 			if g, w := enabledVariants(ctx, "foo"), tt.fooVariants; !reflect.DeepEqual(w, g) { | 
 | 				t.Errorf("want foo variants:\n%q\ngot:\n%q\n", w, g) | 
 | 			} | 
 |  | 
 | 			if g, w := enabledVariants(ctx, "bar"), tt.barVariants; !reflect.DeepEqual(w, g) { | 
 | 				t.Errorf("want bar variants:\n%q\ngot:\n%q\n", w, g) | 
 | 			} | 
 |  | 
 | 			if g, w := enabledVariants(ctx, "baz"), tt.bazVariants; !reflect.DeepEqual(w, g) { | 
 | 				t.Errorf("want qux variants:\n%q\ngot:\n%q\n", w, g) | 
 | 			} | 
 | 		}) | 
 | 	} | 
 | } | 
 |  | 
 | type testArchPropertiesModule struct { | 
 | 	ModuleBase | 
 | 	properties struct { | 
 | 		A []string `android:"arch_variant"` | 
 | 	} | 
 | } | 
 |  | 
 | func (testArchPropertiesModule) GenerateAndroidBuildActions(ctx ModuleContext) {} | 
 |  | 
 | // Module property "a" does not have "variant_prepend" tag. | 
 | // Expected variant property orders are based on this fact. | 
 | func TestArchProperties(t *testing.T) { | 
 | 	bp := ` | 
 | 		module { | 
 | 			name: "foo", | 
 | 			a: ["root"], | 
 | 			arch: { | 
 | 				arm: { | 
 | 					a:  ["arm"], | 
 | 				}, | 
 | 				arm64: { | 
 | 					a:  ["arm64"], | 
 | 				}, | 
 | 				riscv64: { a: ["riscv64"] }, | 
 | 				x86: { a:  ["x86"] }, | 
 | 				x86_64: { a:  ["x86_64"] }, | 
 | 			}, | 
 | 			multilib: { | 
 | 				lib32: { a:  ["lib32"] }, | 
 | 				lib64: { a:  ["lib64"] }, | 
 | 			}, | 
 | 			target: { | 
 | 				bionic: { a:  ["bionic"] }, | 
 | 				host: { a: ["host"] }, | 
 | 				android: { a:  ["android"] }, | 
 | 				glibc: { a:  ["glibc"] }, | 
 | 				musl: { a:  ["musl"] }, | 
 | 				linux_bionic: { a:  ["linux_bionic"] }, | 
 | 				linux: { a:  ["linux"] }, | 
 | 				host_linux: { a: ["host_linux"] }, | 
 | 				linux_glibc: { a:  ["linux_glibc"] }, | 
 | 				linux_musl: { a:  ["linux_musl"] }, | 
 | 				windows: { a:  ["windows"], enabled: true }, | 
 | 				darwin: { a:  ["darwin"] }, | 
 | 				not_windows: { a:  ["not_windows"] }, | 
 | 				android32: { a:  ["android32"] }, | 
 | 				android64: { a:  ["android64"] }, | 
 | 				android_arm: { a:  ["android_arm"] }, | 
 | 				android_arm64: { a:  ["android_arm64"] }, | 
 | 				linux_x86: { a:  ["linux_x86"] }, | 
 | 				linux_x86_64: { a:  ["linux_x86_64"] }, | 
 | 				linux_glibc_x86: { a:  ["linux_glibc_x86"] }, | 
 | 				linux_glibc_x86_64: { a:  ["linux_glibc_x86_64"] }, | 
 | 				linux_musl_x86: { a:  ["linux_musl_x86"] }, | 
 | 				linux_musl_x86_64: { a:  ["linux_musl_x86_64"] }, | 
 | 				darwin_x86_64: { a:  ["darwin_x86_64"] }, | 
 | 				windows_x86: { a:  ["windows_x86"] }, | 
 | 				windows_x86_64: { a:  ["windows_x86_64"] }, | 
 | 			}, | 
 | 		} | 
 | 	` | 
 |  | 
 | 	type result struct { | 
 | 		module   string | 
 | 		variant  string | 
 | 		property []string | 
 | 	} | 
 |  | 
 | 	testCases := []struct { | 
 | 		name     string | 
 | 		goOS     string | 
 | 		preparer FixturePreparer | 
 | 		results  []result | 
 | 	}{ | 
 | 		{ | 
 | 			name: "default", | 
 | 			results: []result{ | 
 | 				{ | 
 | 					module:   "foo", | 
 | 					variant:  "android_arm64_armv8-a", | 
 | 					property: []string{"root", "linux", "bionic", "android", "android64", "arm64", "lib64", "android_arm64"}, | 
 | 				}, | 
 | 				{ | 
 | 					module:   "foo", | 
 | 					variant:  "android_arm_armv7-a-neon", | 
 | 					property: []string{"root", "linux", "bionic", "android", "android64", "arm", "lib32", "android_arm"}, | 
 | 				}, | 
 | 			}, | 
 | 		}, | 
 | 		{ | 
 | 			name: "linux", | 
 | 			goOS: "linux", | 
 | 			results: []result{ | 
 | 				{ | 
 | 					module:   "foo", | 
 | 					variant:  "linux_glibc_x86_64", | 
 | 					property: []string{"root", "host", "linux", "host_linux", "glibc", "linux_glibc", "not_windows", "x86_64", "lib64", "linux_x86_64", "linux_glibc_x86_64"}, | 
 | 				}, | 
 | 				{ | 
 | 					module:   "foo", | 
 | 					variant:  "linux_glibc_x86", | 
 | 					property: []string{"root", "host", "linux", "host_linux", "glibc", "linux_glibc", "not_windows", "x86", "lib32", "linux_x86", "linux_glibc_x86"}, | 
 | 				}, | 
 | 			}, | 
 | 		}, | 
 | 		{ | 
 | 			name: "windows", | 
 | 			goOS: "linux", | 
 | 			preparer: FixtureModifyConfig(func(config Config) { | 
 | 				config.Targets[Windows] = []Target{ | 
 | 					{Windows, Arch{ArchType: X86_64}, NativeBridgeDisabled, "", "", true}, | 
 | 					{Windows, Arch{ArchType: X86}, NativeBridgeDisabled, "", "", true}, | 
 | 				} | 
 | 			}), | 
 | 			results: []result{ | 
 | 				{ | 
 | 					module:   "foo", | 
 | 					variant:  "windows_x86_64", | 
 | 					property: []string{"root", "host", "windows", "x86_64", "lib64", "windows_x86_64"}, | 
 | 				}, | 
 | 				{ | 
 | 					module:   "foo", | 
 | 					variant:  "windows_x86", | 
 | 					property: []string{"root", "host", "windows", "x86", "lib32", "windows_x86"}, | 
 | 				}, | 
 | 			}, | 
 | 		}, | 
 | 		{ | 
 | 			name:     "linux_musl", | 
 | 			goOS:     "linux", | 
 | 			preparer: FixtureModifyConfig(ModifyTestConfigForMusl), | 
 | 			results: []result{ | 
 | 				{ | 
 | 					module:   "foo", | 
 | 					variant:  "linux_musl_x86_64", | 
 | 					property: []string{"root", "host", "linux", "host_linux", "musl", "linux_musl", "not_windows", "x86_64", "lib64", "linux_x86_64", "linux_musl_x86_64"}, | 
 | 				}, | 
 | 				{ | 
 | 					module:   "foo", | 
 | 					variant:  "linux_musl_x86", | 
 | 					property: []string{"root", "host", "linux", "host_linux", "musl", "linux_musl", "not_windows", "x86", "lib32", "linux_x86", "linux_musl_x86"}, | 
 | 				}, | 
 | 			}, | 
 | 		}, | 
 | 		{ | 
 | 			name: "darwin", | 
 | 			goOS: "darwin", | 
 | 			results: []result{ | 
 | 				{ | 
 | 					module:   "foo", | 
 | 					variant:  "darwin_x86_64", | 
 | 					property: []string{"root", "host", "darwin", "not_windows", "x86_64", "lib64", "darwin_x86_64"}, | 
 | 				}, | 
 | 			}, | 
 | 		}, | 
 | 	} | 
 |  | 
 | 	for _, tt := range testCases { | 
 | 		t.Run(tt.name, func(t *testing.T) { | 
 | 			if tt.goOS != "" && tt.goOS != runtime.GOOS { | 
 | 				t.Skipf("test requires runtime.GOOS==%s, got %s", tt.goOS, runtime.GOOS) | 
 | 			} | 
 | 			result := GroupFixturePreparers( | 
 | 				PrepareForTestWithArchMutator, | 
 | 				OptionalFixturePreparer(tt.preparer), | 
 | 				FixtureRegisterWithContext(func(ctx RegistrationContext) { | 
 | 					ctx.RegisterModuleType("module", func() Module { | 
 | 						module := &testArchPropertiesModule{} | 
 | 						module.AddProperties(&module.properties) | 
 | 						InitAndroidArchModule(module, HostAndDeviceDefault, MultilibBoth) | 
 | 						return module | 
 | 					}) | 
 | 				}), | 
 | 			).RunTestWithBp(t, bp) | 
 |  | 
 | 			for _, want := range tt.results { | 
 | 				t.Run(want.module+"_"+want.variant, func(t *testing.T) { | 
 | 					got := result.ModuleForTests(want.module, want.variant).Module().(*testArchPropertiesModule).properties.A | 
 | 					AssertArrayString(t, "arch mutator property", want.property, got) | 
 | 				}) | 
 | 			} | 
 | 		}) | 
 | 	} | 
 | } |