|  | // 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 ( | 
|  | "path/filepath" | 
|  | "reflect" | 
|  | "testing" | 
|  |  | 
|  | "github.com/google/blueprint" | 
|  | ) | 
|  |  | 
|  | func TestDependingOnModuleInSameNamespace(t *testing.T) { | 
|  | result := GroupFixturePreparers( | 
|  | prepareForTestWithNamespace, | 
|  | dirBpToPreparer(map[string]string{ | 
|  | "dir1": ` | 
|  | soong_namespace { | 
|  | } | 
|  | test_module { | 
|  | name: "a", | 
|  | } | 
|  | test_module { | 
|  | name: "b", | 
|  | deps: ["a"], | 
|  | } | 
|  | `, | 
|  | }), | 
|  | ).RunTest(t) | 
|  |  | 
|  | a := getModule(result, "a") | 
|  | b := getModule(result, "b") | 
|  | if !dependsOn(result, b, a) { | 
|  | t.Errorf("module b does not depend on module a in the same namespace") | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestDependingOnModuleInRootNamespace(t *testing.T) { | 
|  | result := GroupFixturePreparers( | 
|  | prepareForTestWithNamespace, | 
|  | dirBpToPreparer(map[string]string{ | 
|  | ".": ` | 
|  | test_module { | 
|  | name: "b", | 
|  | deps: ["a"], | 
|  | } | 
|  | test_module { | 
|  | name: "a", | 
|  | } | 
|  | `, | 
|  | }), | 
|  | ).RunTest(t) | 
|  |  | 
|  | a := getModule(result, "a") | 
|  | b := getModule(result, "b") | 
|  | if !dependsOn(result, b, a) { | 
|  | t.Errorf("module b in root namespace does not depend on module a in the root namespace") | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestImplicitlyImportRootNamespace(t *testing.T) { | 
|  | GroupFixturePreparers( | 
|  | prepareForTestWithNamespace, | 
|  | dirBpToPreparer(map[string]string{ | 
|  | ".": ` | 
|  | test_module { | 
|  | name: "a", | 
|  | } | 
|  | `, | 
|  | "dir1": ` | 
|  | soong_namespace { | 
|  | } | 
|  | test_module { | 
|  | name: "b", | 
|  | deps: ["a"], | 
|  | } | 
|  | `, | 
|  | }), | 
|  | ).RunTest(t) | 
|  |  | 
|  | // RunTest will report any errors | 
|  | } | 
|  |  | 
|  | func TestDependingOnBlueprintModuleInRootNamespace(t *testing.T) { | 
|  | GroupFixturePreparers( | 
|  | prepareForTestWithNamespace, | 
|  | dirBpToPreparer(map[string]string{ | 
|  | ".": ` | 
|  | blueprint_test_module { | 
|  | name: "a", | 
|  | } | 
|  | `, | 
|  | "dir1": ` | 
|  | soong_namespace { | 
|  | } | 
|  | blueprint_test_module { | 
|  | name: "b", | 
|  | deps: ["a"], | 
|  | } | 
|  | `, | 
|  | }), | 
|  | ).RunTest(t) | 
|  |  | 
|  | // RunTest will report any errors | 
|  | } | 
|  |  | 
|  | func TestDependingOnModuleInImportedNamespace(t *testing.T) { | 
|  | result := GroupFixturePreparers( | 
|  | prepareForTestWithNamespace, | 
|  | dirBpToPreparer(map[string]string{ | 
|  | "dir1": ` | 
|  | soong_namespace { | 
|  | } | 
|  | test_module { | 
|  | name: "a", | 
|  | } | 
|  | `, | 
|  | "dir2": ` | 
|  | soong_namespace { | 
|  | imports: ["dir1"], | 
|  | } | 
|  | test_module { | 
|  | name: "b", | 
|  | deps: ["a"], | 
|  | } | 
|  | `, | 
|  | }), | 
|  | ).RunTest(t) | 
|  |  | 
|  | a := getModule(result, "a") | 
|  | b := getModule(result, "b") | 
|  | if !dependsOn(result, b, a) { | 
|  | t.Errorf("module b does not depend on module a in the same namespace") | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestDependingOnModuleInNonImportedNamespace(t *testing.T) { | 
|  | GroupFixturePreparers( | 
|  | prepareForTestWithNamespace, | 
|  | dirBpToPreparer(map[string]string{ | 
|  | "dir1": ` | 
|  | soong_namespace { | 
|  | } | 
|  | test_module { | 
|  | name: "a", | 
|  | } | 
|  | `, | 
|  | "dir2": ` | 
|  | soong_namespace { | 
|  | } | 
|  | test_module { | 
|  | name: "a", | 
|  | } | 
|  | `, | 
|  | "dir3": ` | 
|  | soong_namespace { | 
|  | } | 
|  | test_module { | 
|  | name: "b", | 
|  | deps: ["a"], | 
|  | } | 
|  | `, | 
|  | }), | 
|  | ). | 
|  | ExtendWithErrorHandler(FixtureExpectsOneErrorPattern(`\Qdir3/Android.bp:4:5: "b" depends on undefined module "a". | 
|  | Module "b" is defined in namespace "dir3" which can read these 2 namespaces: ["dir3" "."] | 
|  | Module "a" can be found in these namespaces: ["dir1" "dir2"]\E | 
|  | Or did you mean ["soong_namespace"]?`)). | 
|  | RunTest(t) | 
|  | } | 
|  |  | 
|  | func TestDependingOnModuleByFullyQualifiedReference(t *testing.T) { | 
|  | result := GroupFixturePreparers( | 
|  | prepareForTestWithNamespace, | 
|  | dirBpToPreparer(map[string]string{ | 
|  | "dir1": ` | 
|  | soong_namespace { | 
|  | } | 
|  | test_module { | 
|  | name: "a", | 
|  | } | 
|  | `, | 
|  | "dir2": ` | 
|  | soong_namespace { | 
|  | } | 
|  | test_module { | 
|  | name: "b", | 
|  | deps: ["//dir1:a"], | 
|  | } | 
|  | `, | 
|  | }), | 
|  | ).RunTest(t) | 
|  |  | 
|  | a := getModule(result, "a") | 
|  | b := getModule(result, "b") | 
|  | if !dependsOn(result, b, a) { | 
|  | t.Errorf("module b does not depend on module a") | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestSameNameInTwoNamespaces(t *testing.T) { | 
|  | result := GroupFixturePreparers( | 
|  | prepareForTestWithNamespace, | 
|  | dirBpToPreparer(map[string]string{ | 
|  | "dir1": ` | 
|  | soong_namespace { | 
|  | } | 
|  | test_module { | 
|  | name: "a", | 
|  | id: "1", | 
|  | } | 
|  | test_module { | 
|  | name: "b", | 
|  | deps: ["a"], | 
|  | id: "2", | 
|  | } | 
|  | `, | 
|  | "dir2": ` | 
|  | soong_namespace { | 
|  | } | 
|  | test_module { | 
|  | name: "a", | 
|  | id:"3", | 
|  | } | 
|  | test_module { | 
|  | name: "b", | 
|  | deps: ["a"], | 
|  | id:"4", | 
|  | } | 
|  | `, | 
|  | }), | 
|  | ).RunTest(t) | 
|  |  | 
|  | one := findModuleById(result, "1") | 
|  | two := findModuleById(result, "2") | 
|  | three := findModuleById(result, "3") | 
|  | four := findModuleById(result, "4") | 
|  | if !dependsOn(result, two, one) { | 
|  | t.Fatalf("Module 2 does not depend on module 1 in its namespace") | 
|  | } | 
|  | if dependsOn(result, two, three) { | 
|  | t.Fatalf("Module 2 depends on module 3 in another namespace") | 
|  | } | 
|  | if !dependsOn(result, four, three) { | 
|  | t.Fatalf("Module 4 does not depend on module 3 in its namespace") | 
|  | } | 
|  | if dependsOn(result, four, one) { | 
|  | t.Fatalf("Module 4 depends on module 1 in another namespace") | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestSearchOrder(t *testing.T) { | 
|  | result := GroupFixturePreparers( | 
|  | prepareForTestWithNamespace, | 
|  | dirBpToPreparer(map[string]string{ | 
|  | "dir1": ` | 
|  | soong_namespace { | 
|  | } | 
|  | test_module { | 
|  | name: "a", | 
|  | id: "1", | 
|  | } | 
|  | `, | 
|  | "dir2": ` | 
|  | soong_namespace { | 
|  | } | 
|  | test_module { | 
|  | name: "a", | 
|  | id:"2", | 
|  | } | 
|  | test_module { | 
|  | name: "b", | 
|  | id:"3", | 
|  | } | 
|  | `, | 
|  | "dir3": ` | 
|  | soong_namespace { | 
|  | } | 
|  | test_module { | 
|  | name: "a", | 
|  | id:"4", | 
|  | } | 
|  | test_module { | 
|  | name: "b", | 
|  | id:"5", | 
|  | } | 
|  | test_module { | 
|  | name: "c", | 
|  | id:"6", | 
|  | } | 
|  | `, | 
|  | ".": ` | 
|  | test_module { | 
|  | name: "a", | 
|  | id: "7", | 
|  | } | 
|  | test_module { | 
|  | name: "b", | 
|  | id: "8", | 
|  | } | 
|  | test_module { | 
|  | name: "c", | 
|  | id: "9", | 
|  | } | 
|  | test_module { | 
|  | name: "d", | 
|  | id: "10", | 
|  | } | 
|  | `, | 
|  | "dir4": ` | 
|  | soong_namespace { | 
|  | imports: ["dir1", "dir2", "dir3"] | 
|  | } | 
|  | test_module { | 
|  | name: "test_me", | 
|  | id:"0", | 
|  | deps: ["a", "b", "c", "d"], | 
|  | } | 
|  | `, | 
|  | }), | 
|  | ).RunTest(t) | 
|  |  | 
|  | testMe := findModuleById(result, "0") | 
|  | if !dependsOn(result, testMe, findModuleById(result, "1")) { | 
|  | t.Errorf("test_me doesn't depend on id 1") | 
|  | } | 
|  | if !dependsOn(result, testMe, findModuleById(result, "3")) { | 
|  | t.Errorf("test_me doesn't depend on id 3") | 
|  | } | 
|  | if !dependsOn(result, testMe, findModuleById(result, "6")) { | 
|  | t.Errorf("test_me doesn't depend on id 6") | 
|  | } | 
|  | if !dependsOn(result, testMe, findModuleById(result, "10")) { | 
|  | t.Errorf("test_me doesn't depend on id 10") | 
|  | } | 
|  | if numDeps(result, testMe) != 4 { | 
|  | t.Errorf("num dependencies of test_me = %v, not 4\n", numDeps(result, testMe)) | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestTwoNamespacesCanImportEachOther(t *testing.T) { | 
|  | GroupFixturePreparers( | 
|  | prepareForTestWithNamespace, | 
|  | dirBpToPreparer(map[string]string{ | 
|  | "dir1": ` | 
|  | soong_namespace { | 
|  | imports: ["dir2"] | 
|  | } | 
|  | test_module { | 
|  | name: "a", | 
|  | } | 
|  | test_module { | 
|  | name: "c", | 
|  | deps: ["b"], | 
|  | } | 
|  | `, | 
|  | "dir2": ` | 
|  | soong_namespace { | 
|  | imports: ["dir1"], | 
|  | } | 
|  | test_module { | 
|  | name: "b", | 
|  | deps: ["a"], | 
|  | } | 
|  | `, | 
|  | }), | 
|  | ).RunTest(t) | 
|  |  | 
|  | // RunTest will report any errors | 
|  | } | 
|  |  | 
|  | func TestImportingNonexistentNamespace(t *testing.T) { | 
|  | GroupFixturePreparers( | 
|  | prepareForTestWithNamespace, | 
|  | dirBpToPreparer(map[string]string{ | 
|  | "dir1": ` | 
|  | soong_namespace { | 
|  | imports: ["a_nonexistent_namespace"] | 
|  | } | 
|  | test_module { | 
|  | name: "a", | 
|  | deps: ["a_nonexistent_module"] | 
|  | } | 
|  | `, | 
|  | }), | 
|  | ). | 
|  | // should complain about the missing namespace and not complain about the unresolvable dependency | 
|  | ExtendWithErrorHandler(FixtureExpectsOneErrorPattern(`\Qdir1/Android.bp:2:5: module "soong_namespace": namespace a_nonexistent_namespace does not exist\E`)). | 
|  | RunTest(t) | 
|  | } | 
|  |  | 
|  | func TestNamespacesDontInheritParentNamespaces(t *testing.T) { | 
|  | GroupFixturePreparers( | 
|  | prepareForTestWithNamespace, | 
|  | dirBpToPreparer(map[string]string{ | 
|  | "dir1": ` | 
|  | soong_namespace { | 
|  | } | 
|  | test_module { | 
|  | name: "a", | 
|  | } | 
|  | `, | 
|  | "dir1/subdir1": ` | 
|  | soong_namespace { | 
|  | } | 
|  | test_module { | 
|  | name: "b", | 
|  | deps: ["a"], | 
|  | } | 
|  | `, | 
|  | }), | 
|  | ). | 
|  | ExtendWithErrorHandler(FixtureExpectsOneErrorPattern(`\Qdir1/subdir1/Android.bp:4:5: "b" depends on undefined module "a". | 
|  | Module "b" is defined in namespace "dir1/subdir1" which can read these 2 namespaces: ["dir1/subdir1" "."] | 
|  | Module "a" can be found in these namespaces: ["dir1"]\E | 
|  | Or did you mean ["soong_namespace"]?`)). | 
|  | RunTest(t) | 
|  | } | 
|  |  | 
|  | func TestModulesDoReceiveParentNamespace(t *testing.T) { | 
|  | GroupFixturePreparers( | 
|  | prepareForTestWithNamespace, | 
|  | dirBpToPreparer(map[string]string{ | 
|  | "dir1": ` | 
|  | soong_namespace { | 
|  | } | 
|  | test_module { | 
|  | name: "a", | 
|  | } | 
|  | `, | 
|  | "dir1/subdir": ` | 
|  | test_module { | 
|  | name: "b", | 
|  | deps: ["a"], | 
|  | } | 
|  | `, | 
|  | }), | 
|  | ).RunTest(t) | 
|  |  | 
|  | // RunTest will report any errors | 
|  | } | 
|  |  | 
|  | func TestNamespaceImportsNotTransitive(t *testing.T) { | 
|  | GroupFixturePreparers( | 
|  | prepareForTestWithNamespace, | 
|  | dirBpToPreparer(map[string]string{ | 
|  | "dir1": ` | 
|  | soong_namespace { | 
|  | } | 
|  | test_module { | 
|  | name: "a", | 
|  | } | 
|  | `, | 
|  | "dir2": ` | 
|  | soong_namespace { | 
|  | imports: ["dir1"], | 
|  | } | 
|  | test_module { | 
|  | name: "b", | 
|  | deps: ["a"], | 
|  | } | 
|  | `, | 
|  | "dir3": ` | 
|  | soong_namespace { | 
|  | imports: ["dir2"], | 
|  | } | 
|  | test_module { | 
|  | name: "c", | 
|  | deps: ["a"], | 
|  | } | 
|  | `, | 
|  | }), | 
|  | ). | 
|  | ExtendWithErrorHandler(FixtureExpectsOneErrorPattern(`\Qdir3/Android.bp:5:5: "c" depends on undefined module "a". | 
|  | Module "c" is defined in namespace "dir3" which can read these 3 namespaces: ["dir3" "dir2" "."] | 
|  | Module "a" can be found in these namespaces: ["dir1"]\E | 
|  | Or did you mean ["b"]?`)). | 
|  | RunTest(t) | 
|  | } | 
|  |  | 
|  | func TestTwoNamepacesInSameDir(t *testing.T) { | 
|  | GroupFixturePreparers( | 
|  | prepareForTestWithNamespace, | 
|  | dirBpToPreparer(map[string]string{ | 
|  | "dir1": ` | 
|  | soong_namespace { | 
|  | } | 
|  | soong_namespace { | 
|  | } | 
|  | `, | 
|  | }), | 
|  | ). | 
|  | ExtendWithErrorHandler(FixtureExpectsOneErrorPattern(`\Qdir1/Android.bp:4:5: namespace dir1 already exists\E`)). | 
|  | RunTest(t) | 
|  | } | 
|  |  | 
|  | func TestNamespaceNotAtTopOfFile(t *testing.T) { | 
|  | GroupFixturePreparers( | 
|  | prepareForTestWithNamespace, | 
|  | dirBpToPreparer(map[string]string{ | 
|  | "dir1": ` | 
|  | test_module { | 
|  | name: "a" | 
|  | } | 
|  | soong_namespace { | 
|  | } | 
|  | `, | 
|  | }), | 
|  | ). | 
|  | ExtendWithErrorHandler(FixtureExpectsOneErrorPattern(`\Qdir1/Android.bp:5:5: a namespace must be the first module in the file\E`)). | 
|  | RunTest(t) | 
|  | } | 
|  |  | 
|  | func TestTwoModulesWithSameNameInSameNamespace(t *testing.T) { | 
|  | GroupFixturePreparers( | 
|  | prepareForTestWithNamespace, | 
|  | dirBpToPreparer(map[string]string{ | 
|  | "dir1": ` | 
|  | soong_namespace { | 
|  | } | 
|  | test_module { | 
|  | name: "a" | 
|  | } | 
|  | test_module { | 
|  | name: "a" | 
|  | } | 
|  | `, | 
|  | }), | 
|  | ). | 
|  | ExtendWithErrorHandler(FixtureExpectsOneErrorPattern(`\Qdir1/Android.bp:7:5: module "a" already defined | 
|  | dir1/Android.bp:4:5 <-- previous definition here\E`)). | 
|  | RunTest(t) | 
|  | } | 
|  |  | 
|  | func TestDeclaringNamespaceInNonAndroidBpFile(t *testing.T) { | 
|  | GroupFixturePreparers( | 
|  | prepareForTestWithNamespace, | 
|  | FixtureWithRootAndroidBp(` | 
|  | build = ["include.bp"] | 
|  | `), | 
|  | FixtureAddTextFile("include.bp", ` | 
|  | soong_namespace { | 
|  | } | 
|  | `), | 
|  | ). | 
|  | ExtendWithErrorHandler(FixtureExpectsOneErrorPattern( | 
|  | `\Qinclude.bp:2:5: A namespace may only be declared in a file named Android.bp\E`, | 
|  | )). | 
|  | RunTest(t) | 
|  | } | 
|  |  | 
|  | // so that the generated .ninja file will have consistent names | 
|  | func TestConsistentNamespaceNames(t *testing.T) { | 
|  | result := GroupFixturePreparers( | 
|  | prepareForTestWithNamespace, | 
|  | dirBpToPreparer(map[string]string{ | 
|  | "dir1": "soong_namespace{}", | 
|  | "dir2": "soong_namespace{}", | 
|  | "dir3": "soong_namespace{}", | 
|  | }), | 
|  | ).RunTest(t) | 
|  |  | 
|  | ns1, _ := result.NameResolver.namespaceAt("dir1") | 
|  | ns2, _ := result.NameResolver.namespaceAt("dir2") | 
|  | ns3, _ := result.NameResolver.namespaceAt("dir3") | 
|  | actualIds := []string{ns1.id, ns2.id, ns3.id} | 
|  | expectedIds := []string{"1", "2", "3"} | 
|  | if !reflect.DeepEqual(actualIds, expectedIds) { | 
|  | t.Errorf("Incorrect namespace ids.\nactual: %s\nexpected: %s\n", actualIds, expectedIds) | 
|  | } | 
|  | } | 
|  |  | 
|  | // so that the generated .ninja file will have consistent names | 
|  | func TestRename(t *testing.T) { | 
|  | GroupFixturePreparers( | 
|  | prepareForTestWithNamespace, | 
|  | dirBpToPreparer(map[string]string{ | 
|  | "dir1": ` | 
|  | soong_namespace { | 
|  | } | 
|  | test_module { | 
|  | name: "a", | 
|  | deps: ["c"], | 
|  | } | 
|  | test_module { | 
|  | name: "b", | 
|  | rename: "c", | 
|  | } | 
|  | `, | 
|  | }), | 
|  | ).RunTest(t) | 
|  |  | 
|  | // RunTest will report any errors | 
|  | } | 
|  |  | 
|  | func TestNamespace_Exports(t *testing.T) { | 
|  | result := GroupFixturePreparers( | 
|  | prepareForTestWithNamespace, | 
|  | FixtureModifyProductVariables(func(variables FixtureProductVariables) { | 
|  | variables.NamespacesToExport = []string{"dir1"} | 
|  | }), | 
|  | dirBpToPreparer(map[string]string{ | 
|  | "dir1": ` | 
|  | soong_namespace { | 
|  | } | 
|  | test_module { | 
|  | name: "a", | 
|  | } | 
|  | `, | 
|  | "dir2": ` | 
|  | soong_namespace { | 
|  | } | 
|  | test_module { | 
|  | name: "b", | 
|  | } | 
|  | `, | 
|  | }), | 
|  | ).RunTest(t) | 
|  |  | 
|  | aModule := result.Module("a", "") | 
|  | AssertBoolEquals(t, "a exported", true, aModule.ExportedToMake()) | 
|  | bModule := result.Module("b", "") | 
|  | AssertBoolEquals(t, "b not exported", false, bModule.ExportedToMake()) | 
|  | } | 
|  |  | 
|  | // some utils to support the tests | 
|  |  | 
|  | var prepareForTestWithNamespace = GroupFixturePreparers( | 
|  | FixtureRegisterWithContext(registerNamespaceBuildComponents), | 
|  | FixtureRegisterWithContext(func(ctx RegistrationContext) { | 
|  | ctx.PreArchMutators(RegisterNamespaceMutator) | 
|  | }), | 
|  | FixtureModifyContext(func(ctx *TestContext) { | 
|  | ctx.RegisterModuleType("test_module", newTestModule) | 
|  | ctx.Context.RegisterModuleType("blueprint_test_module", newBlueprintTestModule) | 
|  | ctx.PreDepsMutators(func(ctx RegisterMutatorsContext) { | 
|  | ctx.BottomUp("rename", renameMutator) | 
|  | }) | 
|  | }), | 
|  | ) | 
|  |  | 
|  | // dirBpToPreparer takes a map from directory to the contents of the Android.bp file and produces a | 
|  | // FixturePreparer. | 
|  | func dirBpToPreparer(bps map[string]string) FixturePreparer { | 
|  | files := make(MockFS, len(bps)) | 
|  | files["Android.bp"] = []byte("") | 
|  | for dir, text := range bps { | 
|  | files[filepath.Join(dir, "Android.bp")] = []byte(text) | 
|  | } | 
|  | return files.AddToFixture() | 
|  | } | 
|  |  | 
|  | func dependsOn(result *TestResult, module TestingModule, possibleDependency TestingModule) bool { | 
|  | depends := false | 
|  | visit := func(dependency blueprint.Module) { | 
|  | if dependency == possibleDependency.module { | 
|  | depends = true | 
|  | } | 
|  | } | 
|  | result.VisitDirectDeps(module.module, visit) | 
|  | return depends | 
|  | } | 
|  |  | 
|  | func numDeps(result *TestResult, module TestingModule) int { | 
|  | count := 0 | 
|  | visit := func(dependency blueprint.Module) { | 
|  | count++ | 
|  | } | 
|  | result.VisitDirectDeps(module.module, visit) | 
|  | return count | 
|  | } | 
|  |  | 
|  | func getModule(result *TestResult, moduleName string) TestingModule { | 
|  | return result.ModuleForTests(moduleName, "") | 
|  | } | 
|  |  | 
|  | func findModuleById(result *TestResult, id string) (module TestingModule) { | 
|  | visit := func(candidate blueprint.Module) { | 
|  | testModule, ok := candidate.(*testModule) | 
|  | if ok { | 
|  | if testModule.properties.Id == id { | 
|  | module = newTestingModule(result.config, testModule) | 
|  | } | 
|  | } | 
|  | } | 
|  | result.VisitAllModules(visit) | 
|  | return module | 
|  | } | 
|  |  | 
|  | type testModule struct { | 
|  | ModuleBase | 
|  | properties struct { | 
|  | Rename string | 
|  | Deps   []string | 
|  | Id     string | 
|  | } | 
|  | } | 
|  |  | 
|  | func (m *testModule) DepsMutator(ctx BottomUpMutatorContext) { | 
|  | if m.properties.Rename != "" { | 
|  | ctx.Rename(m.properties.Rename) | 
|  | } | 
|  | for _, d := range m.properties.Deps { | 
|  | ctx.AddDependency(ctx.Module(), nil, d) | 
|  | } | 
|  | } | 
|  |  | 
|  | func (m *testModule) GenerateAndroidBuildActions(ModuleContext) { | 
|  | } | 
|  |  | 
|  | func renameMutator(ctx BottomUpMutatorContext) { | 
|  | if m, ok := ctx.Module().(*testModule); ok { | 
|  | if m.properties.Rename != "" { | 
|  | ctx.Rename(m.properties.Rename) | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | func newTestModule() Module { | 
|  | m := &testModule{} | 
|  | m.AddProperties(&m.properties) | 
|  | InitAndroidModule(m) | 
|  | return m | 
|  | } | 
|  |  | 
|  | type blueprintTestModule struct { | 
|  | blueprint.SimpleName | 
|  | properties struct { | 
|  | Deps []string | 
|  | } | 
|  | } | 
|  |  | 
|  | func (b *blueprintTestModule) DynamicDependencies(_ blueprint.DynamicDependerModuleContext) []string { | 
|  | return b.properties.Deps | 
|  | } | 
|  |  | 
|  | func (b *blueprintTestModule) GenerateBuildActions(blueprint.ModuleContext) { | 
|  | } | 
|  |  | 
|  | func newBlueprintTestModule() (blueprint.Module, []interface{}) { | 
|  | m := &blueprintTestModule{} | 
|  | return m, []interface{}{&m.properties, &m.SimpleName.Properties} | 
|  | } |