diff --git a/androidmk/cmd/androidmk/androidmk_test.go b/androidmk/cmd/androidmk/androidmk_test.go index a54a4d2ff..ed5ae022d 100644 --- a/androidmk/cmd/androidmk/androidmk_test.go +++ b/androidmk/cmd/androidmk/androidmk_test.go @@ -376,6 +376,33 @@ include $(BUILD_NATIVE_TEST) expected: ` cc_test { } +`, + }, + { + desc: "Convert LOCAL_MODULE_TAGS tests to java_test", + in: ` +include $(CLEAR_VARS) +LOCAL_MODULE_TAGS := tests +include $(BUILD_JAVA_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_MODULE_TAGS := tests +include $(BUILD_PACKAGE) + +include $(CLEAR_VARS) +LOCAL_MODULE_TAGS := tests +include $(BUILD_HOST_JAVA_LIBRARY) +`, + + expected: ` +java_test { +} + +android_test { +} + +java_test_host { +} `, }, diff --git a/bpfix/bpfix/bpfix.go b/bpfix/bpfix/bpfix.go index 1cd040900..05be3bd53 100644 --- a/bpfix/bpfix/bpfix.go +++ b/bpfix/bpfix/bpfix.go @@ -66,6 +66,10 @@ var fixSteps = []fixStep{ name: "rewriteIncorrectAndroidmkAndroidLibraries", fix: rewriteIncorrectAndroidmkAndroidLibraries, }, + { + name: "rewriteTestModuleTypes", + fix: rewriteTestModuleTypes, + }, { name: "mergeMatchingModuleProperties", fix: runPatchListMod(mergeMatchingModuleProperties), @@ -256,6 +260,46 @@ func rewriteIncorrectAndroidmkAndroidLibraries(f *Fixer) error { return nil } +// rewriteTestModuleTypes looks for modules that are identifiable as tests but for which Make doesn't have a separate +// module class, and moves them to the appropriate Soong module type. +func rewriteTestModuleTypes(f *Fixer) error { + for _, def := range f.tree.Defs { + mod, ok := def.(*parser.Module) + if !ok { + continue + } + + if !strings.HasPrefix(mod.Type, "java_") && !strings.HasPrefix(mod.Type, "android_") { + continue + } + + hasInstrumentationFor := hasNonEmptyLiteralStringProperty(mod, "instrumentation_for") + tags, _ := getLiteralListPropertyValue(mod, "tags") + + var hasTestsTag bool + for _, tag := range tags { + if tag == "tests" { + hasTestsTag = true + } + } + + isTest := hasInstrumentationFor || hasTestsTag + + if isTest { + switch mod.Type { + case "android_app": + mod.Type = "android_test" + case "java_library": + mod.Type = "java_test" + case "java_library_host": + mod.Type = "java_test_host" + } + } + } + + return nil +} + func runPatchListMod(modFunc func(mod *parser.Module, buf []byte, patchlist *parser.PatchList) error) func(*Fixer) error { return func(f *Fixer) error { // Make sure all the offsets are accurate @@ -383,26 +427,34 @@ func removeTags(mod *parser.Module, buf []byte, patchlist *parser.PatchList) err // force installation for -eng builds. ` case "tests": - if strings.Contains(mod.Type, "cc_test") || strings.Contains(mod.Type, "cc_library_static") { + switch { + case strings.Contains(mod.Type, "cc_test"), + strings.Contains(mod.Type, "cc_library_static"), + strings.Contains(mod.Type, "java_test"), + mod.Type == "android_test": continue - } else if strings.Contains(mod.Type, "cc_lib") { + case strings.Contains(mod.Type, "cc_lib"): replaceStr += `// WARNING: Module tags are not supported in Soong. // To make a shared library only for tests, use the "cc_test_library" module // type. If you don't use gtest, set "gtest: false". ` - } else if strings.Contains(mod.Type, "cc_bin") { + case strings.Contains(mod.Type, "cc_bin"): replaceStr += `// WARNING: Module tags are not supported in Soong. // For native test binaries, use the "cc_test" module type. Some differences: // - If you don't use gtest, set "gtest: false" // - Binaries will be installed into /data/nativetest[64]// // - Both 32 & 64 bit versions will be built (as appropriate) ` - } else if strings.Contains(mod.Type, "java_lib") { + case strings.Contains(mod.Type, "java_lib"): replaceStr += `// WARNING: Module tags are not supported in Soong. // For JUnit or similar tests, use the "java_test" module type. A dependency on // Junit will be added by default, if it is using some other runner, set "junit: false". ` - } else { + case mod.Type == "android_app": + replaceStr += `// WARNING: Module tags are not supported in Soong. + // For JUnit or instrumentataion app tests, use the "android_test" module type. + ` + default: replaceStr += `// WARNING: Module tags are not supported in Soong. // In most cases, tests are now identified by their module type: // cc_test, java_test, python_test @@ -552,6 +604,11 @@ func hasNonEmptyLiteralListProperty(mod *parser.Module, name string) bool { return found && len(list.Values) > 0 } +func hasNonEmptyLiteralStringProperty(mod *parser.Module, name string) bool { + s, found := getLiteralStringPropertyValue(mod, name) + return found && len(s) > 0 +} + func getLiteralListProperty(mod *parser.Module, name string) (list *parser.List, found bool) { prop, ok := mod.GetProperty(name) if !ok { @@ -561,6 +618,40 @@ func getLiteralListProperty(mod *parser.Module, name string) (list *parser.List, return list, ok } +func getLiteralListPropertyValue(mod *parser.Module, name string) (list []string, found bool) { + listValue, ok := getLiteralListProperty(mod, name) + if !ok { + return nil, false + } + for _, v := range listValue.Values { + stringValue, ok := v.(*parser.String) + if !ok { + return nil, false + } + list = append(list, stringValue.Value) + } + + return list, true +} + +func getLiteralStringProperty(mod *parser.Module, name string) (s *parser.String, found bool) { + prop, ok := mod.GetProperty(name) + if !ok { + return nil, false + } + s, ok = prop.Value.(*parser.String) + return s, ok +} + +func getLiteralStringPropertyValue(mod *parser.Module, name string) (s string, found bool) { + stringValue, ok := getLiteralStringProperty(mod, name) + if !ok { + return "", false + } + + return stringValue.Value, true +} + func propertyIndex(props []*parser.Property, propertyName string) int { for i, prop := range props { if prop.Name == propertyName { diff --git a/java/androidmk.go b/java/androidmk.go index 88dc6ef3d..bc9544afd 100644 --- a/java/androidmk.go +++ b/java/androidmk.go @@ -228,6 +228,19 @@ func (app *AndroidApp) AndroidMk() android.AndroidMkData { } } +func (a *AndroidTest) AndroidMk() android.AndroidMkData { + data := a.AndroidApp.AndroidMk() + data.Extra = append(data.Extra, func(w io.Writer, outputFile android.Path) { + fmt.Fprintln(w, "LOCAL_MODULE_TAGS := tests") + if len(a.testProperties.Test_suites) > 0 { + fmt.Fprintln(w, "LOCAL_COMPATIBILITY_SUITE :=", + strings.Join(a.testProperties.Test_suites, " ")) + } + }) + + return data +} + func (a *AndroidLibrary) AndroidMk() android.AndroidMkData { data := a.Library.AndroidMk() diff --git a/java/app.go b/java/app.go index ae0592a6a..37109b56a 100644 --- a/java/app.go +++ b/java/app.go @@ -26,6 +26,7 @@ import ( func init() { android.RegisterModuleType("android_app", AndroidAppFactory) + android.RegisterModuleType("android_test", AndroidTestFactory) } // AndroidManifest.xml merging @@ -50,8 +51,6 @@ type appProperties struct { // list of resource labels to generate individual resource packages Package_splits []string - - Instrumentation_for *string } type AndroidApp struct { @@ -61,6 +60,8 @@ type AndroidApp struct { certificate certificate appProperties appProperties + + extraLinkFlags []string } func (a *AndroidApp) ExportedProguardFlagFiles() android.Paths { @@ -85,14 +86,11 @@ func (a *AndroidApp) DepsMutator(ctx android.BottomUpMutatorContext) { } func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) { - var linkFlags []string - if String(a.appProperties.Instrumentation_for) != "" { - linkFlags = append(linkFlags, - "--rename-instrumentation-target-package", - String(a.appProperties.Instrumentation_for)) - } else { - a.properties.Instrument = true - } + a.generateAndroidBuildActions(ctx) +} + +func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { + linkFlags := append([]string(nil), a.extraLinkFlags...) hasProduct := false for _, f := range a.aaptProperties.Aaptflags { @@ -188,6 +186,8 @@ func AndroidAppFactory() android.Module { module.Module.deviceProperties.Optimize.Enabled = proptools.BoolPtr(true) module.Module.deviceProperties.Optimize.Shrink = proptools.BoolPtr(true) + module.Module.properties.Instrument = true + module.AddProperties( &module.Module.properties, &module.Module.deviceProperties, @@ -198,3 +198,43 @@ func AndroidAppFactory() android.Module { android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon) return module } + +type appTestProperties struct { + Instrumentation_for *string +} + +type AndroidTest struct { + AndroidApp + + appTestProperties appTestProperties + + testProperties testProperties +} + +func (a *AndroidTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { + if String(a.appTestProperties.Instrumentation_for) != "" { + a.AndroidApp.extraLinkFlags = append(a.AndroidApp.extraLinkFlags, + "--rename-instrumentation-target-package", + String(a.appTestProperties.Instrumentation_for)) + } + + a.generateAndroidBuildActions(ctx) +} + +func AndroidTestFactory() android.Module { + module := &AndroidTest{} + + module.Module.deviceProperties.Optimize.Enabled = proptools.BoolPtr(true) + + module.AddProperties( + &module.Module.properties, + &module.Module.deviceProperties, + &module.Module.protoProperties, + &module.aaptProperties, + &module.appProperties, + &module.appTestProperties) + + android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon) + + return module +} diff --git a/java/java.go b/java/java.go index a4cb65b51..02fdc00fa 100644 --- a/java/java.go +++ b/java/java.go @@ -212,8 +212,8 @@ type CompilerDeviceProperties struct { } Optimize struct { - // If false, disable all optimization. Defaults to true for apps, false for - // libraries and tests. + // If false, disable all optimization. Defaults to true for android_app and android_test + // modules, false for java_library and java_test modules. Enabled *bool // If true, optimize for size by removing unused code. Defaults to true for apps,