diff --git a/android/namespace_test.go b/android/namespace_test.go index 604b3567e..08e221a65 100644 --- a/android/namespace_test.go +++ b/android/namespace_test.go @@ -697,7 +697,7 @@ func findModuleById(ctx *TestContext, id string) (module TestingModule) { testModule, ok := candidate.(*testModule) if ok { if testModule.properties.Id == id { - module = newTestingModule(testModule) + module = newTestingModule(ctx.config, testModule) } } } diff --git a/android/rule_builder_test.go b/android/rule_builder_test.go index f41d61b49..9cd60a2a9 100644 --- a/android/rule_builder_test.go +++ b/android/rule_builder_test.go @@ -562,46 +562,44 @@ func TestRuleBuilder_Build(t *testing.T) { AssertBoolEquals(t, "RuleParams.Restat", wantRestat, params.RuleParams.Restat) wantImplicits := append([]string{"bar"}, extraImplicits...) - AssertArrayString(t, "Implicits", wantImplicits, params.Implicits.Strings()) + AssertPathsRelativeToTopEquals(t, "Implicits", wantImplicits, params.Implicits) - AssertStringEquals(t, "Output", wantOutput, params.Output.String()) + AssertPathRelativeToTopEquals(t, "Output", wantOutput, params.Output) if len(params.ImplicitOutputs) != 0 { t.Errorf("want ImplicitOutputs = [], got %q", params.ImplicitOutputs.Strings()) } - AssertStringEquals(t, "Depfile", wantDepfile, params.Depfile.String()) + AssertPathRelativeToTopEquals(t, "Depfile", wantDepfile, params.Depfile) if params.Deps != blueprint.DepsGCC { t.Errorf("want Deps = %q, got %q", blueprint.DepsGCC, params.Deps) } } - buildDir := result.Config.BuildDir() - t.Run("module", func(t *testing.T) { - outFile := filepath.Join(buildDir, ".intermediates", "foo", "gen", "foo") - check(t, result.ModuleForTests("foo", "").Rule("rule"), + outFile := "out/soong/.intermediates/foo/gen/foo" + check(t, result.ModuleForTests("foo", "").Rule("rule").RelativeToTop(), "cp bar "+outFile, outFile, outFile+".d", true, nil, nil) }) t.Run("sbox", func(t *testing.T) { - outDir := filepath.Join(buildDir, ".intermediates", "foo_sbox") + outDir := "out/soong/.intermediates/foo_sbox" outFile := filepath.Join(outDir, "gen/foo_sbox") depFile := filepath.Join(outDir, "gen/foo_sbox.d") manifest := filepath.Join(outDir, "sbox.textproto") - sbox := filepath.Join(buildDir, "host", result.Config.PrebuiltOS(), "bin/sbox") - sandboxPath := shared.TempDirForOutDir(buildDir) + sbox := filepath.Join("out", "soong", "host", result.Config.PrebuiltOS(), "bin/sbox") + sandboxPath := shared.TempDirForOutDir("out/soong") cmd := `rm -rf ` + outDir + `/gen && ` + sbox + ` --sandbox-path ` + sandboxPath + ` --manifest ` + manifest - check(t, result.ModuleForTests("foo_sbox", "").Output("gen/foo_sbox"), + check(t, result.ModuleForTests("foo_sbox", "").Output("gen/foo_sbox").RelativeToTop(), cmd, outFile, depFile, false, []string{manifest}, []string{sbox}) }) t.Run("singleton", func(t *testing.T) { - outFile := filepath.Join(buildDir, "singleton/gen/baz") - check(t, result.SingletonForTests("rule_builder_test").Rule("rule"), + outFile := filepath.Join("out/soong/singleton/gen/baz") + check(t, result.SingletonForTests("rule_builder_test").Rule("rule").RelativeToTop(), "cp bar "+outFile, outFile, outFile+".d", true, nil, nil) }) } diff --git a/android/testing.go b/android/testing.go index abfc65932..0b067280c 100644 --- a/android/testing.go +++ b/android/testing.go @@ -479,7 +479,7 @@ func (ctx *TestContext) ModuleForTests(name, variant string) TestingModule { } } - return newTestingModule(module) + return newTestingModule(ctx.config, module) } func (ctx *TestContext) ModuleVariantsForTests(name string) []string { @@ -499,7 +499,7 @@ func (ctx *TestContext) SingletonForTests(name string) TestingSingleton { n := ctx.SingletonName(s) if n == name { return TestingSingleton{ - baseTestingComponent: newBaseTestingComponent(s.(testBuildProvider)), + baseTestingComponent: newBaseTestingComponent(ctx.config, s.(testBuildProvider)), singleton: s.(*singletonAdaptor).Singleton, } } @@ -522,19 +522,118 @@ type testBuildProvider interface { 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 +// * Path instances are intentionally not modified, use AssertPathRelativeToTopEquals or +// AssertPathsRelativeToTopEquals instead which do something similar. +// +// * RuleParams +// * Command +// * Depfile +// * Rspfile +// * RspfileContent +// * SymlinkOutputs +// * CommandDeps +// * CommandOrderOnly +// +// See PathRelativeToTop for more details. +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 { + panic("cannot call RelativeToTop() on a TestingBuildParams previously returned by RelativeToTop()") + } + // 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.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.SymlinkOutputs = normalizeStringArrayRelativeToTop(p.config, rparams.SymlinkOutputs) + rparams.CommandDeps = normalizeStringArrayRelativeToTop(p.config, rparams.CommandDeps) + rparams.CommandOrderOnly = normalizeStringArrayRelativeToTop(p.config, rparams.CommandOrderOnly) + + return TestingBuildParams{ + BuildParams: bparams, + RuleParams: rparams, + } } // baseTestingComponent provides functionality common to both TestingModule and TestingSingleton. type baseTestingComponent struct { + config Config provider testBuildProvider } -func newBaseTestingComponent(provider testBuildProvider) baseTestingComponent { - return baseTestingComponent{provider} +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 buildDir usually looks something like: /tmp/testFoo2345/001 + // + // Replace any usage of the buildDir with out/soong, e.g. replace "/tmp/testFoo2345/001" with + // "out/soong". + outSoongDir := filepath.Clean(config.buildDir) + re := regexp.MustCompile(`\Q` + outSoongDir + `\E\b`) + s = re.ReplaceAllString(s, "out/soong") + + // Replace any usage of the buildDir/.. 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], } @@ -665,9 +764,9 @@ type TestingModule struct { module Module } -func newTestingModule(module Module) TestingModule { +func newTestingModule(config Config, module Module) TestingModule { return TestingModule{ - newBaseTestingComponent(module), + newBaseTestingComponent(config, module), module, } }