Use a minimal set of mutators, module types, and singletons for tests

Calling android.NewContext() in tests results in a context that
contains all the mutators, module types, and singletons, which
causes unexpected interactions in unit tests.  Create an empty
context instead, and add in only the necessary mutators, module
types, and singletons.

Bug: 36366816
Test: soong tests
Change-Id: Ic61262c37e3436b3ad4ccaca18b737021c304be6
diff --git a/android/mutator.go b/android/mutator.go
index 3420280..940b0ff 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -14,7 +14,11 @@
 
 package android
 
-import "github.com/google/blueprint"
+import (
+	"sync"
+
+	"github.com/google/blueprint"
+)
 
 // Mutator phases:
 //   Pre-arch
@@ -23,36 +27,68 @@
 //   Deps
 //   PostDeps
 
-func registerMutators() {
-	ctx := registerMutatorsContext{}
+var registerMutatorsOnce sync.Once
+var registeredMutators []*mutator
 
-	register := func(funcs []RegisterMutatorFunc) {
-		for _, f := range funcs {
-			f(ctx)
+func registerMutatorsToContext(ctx *blueprint.Context, mutators []*mutator) {
+	for _, t := range mutators {
+		var handle blueprint.MutatorHandle
+		if t.bottomUpMutator != nil {
+			handle = ctx.RegisterBottomUpMutator(t.name, t.bottomUpMutator)
+		} else if t.topDownMutator != nil {
+			handle = ctx.RegisterTopDownMutator(t.name, t.topDownMutator)
+		}
+		if t.parallel {
+			handle.Parallel()
 		}
 	}
-
-	ctx.TopDown("load_hooks", loadHookMutator).Parallel()
-	ctx.BottomUp("prebuilts", prebuiltMutator).Parallel()
-	ctx.BottomUp("defaults_deps", defaultsDepsMutator).Parallel()
-	ctx.TopDown("defaults", defaultsMutator).Parallel()
-
-	register(preArch)
-
-	ctx.BottomUp("arch", archMutator).Parallel()
-	ctx.TopDown("arch_hooks", archHookMutator).Parallel()
-
-	register(preDeps)
-
-	ctx.BottomUp("deps", depsMutator).Parallel()
-
-	ctx.TopDown("prebuilt_select", PrebuiltSelectModuleMutator).Parallel()
-	ctx.BottomUp("prebuilt_replace", PrebuiltReplaceMutator).Parallel()
-
-	register(postDeps)
 }
 
-type registerMutatorsContext struct{}
+func registerMutators(ctx *blueprint.Context) {
+
+	registerMutatorsOnce.Do(func() {
+		ctx := &registerMutatorsContext{}
+
+		register := func(funcs []RegisterMutatorFunc) {
+			for _, f := range funcs {
+				f(ctx)
+			}
+		}
+
+		ctx.TopDown("load_hooks", loadHookMutator).Parallel()
+		ctx.BottomUp("prebuilts", prebuiltMutator).Parallel()
+		ctx.BottomUp("defaults_deps", defaultsDepsMutator).Parallel()
+		ctx.TopDown("defaults", defaultsMutator).Parallel()
+
+		register(preArch)
+
+		ctx.BottomUp("arch", archMutator).Parallel()
+		ctx.TopDown("arch_hooks", archHookMutator).Parallel()
+
+		register(preDeps)
+
+		ctx.BottomUp("deps", depsMutator).Parallel()
+
+		ctx.TopDown("prebuilt_select", PrebuiltSelectModuleMutator).Parallel()
+		ctx.BottomUp("prebuilt_replace", PrebuiltReplaceMutator).Parallel()
+
+		register(postDeps)
+
+		registeredMutators = ctx.mutators
+	})
+
+	registerMutatorsToContext(ctx, registeredMutators)
+}
+
+func RegisterTestMutators(ctx *blueprint.Context) {
+	mutators := registerMutatorsContext{}
+	mutators.BottomUp("deps", depsMutator).Parallel()
+	registerMutatorsToContext(ctx, mutators.mutators)
+}
+
+type registerMutatorsContext struct {
+	mutators []*mutator
+}
 
 type RegisterMutatorsContext interface {
 	TopDown(name string, m AndroidTopDownMutator) MutatorHandle
@@ -99,7 +135,7 @@
 	androidBaseContextImpl
 }
 
-func (registerMutatorsContext) BottomUp(name string, m AndroidBottomUpMutator) MutatorHandle {
+func (x *registerMutatorsContext) BottomUp(name string, m AndroidBottomUpMutator) MutatorHandle {
 	f := func(ctx blueprint.BottomUpMutatorContext) {
 		if a, ok := ctx.Module().(Module); ok {
 			actx := &androidBottomUpMutatorContext{
@@ -110,11 +146,11 @@
 		}
 	}
 	mutator := &mutator{name: name, bottomUpMutator: f}
-	mutators = append(mutators, mutator)
+	x.mutators = append(x.mutators, mutator)
 	return mutator
 }
 
-func (registerMutatorsContext) TopDown(name string, m AndroidTopDownMutator) MutatorHandle {
+func (x *registerMutatorsContext) TopDown(name string, m AndroidTopDownMutator) MutatorHandle {
 	f := func(ctx blueprint.TopDownMutatorContext) {
 		if a, ok := ctx.Module().(Module); ok {
 			actx := &androidTopDownMutatorContext{
@@ -125,7 +161,7 @@
 		}
 	}
 	mutator := &mutator{name: name, topDownMutator: f}
-	mutators = append(mutators, mutator)
+	x.mutators = append(x.mutators, mutator)
 	return mutator
 }
 
diff --git a/android/register.go b/android/register.go
index d6b290d..9396664 100644
--- a/android/register.go
+++ b/android/register.go
@@ -15,8 +15,6 @@
 package android
 
 import (
-	"sync"
-
 	"github.com/google/blueprint"
 )
 
@@ -51,8 +49,6 @@
 	singletons = append(singletons, singleton{name, factory})
 }
 
-var registerMutatorsOnce sync.Once
-
 func NewContext() *blueprint.Context {
 	ctx := blueprint.NewContext()
 
@@ -64,19 +60,8 @@
 		ctx.RegisterSingletonType(t.name, t.factory)
 	}
 
-	registerMutatorsOnce.Do(registerMutators)
+	registerMutators(ctx)
 
-	for _, t := range mutators {
-		var handle blueprint.MutatorHandle
-		if t.bottomUpMutator != nil {
-			handle = ctx.RegisterBottomUpMutator(t.name, t.bottomUpMutator)
-		} else if t.topDownMutator != nil {
-			handle = ctx.RegisterTopDownMutator(t.name, t.topDownMutator)
-		}
-		if t.parallel {
-			handle.Parallel()
-		}
-	}
 	ctx.RegisterSingletonType("env", EnvSingleton)
 
 	return ctx
diff --git a/cc/test_data_test.go b/cc/test_data_test.go
index e3b1214..9b5a85a 100644
--- a/cc/test_data_test.go
+++ b/cc/test_data_test.go
@@ -22,6 +22,8 @@
 	"testing"
 
 	"android/soong/android"
+	"android/soong/genrule"
+
 	"github.com/google/blueprint"
 )
 
@@ -121,13 +123,15 @@
 
 	for _, test := range testDataTests {
 		t.Run(test.name, func(t *testing.T) {
-			ctx := android.NewContext()
+			ctx := blueprint.NewContext()
+			android.RegisterTestMutators(ctx)
 			ctx.MockFileSystem(map[string][]byte{
 				"Blueprints":     []byte(`subdirs = ["dir"]`),
 				"dir/Blueprints": []byte(test.modules),
 				"dir/baz":        nil,
 				"dir/bar/baz":    nil,
 			})
+			ctx.RegisterModuleType("filegroup", genrule.FileGroupFactory)
 			ctx.RegisterModuleType("test", newTest)
 
 			_, errs := ctx.ParseBlueprintsFiles("Blueprints")
diff --git a/genrule/filegroup.go b/genrule/filegroup.go
index c1d08a8..71c5439 100644
--- a/genrule/filegroup.go
+++ b/genrule/filegroup.go
@@ -21,7 +21,7 @@
 )
 
 func init() {
-	android.RegisterModuleType("filegroup", fileGroupFactory)
+	android.RegisterModuleType("filegroup", FileGroupFactory)
 }
 
 type fileGroupProperties struct {
@@ -48,7 +48,7 @@
 // filegroup modules contain a list of files, and can be used to export files across package
 // boundaries.  filegroups (and genrules) can be referenced from srcs properties of other modules
 // using the syntax ":module".
-func fileGroupFactory() (blueprint.Module, []interface{}) {
+func FileGroupFactory() (blueprint.Module, []interface{}) {
 	module := &fileGroup{}
 
 	return android.InitAndroidModule(module, &module.properties)