| // Copyright 2017 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 ( | 
 | 	"bytes" | 
 | 	"fmt" | 
 | 	"path/filepath" | 
 | 	"regexp" | 
 | 	"sort" | 
 | 	"strings" | 
 | 	"sync" | 
 | 	"testing" | 
 |  | 
 | 	mkparser "android/soong/androidmk/parser" | 
 |  | 
 | 	"github.com/google/blueprint" | 
 | 	"github.com/google/blueprint/proptools" | 
 | ) | 
 |  | 
 | func newTestContextForFixture(config Config) *TestContext { | 
 | 	ctx := &TestContext{ | 
 | 		Context: &Context{blueprint.NewContext(), config}, | 
 | 	} | 
 |  | 
 | 	ctx.postDeps = append(ctx.postDeps, registerPathDepsMutator) | 
 |  | 
 | 	ctx.SetFs(ctx.config.fs) | 
 | 	if ctx.config.mockBpList != "" { | 
 | 		ctx.SetModuleListFile(ctx.config.mockBpList) | 
 | 	} | 
 |  | 
 | 	return ctx | 
 | } | 
 |  | 
 | func NewTestContext(config Config) *TestContext { | 
 | 	ctx := newTestContextForFixture(config) | 
 |  | 
 | 	nameResolver := NewNameResolver(config) | 
 | 	ctx.NameResolver = nameResolver | 
 | 	ctx.SetNameInterface(nameResolver) | 
 |  | 
 | 	return ctx | 
 | } | 
 |  | 
 | var PrepareForTestWithArchMutator = GroupFixturePreparers( | 
 | 	// Configure architecture targets in the fixture config. | 
 | 	FixtureModifyConfig(modifyTestConfigToSupportArchMutator), | 
 |  | 
 | 	// Add the arch mutator to the context. | 
 | 	FixtureRegisterWithContext(func(ctx RegistrationContext) { | 
 | 		ctx.PreDepsMutators(registerArchMutator) | 
 | 	}), | 
 | ) | 
 |  | 
 | var PrepareForTestWithDefaults = FixtureRegisterWithContext(func(ctx RegistrationContext) { | 
 | 	ctx.PreArchMutators(RegisterDefaultsPreArchMutators) | 
 | }) | 
 |  | 
 | var PrepareForTestWithComponentsMutator = FixtureRegisterWithContext(func(ctx RegistrationContext) { | 
 | 	ctx.PreArchMutators(RegisterComponentsMutator) | 
 | }) | 
 |  | 
 | var PrepareForTestWithPrebuilts = FixtureRegisterWithContext(RegisterPrebuiltMutators) | 
 |  | 
 | var PrepareForTestWithOverrides = FixtureRegisterWithContext(func(ctx RegistrationContext) { | 
 | 	ctx.PostDepsMutators(RegisterOverridePostDepsMutators) | 
 | }) | 
 |  | 
 | var PrepareForTestWithLicenses = GroupFixturePreparers( | 
 | 	FixtureRegisterWithContext(RegisterLicenseKindBuildComponents), | 
 | 	FixtureRegisterWithContext(RegisterLicenseBuildComponents), | 
 | 	FixtureRegisterWithContext(registerLicenseMutators), | 
 | ) | 
 |  | 
 | var PrepareForTestWithGenNotice = FixtureRegisterWithContext(RegisterGenNoticeBuildComponents) | 
 |  | 
 | func registerLicenseMutators(ctx RegistrationContext) { | 
 | 	ctx.PreArchMutators(RegisterLicensesPackageMapper) | 
 | 	ctx.PreArchMutators(RegisterLicensesPropertyGatherer) | 
 | 	ctx.PostDepsMutators(RegisterLicensesDependencyChecker) | 
 | } | 
 |  | 
 | var PrepareForTestWithLicenseDefaultModules = GroupFixturePreparers( | 
 | 	FixtureAddTextFile("build/soong/licenses/Android.bp", ` | 
 | 		license { | 
 | 				name: "Android-Apache-2.0", | 
 | 				package_name: "Android", | 
 | 				license_kinds: ["SPDX-license-identifier-Apache-2.0"], | 
 | 				copyright_notice: "Copyright (C) The Android Open Source Project", | 
 | 				license_text: ["LICENSE"], | 
 | 		} | 
 |  | 
 | 		license_kind { | 
 | 				name: "SPDX-license-identifier-Apache-2.0", | 
 | 				conditions: ["notice"], | 
 | 				url: "https://spdx.org/licenses/Apache-2.0.html", | 
 | 		} | 
 |  | 
 | 		license_kind { | 
 | 				name: "legacy_unencumbered", | 
 | 				conditions: ["unencumbered"], | 
 | 		} | 
 | 	`), | 
 | 	FixtureAddFile("build/soong/licenses/LICENSE", nil), | 
 | ) | 
 |  | 
 | var PrepareForTestWithNamespace = FixtureRegisterWithContext(func(ctx RegistrationContext) { | 
 | 	registerNamespaceBuildComponents(ctx) | 
 | 	ctx.PreArchMutators(RegisterNamespaceMutator) | 
 | }) | 
 |  | 
 | var PrepareForTestWithMakevars = FixtureRegisterWithContext(func(ctx RegistrationContext) { | 
 | 	ctx.RegisterSingletonType("makevars", makeVarsSingletonFunc) | 
 | }) | 
 |  | 
 | var PrepareForTestVintfFragmentModules = FixtureRegisterWithContext(func(ctx RegistrationContext) { | 
 | 	registerVintfFragmentComponents(ctx) | 
 | }) | 
 |  | 
 | // Test fixture preparer that will register most java build components. | 
 | // | 
 | // Singletons and mutators should only be added here if they are needed for a majority of java | 
 | // module types, otherwise they should be added under a separate preparer to allow them to be | 
 | // selected only when needed to reduce test execution time. | 
 | // | 
 | // Module types do not have much of an overhead unless they are used so this should include as many | 
 | // module types as possible. The exceptions are those module types that require mutators and/or | 
 | // singletons in order to function in which case they should be kept together in a separate | 
 | // preparer. | 
 | // | 
 | // The mutators in this group were chosen because they are needed by the vast majority of tests. | 
 | var PrepareForTestWithAndroidBuildComponents = GroupFixturePreparers( | 
 | 	// Sorted alphabetically as the actual order does not matter as tests automatically enforce the | 
 | 	// correct order. | 
 | 	PrepareForTestWithArchMutator, | 
 | 	PrepareForTestWithComponentsMutator, | 
 | 	PrepareForTestWithDefaults, | 
 | 	PrepareForTestWithFilegroup, | 
 | 	PrepareForTestWithOverrides, | 
 | 	PrepareForTestWithPackageModule, | 
 | 	PrepareForTestWithPrebuilts, | 
 | 	PrepareForTestWithVisibility, | 
 | 	PrepareForTestVintfFragmentModules, | 
 | ) | 
 |  | 
 | // Prepares an integration test with all build components from the android package. | 
 | // | 
 | // This should only be used by tests that want to run with as much of the build enabled as possible. | 
 | var PrepareForIntegrationTestWithAndroid = GroupFixturePreparers( | 
 | 	PrepareForTestWithAndroidBuildComponents, | 
 | ) | 
 |  | 
 | // Prepares a test that may be missing dependencies by setting allow_missing_dependencies to | 
 | // true. | 
 | var PrepareForTestWithAllowMissingDependencies = GroupFixturePreparers( | 
 | 	FixtureModifyProductVariables(func(variables FixtureProductVariables) { | 
 | 		variables.Allow_missing_dependencies = proptools.BoolPtr(true) | 
 | 	}), | 
 | 	FixtureModifyContext(func(ctx *TestContext) { | 
 | 		ctx.SetAllowMissingDependencies(true) | 
 | 	}), | 
 | ) | 
 |  | 
 | // Prepares a test that disallows non-existent paths. | 
 | var PrepareForTestDisallowNonExistentPaths = FixtureModifyConfig(func(config Config) { | 
 | 	config.TestAllowNonExistentPaths = false | 
 | }) | 
 |  | 
 | // PrepareForTestWithBuildFlag returns a FixturePreparer that sets the given flag to the given value. | 
 | func PrepareForTestWithBuildFlag(flag, value string) FixturePreparer { | 
 | 	return FixtureModifyProductVariables(func(variables FixtureProductVariables) { | 
 | 		if variables.BuildFlags == nil { | 
 | 			variables.BuildFlags = make(map[string]string) | 
 | 		} | 
 | 		variables.BuildFlags[flag] = value | 
 | 	}) | 
 | } | 
 |  | 
 | func NewTestArchContext(config Config) *TestContext { | 
 | 	ctx := NewTestContext(config) | 
 | 	ctx.preDeps = append(ctx.preDeps, registerArchMutator) | 
 | 	return ctx | 
 | } | 
 |  | 
 | type TestContext struct { | 
 | 	*Context | 
 | 	preArch, preDeps, postDeps, finalDeps []RegisterMutatorFunc | 
 | 	NameResolver                          *NameResolver | 
 |  | 
 | 	// The list of singletons registered for the test. | 
 | 	singletons sortableComponents | 
 |  | 
 | 	// The order in which the mutators and singletons will be run in this test | 
 | 	// context; for debugging. | 
 | 	mutatorOrder, singletonOrder []string | 
 | } | 
 |  | 
 | func (ctx *TestContext) PreArchMutators(f RegisterMutatorFunc) { | 
 | 	ctx.preArch = append(ctx.preArch, f) | 
 | } | 
 |  | 
 | func (ctx *TestContext) HardCodedPreArchMutators(f RegisterMutatorFunc) { | 
 | 	// Register mutator function as normal for testing. | 
 | 	ctx.PreArchMutators(f) | 
 | } | 
 |  | 
 | func (ctx *TestContext) otherModuleProvider(m blueprint.Module, p blueprint.AnyProviderKey) (any, bool) { | 
 | 	return ctx.Context.ModuleProvider(m, p) | 
 | } | 
 |  | 
 | func (ctx *TestContext) PreDepsMutators(f RegisterMutatorFunc) { | 
 | 	ctx.preDeps = append(ctx.preDeps, f) | 
 | } | 
 |  | 
 | func (ctx *TestContext) PostDepsMutators(f RegisterMutatorFunc) { | 
 | 	ctx.postDeps = append(ctx.postDeps, f) | 
 | } | 
 |  | 
 | func (ctx *TestContext) FinalDepsMutators(f RegisterMutatorFunc) { | 
 | 	ctx.finalDeps = append(ctx.finalDeps, f) | 
 | } | 
 |  | 
 | func (ctx *TestContext) OtherModuleProviderAdaptor() OtherModuleProviderContext { | 
 | 	return NewOtherModuleProviderAdaptor(func(module blueprint.Module, provider blueprint.AnyProviderKey) (any, bool) { | 
 | 		return ctx.otherModuleProvider(module, provider) | 
 | 	}) | 
 | } | 
 |  | 
 | func (ctx *TestContext) OtherModulePropertyErrorf(module Module, property string, fmt_ string, args ...interface{}) { | 
 | 	panic(fmt.Sprintf(fmt_, args...)) | 
 | } | 
 |  | 
 | // registeredComponentOrder defines the order in which a sortableComponent type is registered at | 
 | // runtime and provides support for reordering the components registered for a test in the same | 
 | // way. | 
 | type registeredComponentOrder struct { | 
 | 	// The name of the component type, used for error messages. | 
 | 	componentType string | 
 |  | 
 | 	// The names of the registered components in the order in which they were registered. | 
 | 	namesInOrder []string | 
 |  | 
 | 	// Maps from the component name to its position in the runtime ordering. | 
 | 	namesToIndex map[string]int | 
 |  | 
 | 	// A function that defines the order between two named components that can be used to sort a slice | 
 | 	// of component names into the same order as they appear in namesInOrder. | 
 | 	less func(string, string) bool | 
 | } | 
 |  | 
 | // registeredComponentOrderFromExistingOrder takes an existing slice of sortableComponents and | 
 | // creates a registeredComponentOrder that contains a less function that can be used to sort a | 
 | // subset of that list of names so it is in the same order as the original sortableComponents. | 
 | func registeredComponentOrderFromExistingOrder(componentType string, existingOrder sortableComponents) registeredComponentOrder { | 
 | 	// Only the names from the existing order are needed for this so create a list of component names | 
 | 	// in the correct order. | 
 | 	namesInOrder := componentsToNames(existingOrder) | 
 |  | 
 | 	// Populate the map from name to position in the list. | 
 | 	nameToIndex := make(map[string]int) | 
 | 	for i, n := range namesInOrder { | 
 | 		nameToIndex[n] = i | 
 | 	} | 
 |  | 
 | 	// A function to use to map from a name to an index in the original order. | 
 | 	indexOf := func(name string) int { | 
 | 		index, ok := nameToIndex[name] | 
 | 		if !ok { | 
 | 			// Should never happen as tests that use components that are not known at runtime do not sort | 
 | 			// so should never use this function. | 
 | 			panic(fmt.Errorf("internal error: unknown %s %q should be one of %s", componentType, name, strings.Join(namesInOrder, ", "))) | 
 | 		} | 
 | 		return index | 
 | 	} | 
 |  | 
 | 	// The less function. | 
 | 	less := func(n1, n2 string) bool { | 
 | 		i1 := indexOf(n1) | 
 | 		i2 := indexOf(n2) | 
 | 		return i1 < i2 | 
 | 	} | 
 |  | 
 | 	return registeredComponentOrder{ | 
 | 		componentType: componentType, | 
 | 		namesInOrder:  namesInOrder, | 
 | 		namesToIndex:  nameToIndex, | 
 | 		less:          less, | 
 | 	} | 
 | } | 
 |  | 
 | // componentsToNames maps from the slice of components to a slice of their names. | 
 | func componentsToNames(components sortableComponents) []string { | 
 | 	names := make([]string, len(components)) | 
 | 	for i, c := range components { | 
 | 		names[i] = c.componentName() | 
 | 	} | 
 | 	return names | 
 | } | 
 |  | 
 | // enforceOrdering enforces the supplied components are in the same order as is defined in this | 
 | // object. | 
 | // | 
 | // If the supplied components contains any components that are not registered at runtime, i.e. test | 
 | // specific components, then it is impossible to sort them into an order that both matches the | 
 | // runtime and also preserves the implicit ordering defined in the test. In that case it will not | 
 | // sort the components, instead it will just check that the components are in the correct order. | 
 | // | 
 | // Otherwise, this will sort the supplied components in place. | 
 | func (o *registeredComponentOrder) enforceOrdering(components sortableComponents) { | 
 | 	// Check to see if the list of components contains any components that are | 
 | 	// not registered at runtime. | 
 | 	var unknownComponents []string | 
 | 	testOrder := componentsToNames(components) | 
 | 	for _, name := range testOrder { | 
 | 		if _, ok := o.namesToIndex[name]; !ok { | 
 | 			unknownComponents = append(unknownComponents, name) | 
 | 			break | 
 | 		} | 
 | 	} | 
 |  | 
 | 	// If the slice contains some unknown components then it is not possible to | 
 | 	// sort them into an order that matches the runtime while also preserving the | 
 | 	// order expected from the test, so in that case don't sort just check that | 
 | 	// the order of the known mutators does match. | 
 | 	if len(unknownComponents) > 0 { | 
 | 		// Check order. | 
 | 		o.checkTestOrder(testOrder, unknownComponents) | 
 | 	} else { | 
 | 		// Sort the components. | 
 | 		sort.Slice(components, func(i, j int) bool { | 
 | 			n1 := components[i].componentName() | 
 | 			n2 := components[j].componentName() | 
 | 			return o.less(n1, n2) | 
 | 		}) | 
 | 	} | 
 | } | 
 |  | 
 | // checkTestOrder checks that the supplied testOrder matches the one defined by this object, | 
 | // panicking if it does not. | 
 | func (o *registeredComponentOrder) checkTestOrder(testOrder []string, unknownComponents []string) { | 
 | 	lastMatchingTest := -1 | 
 | 	matchCount := 0 | 
 | 	// Take a copy of the runtime order as it is modified during the comparison. | 
 | 	runtimeOrder := append([]string(nil), o.namesInOrder...) | 
 | 	componentType := o.componentType | 
 | 	for i, j := 0, 0; i < len(testOrder) && j < len(runtimeOrder); { | 
 | 		test := testOrder[i] | 
 | 		runtime := runtimeOrder[j] | 
 |  | 
 | 		if test == runtime { | 
 | 			testOrder[i] = test + fmt.Sprintf(" <-- matched with runtime %s %d", componentType, j) | 
 | 			runtimeOrder[j] = runtime + fmt.Sprintf(" <-- matched with test %s %d", componentType, i) | 
 | 			lastMatchingTest = i | 
 | 			i += 1 | 
 | 			j += 1 | 
 | 			matchCount += 1 | 
 | 		} else if _, ok := o.namesToIndex[test]; !ok { | 
 | 			// The test component is not registered globally so assume it is the correct place, treat it | 
 | 			// as having matched and skip it. | 
 | 			i += 1 | 
 | 			matchCount += 1 | 
 | 		} else { | 
 | 			// Assume that the test list is in the same order as the runtime list but the runtime list | 
 | 			// contains some components that are not present in the tests. So, skip the runtime component | 
 | 			// to try and find the next one that matches the current test component. | 
 | 			j += 1 | 
 | 		} | 
 | 	} | 
 |  | 
 | 	// If every item in the test order was either test specific or matched one in the runtime then | 
 | 	// it is in the correct order. Otherwise, it was not so fail. | 
 | 	if matchCount != len(testOrder) { | 
 | 		// The test component names were not all matched with a runtime component name so there must | 
 | 		// either be a component present in the test that is not present in the runtime or they must be | 
 | 		// in the wrong order. | 
 | 		testOrder[lastMatchingTest+1] = testOrder[lastMatchingTest+1] + " <--- unmatched" | 
 | 		panic(fmt.Errorf("the tests uses test specific components %q and so cannot be automatically sorted."+ | 
 | 			" Unfortunately it uses %s components in the wrong order.\n"+ | 
 | 			"test order:\n    %s\n"+ | 
 | 			"runtime order\n    %s\n", | 
 | 			SortedUniqueStrings(unknownComponents), | 
 | 			componentType, | 
 | 			strings.Join(testOrder, "\n    "), | 
 | 			strings.Join(runtimeOrder, "\n    "))) | 
 | 	} | 
 | } | 
 |  | 
 | // registrationSorter encapsulates the information needed to ensure that the test mutators are | 
 | // registered, and thereby executed, in the same order as they are at runtime. | 
 | // | 
 | // It MUST be populated lazily AFTER all package initialization has been done otherwise it will | 
 | // only define the order for a subset of all the registered build components that are available for | 
 | // the packages being tested. | 
 | // | 
 | // e.g if this is initialized during say the cc package initialization then any tests run in the | 
 | // java package will not sort build components registered by the java package's init() functions. | 
 | type registrationSorter struct { | 
 | 	// Used to ensure that this is only created once. | 
 | 	once sync.Once | 
 |  | 
 | 	// The order of mutators | 
 | 	mutatorOrder registeredComponentOrder | 
 |  | 
 | 	// The order of singletons | 
 | 	singletonOrder registeredComponentOrder | 
 | } | 
 |  | 
 | // populate initializes this structure from globally registered build components. | 
 | // | 
 | // Only the first call has any effect. | 
 | func (s *registrationSorter) populate() { | 
 | 	s.once.Do(func() { | 
 | 		// Created an ordering from the globally registered mutators. | 
 | 		globallyRegisteredMutators := collateGloballyRegisteredMutators() | 
 | 		s.mutatorOrder = registeredComponentOrderFromExistingOrder("mutator", globallyRegisteredMutators) | 
 |  | 
 | 		// Create an ordering from the globally registered singletons. | 
 | 		globallyRegisteredSingletons := collateGloballyRegisteredSingletons() | 
 | 		s.singletonOrder = registeredComponentOrderFromExistingOrder("singleton", globallyRegisteredSingletons) | 
 | 	}) | 
 | } | 
 |  | 
 | // Provides support for enforcing the same order in which build components are registered globally | 
 | // to the order in which they are registered during tests. | 
 | // | 
 | // MUST only be accessed via the globallyRegisteredComponentsOrder func. | 
 | var globalRegistrationSorter registrationSorter | 
 |  | 
 | // globallyRegisteredComponentsOrder returns the globalRegistrationSorter after ensuring it is | 
 | // correctly populated. | 
 | func globallyRegisteredComponentsOrder() *registrationSorter { | 
 | 	globalRegistrationSorter.populate() | 
 | 	return &globalRegistrationSorter | 
 | } | 
 |  | 
 | func (ctx *TestContext) Register() { | 
 | 	globalOrder := globallyRegisteredComponentsOrder() | 
 |  | 
 | 	mutators := collateRegisteredMutators(ctx.preArch, ctx.preDeps, ctx.postDeps, ctx.finalDeps) | 
 | 	// Ensure that the mutators used in the test are in the same order as they are used at runtime. | 
 | 	globalOrder.mutatorOrder.enforceOrdering(mutators) | 
 | 	mutators.registerAll(ctx.Context) | 
 |  | 
 | 	// Ensure that the singletons used in the test are in the same order as they are used at runtime. | 
 | 	globalOrder.singletonOrder.enforceOrdering(ctx.singletons) | 
 | 	ctx.singletons.registerAll(ctx.Context) | 
 |  | 
 | 	// Save the sorted components order away to make them easy to access while debugging. | 
 | 	ctx.mutatorOrder = componentsToNames(mutators) | 
 | 	ctx.singletonOrder = componentsToNames(singletons) | 
 | } | 
 |  | 
 | func (ctx *TestContext) ParseFileList(rootDir string, filePaths []string) (deps []string, errs []error) { | 
 | 	// This function adapts the old style ParseFileList calls that are spread throughout the tests | 
 | 	// to the new style that takes a config. | 
 | 	return ctx.Context.ParseFileList(rootDir, filePaths, ctx.config) | 
 | } | 
 |  | 
 | func (ctx *TestContext) ParseBlueprintsFiles(rootDir string) (deps []string, errs []error) { | 
 | 	// This function adapts the old style ParseBlueprintsFiles calls that are spread throughout the | 
 | 	// tests to the new style that takes a config. | 
 | 	return ctx.Context.ParseBlueprintsFiles(rootDir, ctx.config) | 
 | } | 
 |  | 
 | func (ctx *TestContext) RegisterModuleType(name string, factory ModuleFactory) { | 
 | 	ctx.Context.RegisterModuleType(name, ModuleFactoryAdaptor(factory)) | 
 | } | 
 |  | 
 | func (ctx *TestContext) RegisterSingletonModuleType(name string, factory SingletonModuleFactory) { | 
 | 	s, m := SingletonModuleFactoryAdaptor(name, factory) | 
 | 	ctx.RegisterSingletonType(name, s) | 
 | 	ctx.RegisterModuleType(name, m) | 
 | } | 
 |  | 
 | func (ctx *TestContext) RegisterParallelSingletonModuleType(name string, factory SingletonModuleFactory) { | 
 | 	s, m := SingletonModuleFactoryAdaptor(name, factory) | 
 | 	ctx.RegisterParallelSingletonType(name, s) | 
 | 	ctx.RegisterModuleType(name, m) | 
 | } | 
 |  | 
 | func (ctx *TestContext) RegisterSingletonType(name string, factory SingletonFactory) { | 
 | 	ctx.singletons = append(ctx.singletons, newSingleton(name, factory, false)) | 
 | } | 
 |  | 
 | func (ctx *TestContext) RegisterParallelSingletonType(name string, factory SingletonFactory) { | 
 | 	ctx.singletons = append(ctx.singletons, newSingleton(name, factory, true)) | 
 | } | 
 |  | 
 | // ModuleVariantForTests selects a specific variant of the module with the given | 
 | // name by matching the variations map against the variations of each module | 
 | // variant. A module variant matches the map if every variation that exists in | 
 | // both have the same value. Both the module and the map are allowed to have | 
 | // extra variations that the other doesn't have. Panics if not exactly one | 
 | // module variant matches. | 
 | func (ctx *TestContext) ModuleVariantForTests(name string, matchVariations map[string]string) TestingModule { | 
 | 	modules := []Module{} | 
 | 	ctx.VisitAllModules(func(m blueprint.Module) { | 
 | 		if ctx.ModuleName(m) == name { | 
 | 			am := m.(Module) | 
 | 			amMut := am.base().commonProperties.DebugMutators | 
 | 			amVar := am.base().commonProperties.DebugVariations | 
 | 			matched := true | 
 | 			for i, mut := range amMut { | 
 | 				if wantedVar, found := matchVariations[mut]; found && amVar[i] != wantedVar { | 
 | 					matched = false | 
 | 					break | 
 | 				} | 
 | 			} | 
 | 			if matched { | 
 | 				modules = append(modules, am) | 
 | 			} | 
 | 		} | 
 | 	}) | 
 |  | 
 | 	if len(modules) == 0 { | 
 | 		// Show all the modules or module variants that do exist. | 
 | 		var allModuleNames []string | 
 | 		var allVariants []string | 
 | 		ctx.VisitAllModules(func(m blueprint.Module) { | 
 | 			allModuleNames = append(allModuleNames, ctx.ModuleName(m)) | 
 | 			if ctx.ModuleName(m) == name { | 
 | 				allVariants = append(allVariants, m.(Module).String()) | 
 | 			} | 
 | 		}) | 
 |  | 
 | 		if len(allVariants) == 0 { | 
 | 			panic(fmt.Errorf("failed to find module %q. All modules:\n  %s", | 
 | 				name, strings.Join(SortedUniqueStrings(allModuleNames), "\n  "))) | 
 | 		} else { | 
 | 			sort.Strings(allVariants) | 
 | 			panic(fmt.Errorf("failed to find module %q matching %v. All variants:\n  %s", | 
 | 				name, matchVariations, strings.Join(allVariants, "\n  "))) | 
 | 		} | 
 | 	} | 
 |  | 
 | 	if len(modules) > 1 { | 
 | 		moduleStrings := []string{} | 
 | 		for _, m := range modules { | 
 | 			moduleStrings = append(moduleStrings, m.String()) | 
 | 		} | 
 | 		sort.Strings(moduleStrings) | 
 | 		panic(fmt.Errorf("module %q has more than one variant that match %v:\n  %s", | 
 | 			name, matchVariations, strings.Join(moduleStrings, "\n  "))) | 
 | 	} | 
 |  | 
 | 	return newTestingModule(ctx.config, modules[0]) | 
 | } | 
 |  | 
 | func (ctx *TestContext) ModuleForTests(name, variant string) TestingModule { | 
 | 	var module Module | 
 | 	ctx.VisitAllModules(func(m blueprint.Module) { | 
 | 		if ctx.ModuleName(m) == name && ctx.ModuleSubDir(m) == variant { | 
 | 			module = m.(Module) | 
 | 		} | 
 | 	}) | 
 |  | 
 | 	if module == nil { | 
 | 		// find all the modules that do exist | 
 | 		var allModuleNames []string | 
 | 		var allVariants []string | 
 | 		ctx.VisitAllModules(func(m blueprint.Module) { | 
 | 			allModuleNames = append(allModuleNames, ctx.ModuleName(m)) | 
 | 			if ctx.ModuleName(m) == name { | 
 | 				allVariants = append(allVariants, ctx.ModuleSubDir(m)) | 
 | 			} | 
 | 		}) | 
 | 		sort.Strings(allVariants) | 
 |  | 
 | 		if len(allVariants) == 0 { | 
 | 			panic(fmt.Errorf("failed to find module %q. All modules:\n  %s", | 
 | 				name, strings.Join(SortedUniqueStrings(allModuleNames), "\n  "))) | 
 | 		} else { | 
 | 			panic(fmt.Errorf("failed to find module %q variant %q. All variants:\n  %s", | 
 | 				name, variant, strings.Join(allVariants, "\n  "))) | 
 | 		} | 
 | 	} | 
 |  | 
 | 	return newTestingModule(ctx.config, module) | 
 | } | 
 |  | 
 | func (ctx *TestContext) ModuleVariantsForTests(name string) []string { | 
 | 	var variants []string | 
 | 	ctx.VisitAllModules(func(m blueprint.Module) { | 
 | 		if ctx.ModuleName(m) == name { | 
 | 			variants = append(variants, ctx.ModuleSubDir(m)) | 
 | 		} | 
 | 	}) | 
 | 	return variants | 
 | } | 
 |  | 
 | // SingletonForTests returns a TestingSingleton for the singleton registered with the given name. | 
 | func (ctx *TestContext) SingletonForTests(name string) TestingSingleton { | 
 | 	allSingletonNames := []string{} | 
 | 	for _, s := range ctx.Singletons() { | 
 | 		n := ctx.SingletonName(s) | 
 | 		if n == name { | 
 | 			return TestingSingleton{ | 
 | 				baseTestingComponent: newBaseTestingComponent(ctx.config, s.(testBuildProvider)), | 
 | 				singleton:            s.(*singletonAdaptor).Singleton, | 
 | 			} | 
 | 		} | 
 | 		allSingletonNames = append(allSingletonNames, n) | 
 | 	} | 
 |  | 
 | 	panic(fmt.Errorf("failed to find singleton %q."+ | 
 | 		"\nall singletons: %v", name, allSingletonNames)) | 
 | } | 
 |  | 
 | type InstallMakeRule struct { | 
 | 	Target        string | 
 | 	Deps          []string | 
 | 	OrderOnlyDeps []string | 
 | } | 
 |  | 
 | func parseMkRules(t *testing.T, config Config, nodes []mkparser.Node) []InstallMakeRule { | 
 | 	var rules []InstallMakeRule | 
 | 	for _, node := range nodes { | 
 | 		if mkParserRule, ok := node.(*mkparser.Rule); ok { | 
 | 			var rule InstallMakeRule | 
 |  | 
 | 			if targets := mkParserRule.Target.Words(); len(targets) == 0 { | 
 | 				t.Fatalf("no targets for rule %s", mkParserRule.Dump()) | 
 | 			} else if len(targets) > 1 { | 
 | 				t.Fatalf("unsupported multiple targets for rule %s", mkParserRule.Dump()) | 
 | 			} else if !targets[0].Const() { | 
 | 				t.Fatalf("unsupported non-const target for rule %s", mkParserRule.Dump()) | 
 | 			} else { | 
 | 				rule.Target = normalizeStringRelativeToTop(config, targets[0].Value(nil)) | 
 | 			} | 
 |  | 
 | 			prereqList := &rule.Deps | 
 | 			for _, prereq := range mkParserRule.Prerequisites.Words() { | 
 | 				if !prereq.Const() { | 
 | 					t.Fatalf("unsupported non-const prerequisite for rule %s", mkParserRule.Dump()) | 
 | 				} | 
 |  | 
 | 				if prereq.Value(nil) == "|" { | 
 | 					prereqList = &rule.OrderOnlyDeps | 
 | 					continue | 
 | 				} | 
 |  | 
 | 				*prereqList = append(*prereqList, normalizeStringRelativeToTop(config, prereq.Value(nil))) | 
 | 			} | 
 |  | 
 | 			rules = append(rules, rule) | 
 | 		} | 
 | 	} | 
 |  | 
 | 	return rules | 
 | } | 
 |  | 
 | func (ctx *TestContext) InstallMakeRulesForTesting(t *testing.T) []InstallMakeRule { | 
 | 	installs := ctx.SingletonForTests("makevars").Singleton().(*makeVarsSingleton).installsForTesting | 
 | 	buf := bytes.NewBuffer(append([]byte(nil), installs...)) | 
 | 	parser := mkparser.NewParser("makevars", buf) | 
 |  | 
 | 	nodes, errs := parser.Parse() | 
 | 	if len(errs) > 0 { | 
 | 		t.Fatalf("error parsing install rules: %s", errs[0]) | 
 | 	} | 
 |  | 
 | 	return parseMkRules(t, ctx.config, nodes) | 
 | } | 
 |  | 
 | // MakeVarVariable provides access to make vars that will be written by the makeVarsSingleton | 
 | type MakeVarVariable interface { | 
 | 	// Name is the name of the variable. | 
 | 	Name() string | 
 |  | 
 | 	// Value is the value of the variable. | 
 | 	Value() string | 
 | } | 
 |  | 
 | func (v makeVarsVariable) Name() string { | 
 | 	return v.name | 
 | } | 
 |  | 
 | func (v makeVarsVariable) Value() string { | 
 | 	return v.value | 
 | } | 
 |  | 
 | // PrepareForTestAccessingMakeVars sets up the test so that MakeVarsForTesting will work. | 
 | var PrepareForTestAccessingMakeVars = GroupFixturePreparers( | 
 | 	PrepareForTestWithAndroidMk, | 
 | 	PrepareForTestWithMakevars, | 
 | ) | 
 |  | 
 | // MakeVarsForTesting returns a filtered list of MakeVarVariable objects that represent the | 
 | // variables that will be written out. | 
 | // | 
 | // It is necessary to use PrepareForTestAccessingMakeVars in tests that want to call this function. | 
 | // Along with any other preparers needed to add the make vars. | 
 | func (ctx *TestContext) MakeVarsForTesting(filter func(variable MakeVarVariable) bool) []MakeVarVariable { | 
 | 	vars := ctx.SingletonForTests("makevars").Singleton().(*makeVarsSingleton).varsForTesting | 
 | 	result := make([]MakeVarVariable, 0, len(vars)) | 
 | 	for _, v := range vars { | 
 | 		if filter(v) { | 
 | 			result = append(result, v) | 
 | 		} | 
 | 	} | 
 |  | 
 | 	return result | 
 | } | 
 |  | 
 | func (ctx *TestContext) Config() Config { | 
 | 	return ctx.config | 
 | } | 
 |  | 
 | type testBuildProvider interface { | 
 | 	BuildParamsForTests() []BuildParams | 
 | 	RuleParamsForTests() map[blueprint.Rule]blueprint.RuleParams | 
 | } | 
 |  | 
 | type TestingBuildParams struct { | 
 | 	BuildParams | 
 | 	RuleParams blueprint.RuleParams | 
 |  | 
 | 	config Config | 
 | } | 
 |  | 
 | // RelativeToTop creates a new instance of this which has had any usages of the current test's | 
 | // temporary and test specific build directory replaced with a path relative to the notional top. | 
 | // | 
 | // The parts of this structure which are changed are: | 
 | // * BuildParams | 
 | //   - Args | 
 | //   - All Path, Paths, WritablePath and WritablePaths fields. | 
 | // | 
 | // * RuleParams | 
 | //   - Command | 
 | //   - Depfile | 
 | //   - Rspfile | 
 | //   - RspfileContent | 
 | //   - CommandDeps | 
 | //   - CommandOrderOnly | 
 | // | 
 | // See PathRelativeToTop for more details. | 
 | // | 
 | // deprecated: this is no longer needed as TestingBuildParams are created in this form. | 
 | func (p TestingBuildParams) RelativeToTop() TestingBuildParams { | 
 | 	// If this is not a valid params then just return it back. That will make it easy to use with the | 
 | 	// Maybe...() methods. | 
 | 	if p.Rule == nil { | 
 | 		return p | 
 | 	} | 
 | 	if p.config.config == nil { | 
 | 		return p | 
 | 	} | 
 | 	// Take a copy of the build params and replace any args that contains test specific temporary | 
 | 	// paths with paths relative to the top. | 
 | 	bparams := p.BuildParams | 
 | 	bparams.Depfile = normalizeWritablePathRelativeToTop(bparams.Depfile) | 
 | 	bparams.Output = normalizeWritablePathRelativeToTop(bparams.Output) | 
 | 	bparams.Outputs = bparams.Outputs.RelativeToTop() | 
 | 	bparams.ImplicitOutput = normalizeWritablePathRelativeToTop(bparams.ImplicitOutput) | 
 | 	bparams.ImplicitOutputs = bparams.ImplicitOutputs.RelativeToTop() | 
 | 	bparams.Input = normalizePathRelativeToTop(bparams.Input) | 
 | 	bparams.Inputs = bparams.Inputs.RelativeToTop() | 
 | 	bparams.Implicit = normalizePathRelativeToTop(bparams.Implicit) | 
 | 	bparams.Implicits = bparams.Implicits.RelativeToTop() | 
 | 	bparams.OrderOnly = bparams.OrderOnly.RelativeToTop() | 
 | 	bparams.Validation = normalizePathRelativeToTop(bparams.Validation) | 
 | 	bparams.Validations = bparams.Validations.RelativeToTop() | 
 | 	bparams.Args = normalizeStringMapRelativeToTop(p.config, bparams.Args) | 
 |  | 
 | 	// Ditto for any fields in the RuleParams. | 
 | 	rparams := p.RuleParams | 
 | 	rparams.Command = normalizeStringRelativeToTop(p.config, rparams.Command) | 
 | 	rparams.Depfile = normalizeStringRelativeToTop(p.config, rparams.Depfile) | 
 | 	rparams.Rspfile = normalizeStringRelativeToTop(p.config, rparams.Rspfile) | 
 | 	rparams.RspfileContent = normalizeStringRelativeToTop(p.config, rparams.RspfileContent) | 
 | 	rparams.CommandDeps = normalizeStringArrayRelativeToTop(p.config, rparams.CommandDeps) | 
 | 	rparams.CommandOrderOnly = normalizeStringArrayRelativeToTop(p.config, rparams.CommandOrderOnly) | 
 |  | 
 | 	return TestingBuildParams{ | 
 | 		BuildParams: bparams, | 
 | 		RuleParams:  rparams, | 
 | 	} | 
 | } | 
 |  | 
 | func normalizeWritablePathRelativeToTop(path WritablePath) WritablePath { | 
 | 	if path == nil { | 
 | 		return nil | 
 | 	} | 
 | 	return path.RelativeToTop().(WritablePath) | 
 | } | 
 |  | 
 | func normalizePathRelativeToTop(path Path) Path { | 
 | 	if path == nil { | 
 | 		return nil | 
 | 	} | 
 | 	return path.RelativeToTop() | 
 | } | 
 |  | 
 | func allOutputs(p BuildParams) []string { | 
 | 	outputs := append(WritablePaths(nil), p.Outputs...) | 
 | 	outputs = append(outputs, p.ImplicitOutputs...) | 
 | 	if p.Output != nil { | 
 | 		outputs = append(outputs, p.Output) | 
 | 	} | 
 | 	return outputs.Strings() | 
 | } | 
 |  | 
 | // AllOutputs returns all 'BuildParams.Output's and 'BuildParams.Outputs's in their full path string forms. | 
 | func (p TestingBuildParams) AllOutputs() []string { | 
 | 	return allOutputs(p.BuildParams) | 
 | } | 
 |  | 
 | // baseTestingComponent provides functionality common to both TestingModule and TestingSingleton. | 
 | type baseTestingComponent struct { | 
 | 	config   Config | 
 | 	provider testBuildProvider | 
 | } | 
 |  | 
 | func newBaseTestingComponent(config Config, provider testBuildProvider) baseTestingComponent { | 
 | 	return baseTestingComponent{config, provider} | 
 | } | 
 |  | 
 | // A function that will normalize a string containing paths, e.g. ninja command, by replacing | 
 | // any references to the test specific temporary build directory that changes with each run to a | 
 | // fixed path relative to a notional top directory. | 
 | // | 
 | // This is similar to StringPathRelativeToTop except that assumes the string is a single path | 
 | // containing at most one instance of the temporary build directory at the start of the path while | 
 | // this assumes that there can be any number at any position. | 
 | func normalizeStringRelativeToTop(config Config, s string) string { | 
 | 	// The outDir usually looks something like: /tmp/testFoo2345/001 | 
 | 	// | 
 | 	// Replace any usage of the outDir with out/soong, e.g. replace "/tmp/testFoo2345/001" with | 
 | 	// "out/soong". | 
 | 	outSoongDir := filepath.Clean(config.soongOutDir) | 
 | 	re := regexp.MustCompile(`\Q` + outSoongDir + `\E\b`) | 
 | 	s = re.ReplaceAllString(s, "out/soong") | 
 |  | 
 | 	// Replace any usage of the outDir/.. with out, e.g. replace "/tmp/testFoo2345" with | 
 | 	// "out". This must come after the previous replacement otherwise this would replace | 
 | 	// "/tmp/testFoo2345/001" with "out/001" instead of "out/soong". | 
 | 	outDir := filepath.Dir(outSoongDir) | 
 | 	re = regexp.MustCompile(`\Q` + outDir + `\E\b`) | 
 | 	s = re.ReplaceAllString(s, "out") | 
 |  | 
 | 	return s | 
 | } | 
 |  | 
 | // normalizeStringArrayRelativeToTop creates a new slice constructed by applying | 
 | // normalizeStringRelativeToTop to each item in the slice. | 
 | func normalizeStringArrayRelativeToTop(config Config, slice []string) []string { | 
 | 	newSlice := make([]string, len(slice)) | 
 | 	for i, s := range slice { | 
 | 		newSlice[i] = normalizeStringRelativeToTop(config, s) | 
 | 	} | 
 | 	return newSlice | 
 | } | 
 |  | 
 | // normalizeStringMapRelativeToTop creates a new map constructed by applying | 
 | // normalizeStringRelativeToTop to each value in the map. | 
 | func normalizeStringMapRelativeToTop(config Config, m map[string]string) map[string]string { | 
 | 	newMap := map[string]string{} | 
 | 	for k, v := range m { | 
 | 		newMap[k] = normalizeStringRelativeToTop(config, v) | 
 | 	} | 
 | 	return newMap | 
 | } | 
 |  | 
 | func (b baseTestingComponent) newTestingBuildParams(bparams BuildParams) TestingBuildParams { | 
 | 	return TestingBuildParams{ | 
 | 		config:      b.config, | 
 | 		BuildParams: bparams, | 
 | 		RuleParams:  b.provider.RuleParamsForTests()[bparams.Rule], | 
 | 	}.RelativeToTop() | 
 | } | 
 |  | 
 | func (b baseTestingComponent) maybeBuildParamsFromRule(rule string) (TestingBuildParams, []string) { | 
 | 	var searchedRules []string | 
 | 	buildParams := b.provider.BuildParamsForTests() | 
 | 	for _, p := range buildParams { | 
 | 		ruleAsString := p.Rule.String() | 
 | 		searchedRules = append(searchedRules, ruleAsString) | 
 | 		if strings.Contains(ruleAsString, rule) { | 
 | 			return b.newTestingBuildParams(p), searchedRules | 
 | 		} | 
 | 	} | 
 | 	return TestingBuildParams{}, searchedRules | 
 | } | 
 |  | 
 | func (b baseTestingComponent) buildParamsFromRule(rule string) TestingBuildParams { | 
 | 	p, searchRules := b.maybeBuildParamsFromRule(rule) | 
 | 	if p.Rule == nil { | 
 | 		panic(fmt.Errorf("couldn't find rule %q.\nall rules:\n%s", rule, strings.Join(searchRules, "\n"))) | 
 | 	} | 
 | 	return p | 
 | } | 
 |  | 
 | func (b baseTestingComponent) maybeBuildParamsFromDescription(desc string) (TestingBuildParams, []string) { | 
 | 	var searchedDescriptions []string | 
 | 	for _, p := range b.provider.BuildParamsForTests() { | 
 | 		searchedDescriptions = append(searchedDescriptions, p.Description) | 
 | 		if strings.Contains(p.Description, desc) { | 
 | 			return b.newTestingBuildParams(p), searchedDescriptions | 
 | 		} | 
 | 	} | 
 | 	return TestingBuildParams{}, searchedDescriptions | 
 | } | 
 |  | 
 | func (b baseTestingComponent) buildParamsFromDescription(desc string) TestingBuildParams { | 
 | 	p, searchedDescriptions := b.maybeBuildParamsFromDescription(desc) | 
 | 	if p.Rule == nil { | 
 | 		panic(fmt.Errorf("couldn't find description %q\nall descriptions:\n%s", desc, strings.Join(searchedDescriptions, "\n"))) | 
 | 	} | 
 | 	return p | 
 | } | 
 |  | 
 | func (b baseTestingComponent) maybeBuildParamsFromOutput(file string) (TestingBuildParams, []string) { | 
 | 	searchedOutputs := WritablePaths(nil) | 
 | 	for _, p := range b.provider.BuildParamsForTests() { | 
 | 		outputs := append(WritablePaths(nil), p.Outputs...) | 
 | 		outputs = append(outputs, p.ImplicitOutputs...) | 
 | 		if p.Output != nil { | 
 | 			outputs = append(outputs, p.Output) | 
 | 		} | 
 | 		for _, f := range outputs { | 
 | 			if f.String() == file || f.Rel() == file || PathRelativeToTop(f) == file { | 
 | 				return b.newTestingBuildParams(p), nil | 
 | 			} | 
 | 			searchedOutputs = append(searchedOutputs, f) | 
 | 		} | 
 | 	} | 
 |  | 
 | 	formattedOutputs := []string{} | 
 | 	for _, f := range searchedOutputs { | 
 | 		formattedOutputs = append(formattedOutputs, | 
 | 			fmt.Sprintf("%s (rel=%s)", PathRelativeToTop(f), f.Rel())) | 
 | 	} | 
 |  | 
 | 	return TestingBuildParams{}, formattedOutputs | 
 | } | 
 |  | 
 | func (b baseTestingComponent) buildParamsFromOutput(file string) TestingBuildParams { | 
 | 	p, searchedOutputs := b.maybeBuildParamsFromOutput(file) | 
 | 	if p.Rule == nil { | 
 | 		panic(fmt.Errorf("couldn't find output %q.\nall outputs:\n    %s\n", | 
 | 			file, strings.Join(searchedOutputs, "\n    "))) | 
 | 	} | 
 | 	return p | 
 | } | 
 |  | 
 | func (b baseTestingComponent) allOutputs() []string { | 
 | 	var outputFullPaths []string | 
 | 	for _, p := range b.provider.BuildParamsForTests() { | 
 | 		outputFullPaths = append(outputFullPaths, allOutputs(p)...) | 
 | 	} | 
 | 	return outputFullPaths | 
 | } | 
 |  | 
 | // MaybeRule finds a call to ctx.Build with BuildParams.Rule set to a rule with the given name.  Returns an empty | 
 | // BuildParams if no rule is found. | 
 | func (b baseTestingComponent) MaybeRule(rule string) TestingBuildParams { | 
 | 	r, _ := b.maybeBuildParamsFromRule(rule) | 
 | 	return r | 
 | } | 
 |  | 
 | // Rule finds a call to ctx.Build with BuildParams.Rule set to a rule with the given name.  Panics if no rule is found. | 
 | func (b baseTestingComponent) Rule(rule string) TestingBuildParams { | 
 | 	return b.buildParamsFromRule(rule) | 
 | } | 
 |  | 
 | // MaybeDescription finds a call to ctx.Build with BuildParams.Description set to a the given string.  Returns an empty | 
 | // BuildParams if no rule is found. | 
 | func (b baseTestingComponent) MaybeDescription(desc string) TestingBuildParams { | 
 | 	p, _ := b.maybeBuildParamsFromDescription(desc) | 
 | 	return p | 
 | } | 
 |  | 
 | // Description finds a call to ctx.Build with BuildParams.Description set to a the given string.  Panics if no rule is | 
 | // found. | 
 | func (b baseTestingComponent) Description(desc string) TestingBuildParams { | 
 | 	return b.buildParamsFromDescription(desc) | 
 | } | 
 |  | 
 | // MaybeOutput finds a call to ctx.Build with a BuildParams.Output or BuildParams.Outputs whose String() or Rel() | 
 | // value matches the provided string.  Returns an empty BuildParams if no rule is found. | 
 | func (b baseTestingComponent) MaybeOutput(file string) TestingBuildParams { | 
 | 	p, _ := b.maybeBuildParamsFromOutput(file) | 
 | 	return p | 
 | } | 
 |  | 
 | // Output finds a call to ctx.Build with a BuildParams.Output or BuildParams.Outputs whose String() or Rel() | 
 | // value matches the provided string.  Panics if no rule is found. | 
 | func (b baseTestingComponent) Output(file string) TestingBuildParams { | 
 | 	return b.buildParamsFromOutput(file) | 
 | } | 
 |  | 
 | // AllOutputs returns all 'BuildParams.Output's and 'BuildParams.Outputs's in their full path string forms. | 
 | func (b baseTestingComponent) AllOutputs() []string { | 
 | 	return b.allOutputs() | 
 | } | 
 |  | 
 | // TestingModule is wrapper around an android.Module that provides methods to find information about individual | 
 | // ctx.Build parameters for verification in tests. | 
 | type TestingModule struct { | 
 | 	baseTestingComponent | 
 | 	module Module | 
 | } | 
 |  | 
 | func newTestingModule(config Config, module Module) TestingModule { | 
 | 	return TestingModule{ | 
 | 		newBaseTestingComponent(config, module), | 
 | 		module, | 
 | 	} | 
 | } | 
 |  | 
 | // Module returns the Module wrapped by the TestingModule. | 
 | func (m TestingModule) Module() Module { | 
 | 	return m.module | 
 | } | 
 |  | 
 | // VariablesForTestsRelativeToTop returns a copy of the Module.VariablesForTests() with every value | 
 | // having any temporary build dir usages replaced with paths relative to a notional top. | 
 | func (m TestingModule) VariablesForTestsRelativeToTop() map[string]string { | 
 | 	return normalizeStringMapRelativeToTop(m.config, m.module.VariablesForTests()) | 
 | } | 
 |  | 
 | // OutputFiles checks if module base outputFiles property has any output | 
 | // files can be used to return. | 
 | // Exits the test immediately if there is an error and | 
 | // otherwise returns the result of calling Paths.RelativeToTop | 
 | // on the returned Paths. | 
 | func (m TestingModule) OutputFiles(ctx *TestContext, t *testing.T, tag string) Paths { | 
 | 	outputFiles := OtherModuleProviderOrDefault(ctx.OtherModuleProviderAdaptor(), m.Module(), OutputFilesProvider) | 
 | 	if tag == "" && outputFiles.DefaultOutputFiles != nil { | 
 | 		return outputFiles.DefaultOutputFiles.RelativeToTop() | 
 | 	} else if taggedOutputFiles, hasTag := outputFiles.TaggedOutputFiles[tag]; hasTag { | 
 | 		return taggedOutputFiles.RelativeToTop() | 
 | 	} | 
 |  | 
 | 	t.Fatal(fmt.Errorf("No test output file has been set for tag %q", tag)) | 
 | 	return nil | 
 | } | 
 |  | 
 | // TestingSingleton is wrapper around an android.Singleton that provides methods to find information about individual | 
 | // ctx.Build parameters for verification in tests. | 
 | type TestingSingleton struct { | 
 | 	baseTestingComponent | 
 | 	singleton Singleton | 
 | } | 
 |  | 
 | // Singleton returns the Singleton wrapped by the TestingSingleton. | 
 | func (s TestingSingleton) Singleton() Singleton { | 
 | 	return s.singleton | 
 | } | 
 |  | 
 | func FailIfErrored(t *testing.T, errs []error) { | 
 | 	t.Helper() | 
 | 	if len(errs) > 0 { | 
 | 		for _, err := range errs { | 
 | 			t.Error(err) | 
 | 		} | 
 | 		t.FailNow() | 
 | 	} | 
 | } | 
 |  | 
 | // Fail if no errors that matched the regular expression were found. | 
 | // | 
 | // Returns true if a matching error was found, false otherwise. | 
 | func FailIfNoMatchingErrors(t *testing.T, pattern string, errs []error) bool { | 
 | 	t.Helper() | 
 |  | 
 | 	matcher, err := regexp.Compile(pattern) | 
 | 	if err != nil { | 
 | 		t.Fatalf("failed to compile regular expression %q because %s", pattern, err) | 
 | 	} | 
 |  | 
 | 	found := false | 
 | 	for _, err := range errs { | 
 | 		if matcher.FindStringIndex(err.Error()) != nil { | 
 | 			found = true | 
 | 			break | 
 | 		} | 
 | 	} | 
 | 	if !found { | 
 | 		t.Errorf("could not match the expected error regex %q (checked %d error(s))", pattern, len(errs)) | 
 | 		for i, err := range errs { | 
 | 			t.Errorf("errs[%d] = %q", i, err) | 
 | 		} | 
 | 	} | 
 |  | 
 | 	return found | 
 | } | 
 |  | 
 | func CheckErrorsAgainstExpectations(t *testing.T, errs []error, expectedErrorPatterns []string) { | 
 | 	t.Helper() | 
 |  | 
 | 	if expectedErrorPatterns == nil { | 
 | 		FailIfErrored(t, errs) | 
 | 	} else { | 
 | 		for _, expectedError := range expectedErrorPatterns { | 
 | 			FailIfNoMatchingErrors(t, expectedError, errs) | 
 | 		} | 
 | 		if len(errs) > len(expectedErrorPatterns) { | 
 | 			t.Errorf("additional errors found, expected %d, found %d", | 
 | 				len(expectedErrorPatterns), len(errs)) | 
 | 			for i, expectedError := range expectedErrorPatterns { | 
 | 				t.Errorf("expectedErrors[%d] = %s", i, expectedError) | 
 | 			} | 
 | 			for i, err := range errs { | 
 | 				t.Errorf("errs[%d] = %s", i, err) | 
 | 			} | 
 | 			t.FailNow() | 
 | 		} | 
 | 	} | 
 | } | 
 |  | 
 | func SetKatiEnabledForTests(config Config) { | 
 | 	config.katiEnabled = true | 
 | } | 
 |  | 
 | func SetTrimmedApexEnabledForTests(config Config) { | 
 | 	config.productVariables.TrimmedApex = new(bool) | 
 | 	*config.productVariables.TrimmedApex = true | 
 | } | 
 |  | 
 | func AndroidMkEntriesForTest(t *testing.T, ctx *TestContext, mod blueprint.Module) []AndroidMkEntries { | 
 | 	t.Helper() | 
 | 	var p AndroidMkEntriesProvider | 
 | 	var ok bool | 
 | 	if p, ok = mod.(AndroidMkEntriesProvider); !ok { | 
 | 		t.Errorf("module does not implement AndroidMkEntriesProvider: " + mod.Name()) | 
 | 	} | 
 |  | 
 | 	entriesList := p.AndroidMkEntries() | 
 | 	aconfigUpdateAndroidMkEntries(ctx, mod.(Module), &entriesList) | 
 | 	for i := range entriesList { | 
 | 		entriesList[i].fillInEntries(ctx, mod) | 
 | 	} | 
 | 	return entriesList | 
 | } | 
 |  | 
 | func AndroidMkDataForTest(t *testing.T, ctx *TestContext, mod blueprint.Module) AndroidMkData { | 
 | 	t.Helper() | 
 | 	var p AndroidMkDataProvider | 
 | 	var ok bool | 
 | 	if p, ok = mod.(AndroidMkDataProvider); !ok { | 
 | 		t.Fatalf("module does not implement AndroidMkDataProvider: " + mod.Name()) | 
 | 	} | 
 | 	data := p.AndroidMk() | 
 | 	data.fillInData(ctx, mod) | 
 | 	aconfigUpdateAndroidMkData(ctx, mod.(Module), &data) | 
 | 	return data | 
 | } | 
 |  | 
 | // Normalize the path for testing. | 
 | // | 
 | // If the path is relative to the build directory then return the relative path | 
 | // to avoid tests having to deal with the dynamically generated build directory. | 
 | // | 
 | // Otherwise, return the supplied path as it is almost certainly a source path | 
 | // that is relative to the root of the source tree. | 
 | // | 
 | // The build and source paths should be distinguishable based on their contents. | 
 | // | 
 | // deprecated: use PathRelativeToTop instead as it handles make install paths and differentiates | 
 | // between output and source properly. | 
 | func NormalizePathForTesting(path Path) string { | 
 | 	if path == nil { | 
 | 		return "<nil path>" | 
 | 	} | 
 | 	p := path.String() | 
 | 	if w, ok := path.(WritablePath); ok { | 
 | 		rel, err := filepath.Rel(w.getSoongOutDir(), p) | 
 | 		if err != nil { | 
 | 			panic(err) | 
 | 		} | 
 | 		return rel | 
 | 	} | 
 | 	return p | 
 | } | 
 |  | 
 | // NormalizePathsForTesting creates a slice of strings where each string is the result of applying | 
 | // NormalizePathForTesting to the corresponding Path in the input slice. | 
 | // | 
 | // deprecated: use PathsRelativeToTop instead as it handles make install paths and differentiates | 
 | // between output and source properly. | 
 | func NormalizePathsForTesting(paths Paths) []string { | 
 | 	var result []string | 
 | 	for _, path := range paths { | 
 | 		relative := NormalizePathForTesting(path) | 
 | 		result = append(result, relative) | 
 | 	} | 
 | 	return result | 
 | } | 
 |  | 
 | // PathRelativeToTop returns a string representation of the path relative to a notional top | 
 | // directory. | 
 | // | 
 | // It return "<nil path>" if the supplied path is nil, otherwise it returns the result of calling | 
 | // Path.RelativeToTop to obtain a relative Path and then calling Path.String on that to get the | 
 | // string representation. | 
 | func PathRelativeToTop(path Path) string { | 
 | 	if path == nil { | 
 | 		return "<nil path>" | 
 | 	} | 
 | 	return path.RelativeToTop().String() | 
 | } | 
 |  | 
 | // PathsRelativeToTop creates a slice of strings where each string is the result of applying | 
 | // PathRelativeToTop to the corresponding Path in the input slice. | 
 | func PathsRelativeToTop(paths Paths) []string { | 
 | 	var result []string | 
 | 	for _, path := range paths { | 
 | 		relative := PathRelativeToTop(path) | 
 | 		result = append(result, relative) | 
 | 	} | 
 | 	return result | 
 | } | 
 |  | 
 | // StringPathRelativeToTop returns a string representation of the path relative to a notional top | 
 | // directory. | 
 | // | 
 | // See Path.RelativeToTop for more details as to what `relative to top` means. | 
 | // | 
 | // This is provided for processing paths that have already been converted into a string, e.g. paths | 
 | // in AndroidMkEntries structures. As a result it needs to be supplied the soong output dir against | 
 | // which it can try and relativize paths. PathRelativeToTop must be used for process Path objects. | 
 | func StringPathRelativeToTop(soongOutDir string, path string) string { | 
 | 	ensureTestOnly() | 
 |  | 
 | 	// A relative path must be a source path so leave it as it is. | 
 | 	if !filepath.IsAbs(path) { | 
 | 		return path | 
 | 	} | 
 |  | 
 | 	// Check to see if the path is relative to the soong out dir. | 
 | 	rel, isRel, err := maybeRelErr(soongOutDir, path) | 
 | 	if err != nil { | 
 | 		panic(err) | 
 | 	} | 
 |  | 
 | 	if isRel { | 
 | 		if strings.HasSuffix(soongOutDir, testOutSoongSubDir) { | 
 | 			// The path is in the soong out dir so indicate that in the relative path. | 
 | 			return filepath.Join(TestOutSoongDir, rel) | 
 | 		} else { | 
 | 			// Handle the PathForArbitraryOutput case | 
 | 			return filepath.Join(testOutDir, rel) | 
 |  | 
 | 		} | 
 | 	} | 
 |  | 
 | 	// Check to see if the path is relative to the top level out dir. | 
 | 	outDir := filepath.Dir(soongOutDir) | 
 | 	rel, isRel, err = maybeRelErr(outDir, path) | 
 | 	if err != nil { | 
 | 		panic(err) | 
 | 	} | 
 |  | 
 | 	if isRel { | 
 | 		// The path is in the out dir so indicate that in the relative path. | 
 | 		return filepath.Join("out", rel) | 
 | 	} | 
 |  | 
 | 	// This should never happen. | 
 | 	panic(fmt.Errorf("internal error: absolute path %s is not relative to the out dir %s", path, outDir)) | 
 | } | 
 |  | 
 | // StringPathsRelativeToTop creates a slice of strings where each string is the result of applying | 
 | // StringPathRelativeToTop to the corresponding string path in the input slice. | 
 | // | 
 | // This is provided for processing paths that have already been converted into a string, e.g. paths | 
 | // in AndroidMkEntries structures. As a result it needs to be supplied the soong output dir against | 
 | // which it can try and relativize paths. PathsRelativeToTop must be used for process Paths objects. | 
 | func StringPathsRelativeToTop(soongOutDir string, paths []string) []string { | 
 | 	var result []string | 
 | 	for _, path := range paths { | 
 | 		relative := StringPathRelativeToTop(soongOutDir, path) | 
 | 		result = append(result, relative) | 
 | 	} | 
 | 	return result | 
 | } | 
 |  | 
 | // StringRelativeToTop will normalize a string containing paths, e.g. ninja command, by replacing | 
 | // any references to the test specific temporary build directory that changes with each run to a | 
 | // fixed path relative to a notional top directory. | 
 | // | 
 | // This is similar to StringPathRelativeToTop except that assumes the string is a single path | 
 | // containing at most one instance of the temporary build directory at the start of the path while | 
 | // this assumes that there can be any number at any position. | 
 | func StringRelativeToTop(config Config, command string) string { | 
 | 	return normalizeStringRelativeToTop(config, command) | 
 | } | 
 |  | 
 | // StringsRelativeToTop will return a new slice such that each item in the new slice is the result | 
 | // of calling StringRelativeToTop on the corresponding item in the input slice. | 
 | func StringsRelativeToTop(config Config, command []string) []string { | 
 | 	return normalizeStringArrayRelativeToTop(config, command) | 
 | } | 
 |  | 
 | func EnsureListContainsSuffix(t *testing.T, result []string, expected string) { | 
 | 	t.Helper() | 
 | 	if !SuffixInList(result, expected) { | 
 | 		t.Errorf("%q is not found in %v", expected, result) | 
 | 	} | 
 | } | 
 |  | 
 | type panickingConfigAndErrorContext struct { | 
 | 	ctx *TestContext | 
 | } | 
 |  | 
 | func (ctx *panickingConfigAndErrorContext) OtherModulePropertyErrorf(module Module, property, fmt string, args ...interface{}) { | 
 | 	panic(ctx.ctx.PropertyErrorf(module, property, fmt, args...).Error()) | 
 | } | 
 |  | 
 | func (ctx *panickingConfigAndErrorContext) Config() Config { | 
 | 	return ctx.ctx.Config() | 
 | } | 
 |  | 
 | func PanickingConfigAndErrorContext(ctx *TestContext) ConfigAndErrorContext { | 
 | 	return &panickingConfigAndErrorContext{ | 
 | 		ctx: ctx, | 
 | 	} | 
 | } |