| // 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 ( | 
 | 	"fmt" | 
 | 	"path/filepath" | 
 | 	"testing" | 
 | ) | 
 |  | 
 | type soongConfigTestDefaultsModule struct { | 
 | 	ModuleBase | 
 | 	DefaultsModuleBase | 
 | } | 
 |  | 
 | func soongConfigTestDefaultsModuleFactory() Module { | 
 | 	m := &soongConfigTestDefaultsModule{} | 
 | 	m.AddProperties(&soongConfigTestModuleProperties{}) | 
 | 	InitDefaultsModule(m) | 
 | 	return m | 
 | } | 
 |  | 
 | type soongConfigTestModule struct { | 
 | 	ModuleBase | 
 | 	DefaultableModuleBase | 
 | 	props      soongConfigTestModuleProperties | 
 | 	outputPath ModuleOutPath | 
 | } | 
 |  | 
 | type soongConfigTestModuleProperties struct { | 
 | 	Cflags []string | 
 | } | 
 |  | 
 | func soongConfigTestModuleFactory() Module { | 
 | 	m := &soongConfigTestModule{} | 
 | 	m.AddProperties(&m.props) | 
 | 	InitAndroidModule(m) | 
 | 	InitDefaultableModule(m) | 
 | 	return m | 
 | } | 
 |  | 
 | func (t *soongConfigTestModule) GenerateAndroidBuildActions(ctx ModuleContext) { | 
 | 	t.outputPath = PathForModuleOut(ctx, "test") | 
 | } | 
 |  | 
 | var prepareForSoongConfigTestModule = FixtureRegisterWithContext(func(ctx RegistrationContext) { | 
 | 	ctx.RegisterModuleType("test_defaults", soongConfigTestDefaultsModuleFactory) | 
 | 	ctx.RegisterModuleType("test", soongConfigTestModuleFactory) | 
 | }) | 
 |  | 
 | func TestSoongConfigModule(t *testing.T) { | 
 | 	configBp := ` | 
 | 		soong_config_module_type { | 
 | 			name: "acme_test", | 
 | 			module_type: "test", | 
 | 			config_namespace: "acme", | 
 | 			variables: ["board", "feature1", "FEATURE3", "unused_string_var"], | 
 | 			bool_variables: ["feature2", "unused_feature", "always_true"], | 
 | 			value_variables: ["size", "unused_size"], | 
 | 			properties: ["cflags", "srcs", "defaults"], | 
 | 		} | 
 |  | 
 | 		soong_config_string_variable { | 
 | 			name: "board", | 
 | 			values: ["soc_a", "soc_b", "soc_c", "soc_d"], | 
 | 		} | 
 |  | 
 | 		soong_config_string_variable { | 
 | 			name: "unused_string_var", | 
 | 			values: ["a", "b"], | 
 | 		} | 
 |  | 
 | 		soong_config_bool_variable { | 
 | 			name: "feature1", | 
 | 		} | 
 |  | 
 | 		soong_config_bool_variable { | 
 | 			name: "FEATURE3", | 
 | 		} | 
 | 	` | 
 |  | 
 | 	importBp := ` | 
 | 		soong_config_module_type_import { | 
 | 			from: "SoongConfig.bp", | 
 | 			module_types: ["acme_test"], | 
 | 		} | 
 | 	` | 
 |  | 
 | 	bp := ` | 
 | 		test_defaults { | 
 | 			name: "foo_defaults", | 
 | 			cflags: ["DEFAULT"], | 
 | 		} | 
 |  | 
 | 		acme_test { | 
 | 			name: "foo", | 
 | 			cflags: ["-DGENERIC"], | 
 | 			defaults: ["foo_defaults"], | 
 | 			soong_config_variables: { | 
 | 				board: { | 
 | 					soc_a: { | 
 | 						cflags: ["-DSOC_A"], | 
 | 					}, | 
 | 					soc_b: { | 
 | 						cflags: ["-DSOC_B"], | 
 | 					}, | 
 | 					soc_c: {}, | 
 | 					conditions_default: { | 
 | 						cflags: ["-DSOC_CONDITIONS_DEFAULT"], | 
 | 					}, | 
 | 				}, | 
 | 				size: { | 
 | 					cflags: ["-DSIZE=%s"], | 
 | 					conditions_default: { | 
 | 						cflags: ["-DSIZE=CONDITIONS_DEFAULT"], | 
 | 					}, | 
 | 				}, | 
 | 				feature1: { | 
 | 					  conditions_default: { | 
 | 						  cflags: ["-DF1_CONDITIONS_DEFAULT"], | 
 | 					  }, | 
 | 					cflags: ["-DFEATURE1"], | 
 | 				}, | 
 | 				feature2: { | 
 | 					cflags: ["-DFEATURE2"], | 
 | 					 conditions_default: { | 
 | 						 cflags: ["-DF2_CONDITIONS_DEFAULT"], | 
 | 					 }, | 
 | 				}, | 
 | 				FEATURE3: { | 
 | 					cflags: ["-DFEATURE3"], | 
 | 				}, | 
 | 			}, | 
 | 		} | 
 |  | 
 | 		test_defaults { | 
 | 			name: "foo_defaults_a", | 
 | 			cflags: ["DEFAULT_A"], | 
 | 		} | 
 |  | 
 | 		test_defaults { | 
 | 			name: "foo_defaults_b", | 
 | 			cflags: ["DEFAULT_B"], | 
 | 		} | 
 |  | 
 | 		test_defaults { | 
 | 			name: "foo_defaults_always_true", | 
 | 			cflags: ["DEFAULT_ALWAYS_TRUE"], | 
 | 		} | 
 |  | 
 | 		acme_test { | 
 | 			name: "foo_with_defaults", | 
 | 			cflags: ["-DGENERIC"], | 
 | 			defaults: ["foo_defaults"], | 
 | 			soong_config_variables: { | 
 | 				board: { | 
 | 					soc_a: { | 
 | 						cflags: ["-DSOC_A"], | 
 | 						defaults: ["foo_defaults_a"], | 
 | 					}, | 
 | 					soc_b: { | 
 | 						cflags: ["-DSOC_B"], | 
 | 						defaults: ["foo_defaults_b"], | 
 | 					}, | 
 | 					soc_c: {}, | 
 | 				}, | 
 | 				size: { | 
 | 					cflags: ["-DSIZE=%s"], | 
 | 				}, | 
 | 				feature1: { | 
 | 					cflags: ["-DFEATURE1"], | 
 | 				}, | 
 | 				feature2: { | 
 | 					cflags: ["-DFEATURE2"], | 
 | 				}, | 
 | 				FEATURE3: { | 
 | 					cflags: ["-DFEATURE3"], | 
 | 				}, | 
 | 				always_true: { | 
 | 					defaults: ["foo_defaults_always_true"], | 
 | 					conditions_default: { | 
 | 						// verify that conditions_default is skipped if the | 
 | 						// soong config variable is true by specifying a | 
 | 						// non-existent module in conditions_default | 
 | 						defaults: ["//nonexistent:defaults"], | 
 | 					} | 
 | 				}, | 
 | 			}, | 
 | 		} | 
 |     ` | 
 |  | 
 | 	fixtureForVendorVars := func(vars map[string]map[string]string) FixturePreparer { | 
 | 		return FixtureModifyProductVariables(func(variables FixtureProductVariables) { | 
 | 			variables.VendorVars = vars | 
 | 		}) | 
 | 	} | 
 |  | 
 | 	run := func(t *testing.T, bp string, fs MockFS) { | 
 | 		testCases := []struct { | 
 | 			name                     string | 
 | 			preparer                 FixturePreparer | 
 | 			fooExpectedFlags         []string | 
 | 			fooDefaultsExpectedFlags []string | 
 | 		}{ | 
 | 			{ | 
 | 				name: "withValues", | 
 | 				preparer: fixtureForVendorVars(map[string]map[string]string{ | 
 | 					"acme": { | 
 | 						"board":    "soc_a", | 
 | 						"size":     "42", | 
 | 						"feature1": "true", | 
 | 						"feature2": "false", | 
 | 						// FEATURE3 unset | 
 | 						"unused_feature":    "true", // unused | 
 | 						"unused_size":       "1",    // unused | 
 | 						"unused_string_var": "a",    // unused | 
 | 						"always_true":       "true", | 
 | 					}, | 
 | 				}), | 
 | 				fooExpectedFlags: []string{ | 
 | 					"DEFAULT", | 
 | 					"-DGENERIC", | 
 | 					"-DF2_CONDITIONS_DEFAULT", | 
 | 					"-DSIZE=42", | 
 | 					"-DSOC_A", | 
 | 					"-DFEATURE1", | 
 | 				}, | 
 | 				fooDefaultsExpectedFlags: []string{ | 
 | 					"DEFAULT_A", | 
 | 					"DEFAULT_ALWAYS_TRUE", | 
 | 					"DEFAULT", | 
 | 					"-DGENERIC", | 
 | 					"-DSIZE=42", | 
 | 					"-DSOC_A", | 
 | 					"-DFEATURE1", | 
 | 				}, | 
 | 			}, | 
 | 			{ | 
 | 				name: "empty_prop_for_string_var", | 
 | 				preparer: fixtureForVendorVars(map[string]map[string]string{ | 
 | 					"acme": { | 
 | 						"board":       "soc_c", | 
 | 						"always_true": "true", | 
 | 					}}), | 
 | 				fooExpectedFlags: []string{ | 
 | 					"DEFAULT", | 
 | 					"-DGENERIC", | 
 | 					"-DF2_CONDITIONS_DEFAULT", | 
 | 					"-DSIZE=CONDITIONS_DEFAULT", | 
 | 					"-DF1_CONDITIONS_DEFAULT", | 
 | 				}, | 
 | 				fooDefaultsExpectedFlags: []string{ | 
 | 					"DEFAULT_ALWAYS_TRUE", | 
 | 					"DEFAULT", | 
 | 					"-DGENERIC", | 
 | 				}, | 
 | 			}, | 
 | 			{ | 
 | 				name: "unused_string_var", | 
 | 				preparer: fixtureForVendorVars(map[string]map[string]string{ | 
 | 					"acme": { | 
 | 						"board":       "soc_d", | 
 | 						"always_true": "true", | 
 | 					}}), | 
 | 				fooExpectedFlags: []string{ | 
 | 					"DEFAULT", | 
 | 					"-DGENERIC", | 
 | 					"-DF2_CONDITIONS_DEFAULT", | 
 | 					"-DSIZE=CONDITIONS_DEFAULT", | 
 | 					"-DSOC_CONDITIONS_DEFAULT", // foo does not contain a prop "soc_d", so we use the default | 
 | 					"-DF1_CONDITIONS_DEFAULT", | 
 | 				}, | 
 | 				fooDefaultsExpectedFlags: []string{ | 
 | 					"DEFAULT_ALWAYS_TRUE", | 
 | 					"DEFAULT", | 
 | 					"-DGENERIC", | 
 | 				}, | 
 | 			}, | 
 |  | 
 | 			{ | 
 | 				name: "conditions_default", | 
 | 				preparer: fixtureForVendorVars(map[string]map[string]string{ | 
 | 					"acme": { | 
 | 						"always_true": "true", | 
 | 					}}), | 
 | 				fooExpectedFlags: []string{ | 
 | 					"DEFAULT", | 
 | 					"-DGENERIC", | 
 | 					"-DF2_CONDITIONS_DEFAULT", | 
 | 					"-DSIZE=CONDITIONS_DEFAULT", | 
 | 					"-DSOC_CONDITIONS_DEFAULT", | 
 | 					"-DF1_CONDITIONS_DEFAULT", | 
 | 				}, | 
 | 				fooDefaultsExpectedFlags: []string{ | 
 | 					"DEFAULT_ALWAYS_TRUE", | 
 | 					"DEFAULT", | 
 | 					"-DGENERIC", | 
 | 				}, | 
 | 			}, | 
 | 		} | 
 |  | 
 | 		for _, tc := range testCases { | 
 | 			t.Run(tc.name, func(t *testing.T) { | 
 | 				result := GroupFixturePreparers( | 
 | 					tc.preparer, | 
 | 					PrepareForTestWithDefaults, | 
 | 					PrepareForTestWithSoongConfigModuleBuildComponents, | 
 | 					prepareForSoongConfigTestModule, | 
 | 					fs.AddToFixture(), | 
 | 					FixtureWithRootAndroidBp(bp), | 
 | 				).RunTest(t) | 
 |  | 
 | 				foo := result.ModuleForTests("foo", "").Module().(*soongConfigTestModule) | 
 | 				AssertDeepEquals(t, "foo cflags", tc.fooExpectedFlags, foo.props.Cflags) | 
 |  | 
 | 				fooDefaults := result.ModuleForTests("foo_with_defaults", "").Module().(*soongConfigTestModule) | 
 | 				AssertDeepEquals(t, "foo_with_defaults cflags", tc.fooDefaultsExpectedFlags, fooDefaults.props.Cflags) | 
 | 			}) | 
 | 		} | 
 | 	} | 
 |  | 
 | 	t.Run("single file", func(t *testing.T) { | 
 | 		run(t, configBp+bp, nil) | 
 | 	}) | 
 |  | 
 | 	t.Run("import", func(t *testing.T) { | 
 | 		run(t, importBp+bp, map[string][]byte{ | 
 | 			"SoongConfig.bp": []byte(configBp), | 
 | 		}) | 
 | 	}) | 
 | } | 
 |  | 
 | func TestNonExistentPropertyInSoongConfigModule(t *testing.T) { | 
 | 	bp := ` | 
 | 		soong_config_module_type { | 
 | 			name: "acme_test", | 
 | 			module_type: "test", | 
 | 			config_namespace: "acme", | 
 | 			bool_variables: ["feature1"], | 
 | 			properties: ["made_up_property"], | 
 | 		} | 
 |  | 
 | 		acme_test { | 
 | 			name: "foo", | 
 | 			cflags: ["-DGENERIC"], | 
 | 			soong_config_variables: { | 
 | 				feature1: { | 
 | 					made_up_property: true, | 
 | 				}, | 
 | 			}, | 
 | 		} | 
 |     ` | 
 |  | 
 | 	fixtureForVendorVars := func(vars map[string]map[string]string) FixturePreparer { | 
 | 		return FixtureModifyProductVariables(func(variables FixtureProductVariables) { | 
 | 			variables.VendorVars = vars | 
 | 		}) | 
 | 	} | 
 |  | 
 | 	GroupFixturePreparers( | 
 | 		fixtureForVendorVars(map[string]map[string]string{"acme": {"feature1": "1"}}), | 
 | 		PrepareForTestWithDefaults, | 
 | 		PrepareForTestWithSoongConfigModuleBuildComponents, | 
 | 		prepareForSoongConfigTestModule, | 
 | 		FixtureWithRootAndroidBp(bp), | 
 | 	).ExtendWithErrorHandler(FixtureExpectsAllErrorsToMatchAPattern([]string{ | 
 | 		`unrecognized property "soong_config_variables.feature1.made_up_property`, | 
 | 	})).RunTest(t) | 
 | } | 
 |  | 
 | func TestDuplicateStringValueInSoongConfigStringVariable(t *testing.T) { | 
 | 	bp := ` | 
 | 		soong_config_string_variable { | 
 | 			name: "board", | 
 | 			values: ["soc_a", "soc_b", "soc_c", "soc_a"], | 
 | 		} | 
 |  | 
 | 		soong_config_module_type { | 
 | 			name: "acme_test", | 
 | 			module_type: "test", | 
 | 			config_namespace: "acme", | 
 | 			variables: ["board"], | 
 | 			properties: ["cflags", "srcs", "defaults"], | 
 | 		} | 
 |     ` | 
 |  | 
 | 	fixtureForVendorVars := func(vars map[string]map[string]string) FixturePreparer { | 
 | 		return FixtureModifyProductVariables(func(variables FixtureProductVariables) { | 
 | 			variables.VendorVars = vars | 
 | 		}) | 
 | 	} | 
 |  | 
 | 	GroupFixturePreparers( | 
 | 		fixtureForVendorVars(map[string]map[string]string{"acme": {"feature1": "1"}}), | 
 | 		PrepareForTestWithDefaults, | 
 | 		PrepareForTestWithSoongConfigModuleBuildComponents, | 
 | 		prepareForSoongConfigTestModule, | 
 | 		FixtureWithRootAndroidBp(bp), | 
 | 	).ExtendWithErrorHandler(FixtureExpectsAllErrorsToMatchAPattern([]string{ | 
 | 		// TODO(b/171232169): improve the error message for non-existent properties | 
 | 		`Android.bp: soong_config_string_variable: values property error: duplicate value: "soc_a"`, | 
 | 	})).RunTest(t) | 
 | } | 
 |  | 
 | type soongConfigTestSingletonModule struct { | 
 | 	SingletonModuleBase | 
 | 	props soongConfigTestSingletonModuleProperties | 
 | } | 
 |  | 
 | type soongConfigTestSingletonModuleProperties struct { | 
 | 	Fragments []struct { | 
 | 		Apex   string | 
 | 		Module string | 
 | 	} | 
 | } | 
 |  | 
 | func soongConfigTestSingletonModuleFactory() SingletonModule { | 
 | 	m := &soongConfigTestSingletonModule{} | 
 | 	m.AddProperties(&m.props) | 
 | 	InitAndroidModule(m) | 
 | 	return m | 
 | } | 
 |  | 
 | func (t *soongConfigTestSingletonModule) GenerateAndroidBuildActions(ModuleContext) {} | 
 |  | 
 | func (t *soongConfigTestSingletonModule) GenerateSingletonBuildActions(SingletonContext) {} | 
 |  | 
 | var prepareForSoongConfigTestSingletonModule = FixtureRegisterWithContext(func(ctx RegistrationContext) { | 
 | 	ctx.RegisterSingletonModuleType("test_singleton", soongConfigTestSingletonModuleFactory) | 
 | }) | 
 |  | 
 | func TestSoongConfigModuleSingletonModule(t *testing.T) { | 
 | 	bp := ` | 
 | 		soong_config_module_type { | 
 | 			name: "acme_test_singleton", | 
 | 			module_type: "test_singleton", | 
 | 			config_namespace: "acme", | 
 | 			bool_variables: ["coyote"], | 
 | 			properties: ["fragments"], | 
 | 		} | 
 |  | 
 | 		acme_test_singleton { | 
 | 			name: "wiley", | 
 | 			fragments: [ | 
 | 				{ | 
 | 					apex: "com.android.acme", | 
 | 					module: "road-runner", | 
 | 				}, | 
 | 			], | 
 | 			soong_config_variables: { | 
 | 				coyote: { | 
 | 					fragments: [ | 
 | 						{ | 
 | 							apex: "com.android.acme", | 
 | 							module: "wiley", | 
 | 						}, | 
 | 					], | 
 | 				}, | 
 | 			}, | 
 | 		} | 
 | 	` | 
 |  | 
 | 	for _, test := range []struct { | 
 | 		coyote            bool | 
 | 		expectedFragments string | 
 | 	}{ | 
 | 		{ | 
 | 			coyote:            false, | 
 | 			expectedFragments: "[{Apex:com.android.acme Module:road-runner}]", | 
 | 		}, | 
 | 		{ | 
 | 			coyote:            true, | 
 | 			expectedFragments: "[{Apex:com.android.acme Module:road-runner} {Apex:com.android.acme Module:wiley}]", | 
 | 		}, | 
 | 	} { | 
 | 		t.Run(fmt.Sprintf("coyote:%t", test.coyote), func(t *testing.T) { | 
 | 			result := GroupFixturePreparers( | 
 | 				PrepareForTestWithSoongConfigModuleBuildComponents, | 
 | 				prepareForSoongConfigTestSingletonModule, | 
 | 				FixtureWithRootAndroidBp(bp), | 
 | 				FixtureModifyProductVariables(func(variables FixtureProductVariables) { | 
 | 					variables.VendorVars = map[string]map[string]string{ | 
 | 						"acme": { | 
 | 							"coyote": fmt.Sprintf("%t", test.coyote), | 
 | 						}, | 
 | 					} | 
 | 				}), | 
 | 			).RunTest(t) | 
 |  | 
 | 			// Make sure that the singleton was created. | 
 | 			result.SingletonForTests("test_singleton") | 
 | 			m := result.ModuleForTests("wiley", "").module.(*soongConfigTestSingletonModule) | 
 | 			AssertStringEquals(t, "fragments", test.expectedFragments, fmt.Sprintf("%+v", m.props.Fragments)) | 
 | 		}) | 
 | 	} | 
 | } | 
 |  | 
 | func TestSoongConfigModuleTrace(t *testing.T) { | 
 | 	bp := ` | 
 | 		soong_config_module_type { | 
 | 			name: "acme_test", | 
 | 			module_type: "test", | 
 | 			config_namespace: "acme", | 
 | 			variables: ["board", "feature1", "FEATURE3", "unused_string_var"], | 
 | 			bool_variables: ["feature2", "unused_feature", "always_true"], | 
 | 			value_variables: ["size", "unused_size"], | 
 | 			properties: ["cflags", "srcs", "defaults"], | 
 | 		} | 
 |  | 
 | 		soong_config_module_type { | 
 | 			name: "acme_test_defaults", | 
 | 			module_type: "test_defaults", | 
 | 			config_namespace: "acme", | 
 | 			variables: ["board", "feature1", "FEATURE3", "unused_string_var"], | 
 | 			bool_variables: ["feature2", "unused_feature", "always_true"], | 
 | 			value_variables: ["size", "unused_size"], | 
 | 			properties: ["cflags", "srcs", "defaults"], | 
 | 		} | 
 |  | 
 | 		soong_config_string_variable { | 
 | 			name: "board", | 
 | 			values: ["soc_a", "soc_b", "soc_c"], | 
 | 		} | 
 |  | 
 | 		soong_config_string_variable { | 
 | 			name: "unused_string_var", | 
 | 			values: ["a", "b"], | 
 | 		} | 
 |  | 
 | 		soong_config_bool_variable { | 
 | 			name: "feature1", | 
 | 		} | 
 |  | 
 | 		soong_config_bool_variable { | 
 | 			name: "FEATURE3", | 
 | 		} | 
 |  | 
 | 		test_defaults { | 
 | 			name: "test_defaults", | 
 | 			cflags: ["DEFAULT"], | 
 | 		} | 
 |  | 
 | 		test { | 
 | 			name: "normal", | 
 | 			defaults: ["test_defaults"], | 
 | 		} | 
 |  | 
 | 		acme_test { | 
 | 			name: "board_1", | 
 | 			defaults: ["test_defaults"], | 
 | 			soong_config_variables: { | 
 | 				board: { | 
 | 					soc_a: { | 
 | 						cflags: ["-DSOC_A"], | 
 | 					}, | 
 | 				}, | 
 | 			}, | 
 | 		} | 
 |  | 
 | 		acme_test { | 
 | 			name: "board_2", | 
 | 			defaults: ["test_defaults"], | 
 | 			soong_config_variables: { | 
 | 				board: { | 
 | 					soc_a: { | 
 | 						cflags: ["-DSOC_A"], | 
 | 					}, | 
 | 				}, | 
 | 			}, | 
 | 		} | 
 |  | 
 | 		acme_test { | 
 | 			name: "size", | 
 | 			defaults: ["test_defaults"], | 
 | 			soong_config_variables: { | 
 | 				size: { | 
 | 					cflags: ["-DSIZE=%s"], | 
 | 				}, | 
 | 			}, | 
 | 		} | 
 |  | 
 | 		acme_test { | 
 | 			name: "board_and_size", | 
 | 			defaults: ["test_defaults"], | 
 | 			soong_config_variables: { | 
 | 				board: { | 
 | 					soc_a: { | 
 | 						cflags: ["-DSOC_A"], | 
 | 					}, | 
 | 				}, | 
 | 				size: { | 
 | 					cflags: ["-DSIZE=%s"], | 
 | 				}, | 
 | 			}, | 
 | 		} | 
 |  | 
 | 		acme_test_defaults { | 
 | 			name: "board_defaults", | 
 | 			soong_config_variables: { | 
 | 				board: { | 
 | 					soc_a: { | 
 | 						cflags: ["-DSOC_A"], | 
 | 					}, | 
 | 				}, | 
 | 			}, | 
 | 		} | 
 |  | 
 | 		acme_test_defaults { | 
 | 			name: "size_defaults", | 
 | 			soong_config_variables: { | 
 | 				size: { | 
 | 					cflags: ["-DSIZE=%s"], | 
 | 				}, | 
 | 			}, | 
 | 		} | 
 |  | 
 | 		test { | 
 | 			name: "board_and_size_with_defaults", | 
 | 			defaults: ["board_defaults", "size_defaults"], | 
 | 		} | 
 |     ` | 
 |  | 
 | 	fixtureForVendorVars := func(vars map[string]map[string]string) FixturePreparer { | 
 | 		return FixtureModifyProductVariables(func(variables FixtureProductVariables) { | 
 | 			variables.VendorVars = vars | 
 | 		}) | 
 | 	} | 
 |  | 
 | 	preparer := fixtureForVendorVars(map[string]map[string]string{ | 
 | 		"acme": { | 
 | 			"board":    "soc_a", | 
 | 			"size":     "42", | 
 | 			"feature1": "true", | 
 | 			"feature2": "false", | 
 | 			// FEATURE3 unset | 
 | 			"unused_feature":    "true", // unused | 
 | 			"unused_size":       "1",    // unused | 
 | 			"unused_string_var": "a",    // unused | 
 | 			"always_true":       "true", | 
 | 		}, | 
 | 	}) | 
 |  | 
 | 	t.Run("soong config trace hash", func(t *testing.T) { | 
 | 		result := GroupFixturePreparers( | 
 | 			preparer, | 
 | 			PrepareForTestWithDefaults, | 
 | 			PrepareForTestWithSoongConfigModuleBuildComponents, | 
 | 			prepareForSoongConfigTestModule, | 
 | 			FixtureRegisterWithContext(func(ctx RegistrationContext) { | 
 | 				ctx.FinalDepsMutators(registerSoongConfigTraceMutator) | 
 | 			}), | 
 | 			FixtureWithRootAndroidBp(bp), | 
 | 		).RunTest(t) | 
 |  | 
 | 		// Hashes of modules not using soong config should be empty | 
 | 		normal := result.ModuleForTests("normal", "").Module().(*soongConfigTestModule) | 
 | 		AssertDeepEquals(t, "normal hash", normal.base().commonProperties.SoongConfigTraceHash, "") | 
 | 		AssertDeepEquals(t, "normal hash out", normal.outputPath.RelativeToTop().String(), "out/soong/.intermediates/normal/test") | 
 |  | 
 | 		board1 := result.ModuleForTests("board_1", "").Module().(*soongConfigTestModule) | 
 | 		board2 := result.ModuleForTests("board_2", "").Module().(*soongConfigTestModule) | 
 | 		size := result.ModuleForTests("size", "").Module().(*soongConfigTestModule) | 
 |  | 
 | 		// Trace mutator sets soong config trace hash correctly | 
 | 		board1Hash := board1.base().commonProperties.SoongConfigTrace.hash() | 
 | 		board1Output := board1.outputPath.RelativeToTop().String() | 
 | 		AssertDeepEquals(t, "board hash calc", board1Hash, board1.base().commonProperties.SoongConfigTraceHash) | 
 | 		AssertDeepEquals(t, "board hash path", board1Output, filepath.Join("out/soong/.intermediates/board_1", board1Hash, "test")) | 
 |  | 
 | 		sizeHash := size.base().commonProperties.SoongConfigTrace.hash() | 
 | 		sizeOutput := size.outputPath.RelativeToTop().String() | 
 | 		AssertDeepEquals(t, "size hash calc", sizeHash, size.base().commonProperties.SoongConfigTraceHash) | 
 | 		AssertDeepEquals(t, "size hash path", sizeOutput, filepath.Join("out/soong/.intermediates/size", sizeHash, "test")) | 
 |  | 
 | 		// Trace should be identical for modules using the same set of variables | 
 | 		AssertDeepEquals(t, "board trace", board1.base().commonProperties.SoongConfigTrace, board2.base().commonProperties.SoongConfigTrace) | 
 | 		AssertDeepEquals(t, "board hash", board1.base().commonProperties.SoongConfigTraceHash, board2.base().commonProperties.SoongConfigTraceHash) | 
 |  | 
 | 		// Trace hash should be different for different sets of soong variables | 
 | 		AssertBoolEquals(t, "board hash not equal to size hash", board1.base().commonProperties.SoongConfigTraceHash == size.commonProperties.SoongConfigTraceHash, false) | 
 |  | 
 | 		boardSize := result.ModuleForTests("board_and_size", "").Module().(*soongConfigTestModule) | 
 | 		boardSizeDefaults := result.ModuleForTests("board_and_size_with_defaults", "").Module() | 
 |  | 
 | 		// Trace should propagate | 
 | 		AssertDeepEquals(t, "board_size hash calc", boardSize.base().commonProperties.SoongConfigTrace.hash(), boardSize.base().commonProperties.SoongConfigTraceHash) | 
 | 		AssertDeepEquals(t, "board_size trace", boardSize.base().commonProperties.SoongConfigTrace, boardSizeDefaults.base().commonProperties.SoongConfigTrace) | 
 | 		AssertDeepEquals(t, "board_size hash", boardSize.base().commonProperties.SoongConfigTraceHash, boardSizeDefaults.base().commonProperties.SoongConfigTraceHash) | 
 | 	}) | 
 | } |