Support robolectric_test
robolectric_test will compile a suite of tests that run in
robolectric. For now it also generates a Run* rule, later
that will be removed in favor of atest.
Bug: 123248659
Test: m RunSettingsLibRoboTests
Change-Id: I12407d0b0d639e31c1969077ba787e8985e6a506
diff --git a/Android.bp b/Android.bp
index 1fdd44e..25e2796 100644
--- a/Android.bp
+++ b/Android.bp
@@ -276,6 +276,7 @@
"java/plugin.go",
"java/prebuilt_apis.go",
"java/proto.go",
+ "java/robolectric.go",
"java/sdk.go",
"java/sdk_library.go",
"java/support_libraries.go",
diff --git a/android/module.go b/android/module.go
index 6743412..e3c37bb 100644
--- a/android/module.go
+++ b/android/module.go
@@ -143,6 +143,7 @@
OtherModuleErrorf(m blueprint.Module, fmt string, args ...interface{})
OtherModuleDependencyTag(m blueprint.Module) blueprint.DependencyTag
+ GetDirectDepsWithTag(tag blueprint.DependencyTag) []Module
GetDirectDepWithTag(name string, tag blueprint.DependencyTag) blueprint.Module
GetDirectDep(name string) (blueprint.Module, blueprint.DependencyTag)
@@ -1093,6 +1094,18 @@
}
}
+func (a *androidModuleContext) GetDirectDepsWithTag(tag blueprint.DependencyTag) []Module {
+ var deps []Module
+ a.VisitDirectDepsBlueprint(func(m blueprint.Module) {
+ if aModule, _ := m.(Module); aModule != nil {
+ if a.ModuleContext.OtherModuleDependencyTag(aModule) == tag {
+ deps = append(deps, aModule)
+ }
+ }
+ })
+ return deps
+}
+
func (a *androidModuleContext) GetDirectDepWithTag(name string, tag blueprint.DependencyTag) blueprint.Module {
m, _ := a.getDirectDepInternal(name, tag)
return m
diff --git a/java/robolectric.go b/java/robolectric.go
new file mode 100644
index 0000000..26f1e9d
--- /dev/null
+++ b/java/robolectric.go
@@ -0,0 +1,110 @@
+// Copyright 2019 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 java
+
+import (
+ "fmt"
+ "io"
+ "strings"
+
+ "android/soong/android"
+)
+
+func init() {
+ android.RegisterModuleType("android_robolectric_test", RobolectricTestFactory)
+}
+
+var robolectricDefaultLibs = []string{
+ "robolectric_android-all-stub",
+ "Robolectric_all-target",
+ "mockito-robolectric-prebuilt",
+ "truth-prebuilt",
+}
+
+type robolectricProperties struct {
+ // The name of the android_app module that the tests will run against.
+ Instrumentation_for *string
+
+ Test_options struct {
+ // Timeout in seconds when running the tests.
+ Timeout *string
+ }
+}
+
+type robolectricTest struct {
+ Library
+
+ robolectricProperties robolectricProperties
+
+ libs []string
+}
+
+func (r *robolectricTest) DepsMutator(ctx android.BottomUpMutatorContext) {
+ r.Library.DepsMutator(ctx)
+
+ if r.robolectricProperties.Instrumentation_for != nil {
+ ctx.AddVariationDependencies(nil, instrumentationForTag, String(r.robolectricProperties.Instrumentation_for))
+ } else {
+ ctx.PropertyErrorf("instrumentation_for", "missing required instrumented module")
+ }
+
+ ctx.AddVariationDependencies(nil, libTag, robolectricDefaultLibs...)
+}
+
+func (r *robolectricTest) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ r.Library.GenerateAndroidBuildActions(ctx)
+
+ for _, dep := range ctx.GetDirectDepsWithTag(libTag) {
+ r.libs = append(r.libs, ctx.OtherModuleName(dep))
+ }
+}
+
+func (r *robolectricTest) AndroidMk() android.AndroidMkData {
+ data := r.Library.AndroidMk()
+
+ data.Custom = func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
+ android.WriteAndroidMkData(w, data)
+
+ fmt.Fprintln(w, "")
+ fmt.Fprintln(w, "include $(CLEAR_VARS)")
+ fmt.Fprintln(w, "LOCAL_MODULE := Run"+name)
+ fmt.Fprintln(w, "LOCAL_JAVA_LIBRARIES :=", name)
+ fmt.Fprintln(w, "LOCAL_JAVA_LIBRARIES += ", strings.Join(r.libs, " "))
+ fmt.Fprintln(w, "LOCAL_TEST_PACKAGE :=", String(r.robolectricProperties.Instrumentation_for))
+ if t := r.robolectricProperties.Test_options.Timeout; t != nil {
+ fmt.Fprintln(w, "LOCAL_ROBOTEST_TIMEOUT :=", *t)
+ }
+ fmt.Fprintln(w, "-include external/robolectric-shadows/run_robotests.mk")
+ }
+
+ return data
+}
+
+// An android_robolectric_test module compiles tests against the Robolectric framework that can run on the local host
+// instead of on a device. It also generates a rule with the name of the module prefixed with "Run" that can be
+// used to run the tests. Running the tests with build rule will eventually be deprecated and replaced with atest.
+func RobolectricTestFactory() android.Module {
+ module := &robolectricTest{}
+
+ module.AddProperties(
+ &module.Module.properties,
+ &module.Module.protoProperties,
+ &module.robolectricProperties)
+
+ module.Module.dexpreopter.isTest = true
+
+ InitJavaModule(module, android.DeviceSupported)
+ return module
+}