ICU4J/Libcore: Generalize the IcuTestRunner so it can be used with libcore
Bug: 22023363
Change-Id: Icf4d0f42f07fa719aaa6036f93b7aa7efec214c9
diff --git a/libs/runner/Android.mk b/libs/runner/Android.mk
index 9642f53..15f64a3 100644
--- a/libs/runner/Android.mk
+++ b/libs/runner/Android.mk
@@ -16,9 +16,7 @@
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-java-files-under, ../../tests/core/runner/src)
-
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+LOCAL_STATIC_JAVA_LIBRARIES := cts-test-runner
LOCAL_MODULE_TAGS := optional
diff --git a/tests/core/runner/Android.mk b/tests/core/runner/Android.mk
index 158a1f1..1355512 100644
--- a/tests/core/runner/Android.mk
+++ b/tests/core/runner/Android.mk
@@ -23,12 +23,44 @@
# include this package in the tests target for continuous testing
LOCAL_MODULE_TAGS := tests
-LOCAL_SRC_FILES := $(call all-java-files-under,src)
-
LOCAL_PACKAGE_NAME := android.core.tests.runner
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+LOCAL_STATIC_JAVA_LIBRARIES := cts-test-runner
LOCAL_JAVA_LANGUAGE_VERSION := 1.8
include $(BUILD_CTSCORE_PACKAGE)
+
+#==========================================================
+# Build the core runner.
+#==========================================================
+
+# Build library
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+LOCAL_SRC_FILES := $(call all-java-files-under,src)
+LOCAL_MODULE := cts-core-test-runner
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ compatibility-device-util \
+ android-support-test \
+ android.test.runner \
+ vogarexpect
+
+LOCAL_JAVA_LANGUAGE_VERSION := 1.8
+
+include $(BUILD_JAVA_LIBRARY)
+
+#==========================================================
+# Build the run listener
+#==========================================================
+
+# Build library
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+LOCAL_SRC_FILES := $(call all-java-files-under,src/com/android/cts/runner)
+LOCAL_MODULE := cts-test-runner
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+
+include $(BUILD_JAVA_LIBRARY)
diff --git a/tests/tests/icu/src/android/icu/cts/AndroidJUnitRunnerConstants.java b/tests/core/runner/src/com/android/cts/core/runner/AndroidJUnitRunnerConstants.java
similarity index 95%
rename from tests/tests/icu/src/android/icu/cts/AndroidJUnitRunnerConstants.java
rename to tests/core/runner/src/com/android/cts/core/runner/AndroidJUnitRunnerConstants.java
index 24d8819..c6c8504 100644
--- a/tests/tests/icu/src/android/icu/cts/AndroidJUnitRunnerConstants.java
+++ b/tests/core/runner/src/com/android/cts/core/runner/AndroidJUnitRunnerConstants.java
@@ -14,14 +14,14 @@
* limitations under the License.
*/
-package android.icu.cts;
+package com.android.cts.core.runner;
import android.support.test.runner.AndroidJUnitRunner;
/**
* Constants used to communicate to and from {@link AndroidJUnitRunner}.
*/
-interface AndroidJUnitRunnerConstants {
+public interface AndroidJUnitRunnerConstants {
/**
* The names of the file containing the names of the tests to run.
@@ -82,5 +82,5 @@
/**
* An identifier for tests run using this class.
*/
- String REPORT_VALUE_ID = "IcuTestRunner";
+ String REPORT_VALUE_ID = "CoreTestRunner";
}
diff --git a/tests/tests/icu/src/android/icu/cts/IcuTestRunner.java b/tests/core/runner/src/com/android/cts/core/runner/CoreTestRunner.java
similarity index 72%
rename from tests/tests/icu/src/android/icu/cts/IcuTestRunner.java
rename to tests/core/runner/src/com/android/cts/core/runner/CoreTestRunner.java
index 51c4999..144e9e2 100644
--- a/tests/tests/icu/src/android/icu/cts/IcuTestRunner.java
+++ b/tests/core/runner/src/com/android/cts/core/runner/CoreTestRunner.java
@@ -14,21 +14,21 @@
* limitations under the License.
*/
-package android.icu.cts;
+package com.android.cts.core.runner;
import android.app.Activity;
import android.app.Instrumentation;
-import android.icu.junit.IcuTestRunnerBuilder;
+import com.android.cts.core.runner.support.ExtendedAndroidRunnerBuilder;
import android.os.Bundle;
import android.os.Debug;
import android.support.test.internal.util.AndroidRunnerParams;
import android.util.Log;
+import com.google.common.base.Splitter;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
@@ -45,22 +45,26 @@
import vogar.ExpectationStore;
import vogar.ModeId;
-import static android.icu.cts.AndroidJUnitRunnerConstants.ARGUMENT_COUNT;
-import static android.icu.cts.AndroidJUnitRunnerConstants.ARGUMENT_DEBUG;
-import static android.icu.cts.AndroidJUnitRunnerConstants.ARGUMENT_LOG_ONLY;
-import static android.icu.cts.AndroidJUnitRunnerConstants.ARGUMENT_TEST_CLASS;
-import static android.icu.cts.AndroidJUnitRunnerConstants.ARGUMENT_TEST_FILE;
+import static com.android.cts.core.runner.AndroidJUnitRunnerConstants.ARGUMENT_COUNT;
+import static com.android.cts.core.runner.AndroidJUnitRunnerConstants.ARGUMENT_DEBUG;
+import static com.android.cts.core.runner.AndroidJUnitRunnerConstants.ARGUMENT_LOG_ONLY;
+import static com.android.cts.core.runner.AndroidJUnitRunnerConstants.ARGUMENT_TEST_CLASS;
+import static com.android.cts.core.runner.AndroidJUnitRunnerConstants.ARGUMENT_TEST_FILE;
/**
* A drop-in replacement for AndroidJUnitTestRunner, which understands the same arguments, and has
- * similar functionality, but runs ICU tests instead of calling the JUnit wrapper.
+ * similar functionality, but can filter by expectations and allows a custom runner-builder to be
+ * provided.
*/
-public final class IcuTestRunner extends Instrumentation {
+public class CoreTestRunner extends Instrumentation {
- public static final String TAG = "IcuTestRunner";
+ public static final String TAG = "LibcoreTestRunner";
- private static final List<String> EXPECTATIONS_PATHS =
- Collections.singletonList("expectations/icu-known-failures.txt");
+ private static final java.lang.String ARGUMENT_ROOT_CLASSES = "core-root-classes";
+
+ private static final String ARGUMENT_EXPECTATIONS = "core-expectations";
+
+ private static final Splitter CLASS_LIST_SPLITTER = Splitter.on(',').trimResults();
/** The args for the runner. */
private Bundle args;
@@ -80,10 +84,10 @@
/**
* The list of tests to run.
*/
- private IcuTestList icuTestList;
+ private TestList testList;
@Override
- public void onCreate(Bundle args) {
+ public void onCreate(final Bundle args) {
super.onCreate(args);
this.args = args;
@@ -102,7 +106,9 @@
this.testCountOnly = args.getBoolean(ARGUMENT_COUNT);
try {
- Set<String> expectationResources = new LinkedHashSet<>(EXPECTATIONS_PATHS);
+ // Get the set of resource names containing the expectations.
+ Set<String> expectationResources = new LinkedHashSet<>(
+ CLASS_LIST_SPLITTER.splitToList(args.getString(ARGUMENT_EXPECTATIONS)));
expectationStore = ExpectationStore.parseResources(
getClass(), expectationResources, ModeId.DEVICE);
} catch (IOException e) {
@@ -131,11 +137,16 @@
}
if (testNameList == null) {
- icuTestList = IcuTestList.rootList(Arrays.asList(
- "android.icu.cts.coverage.TestAll",
- "android.icu.dev.test.TestAll"));
+ String rootClasses = args.getString(ARGUMENT_ROOT_CLASSES);
+ if (rootClasses == null) {
+ throw new IllegalStateException(
+ "No tests specified, neither exclusive list or root class");
+ } else {
+ List<String> roots = CLASS_LIST_SPLITTER.splitToList(rootClasses);
+ testList = TestList.rootList(roots);
+ }
} else {
- icuTestList = IcuTestList.exclusiveList(testNameList);
+ testList = TestList.exclusiveList(testNameList);
}
start();
@@ -157,15 +168,15 @@
Request request;
int totalTestCount;
try {
- RunnerBuilder runnerBuilder = new IcuTestRunnerBuilder(runnerParams);
- Class[] classes = icuTestList.getClassesToRun();
+ RunnerBuilder runnerBuilder = new ExtendedAndroidRunnerBuilder(runnerParams);
+ Class[] classes = testList.getClassesToRun();
Runner suite = new Computer().getSuite(runnerBuilder, classes);
if (suite instanceof Filterable) {
Filterable filterable = (Filterable) suite;
// Filter out all the tests that are expected to fail.
- Filter filter = new IcuTestFilter(icuTestList, expectationStore);
+ Filter filter = new TestFilter(testList, expectationStore);
try {
filterable.filter(filter);
@@ -183,17 +194,18 @@
throw new RuntimeException("Could not create a suite", e);
}
- IcuRunListener icuRunListener = new IcuRunListener(this, runnerParams, totalTestCount);
- core.addListener(icuRunListener);
+ StatusUpdaterRunListener statusUpdaterRunListener =
+ new StatusUpdaterRunListener(this, runnerParams, totalTestCount);
+ core.addListener(statusUpdaterRunListener);
core.run(request);
Bundle results;
if (testCountOnly) {
- results = icuRunListener.getCountResults();
+ results = statusUpdaterRunListener.getCountResults();
Log.d(TAG, "test count only: " + results);
} else {
// Get the final results to send back.
- results = icuRunListener.getFinalResults();
+ results = statusUpdaterRunListener.getFinalResults();
}
Log.d(TAG, "Finished");
diff --git a/tests/tests/icu/src/android/icu/cts/IcuRunListener.java b/tests/core/runner/src/com/android/cts/core/runner/StatusUpdaterRunListener.java
similarity index 92%
rename from tests/tests/icu/src/android/icu/cts/IcuRunListener.java
rename to tests/core/runner/src/com/android/cts/core/runner/StatusUpdaterRunListener.java
index 0a6f355..429ae92 100644
--- a/tests/tests/icu/src/android/icu/cts/IcuRunListener.java
+++ b/tests/core/runner/src/com/android/cts/core/runner/StatusUpdaterRunListener.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.icu.cts;
+package com.android.cts.core.runner;
import android.app.Instrumentation;
import android.os.Bundle;
@@ -30,8 +30,8 @@
import static android.app.Instrumentation.REPORT_KEY_IDENTIFIER;
import static android.app.Instrumentation.REPORT_KEY_STREAMRESULT;
-import static android.icu.cts.AndroidJUnitRunnerConstants.REPORT_KEY_RUNTIME;
-import static android.icu.cts.AndroidJUnitRunnerConstants.REPORT_VALUE_ID;
+import static com.android.cts.core.runner.AndroidJUnitRunnerConstants.REPORT_KEY_RUNTIME;
+import static com.android.cts.core.runner.AndroidJUnitRunnerConstants.REPORT_VALUE_ID;
import static android.test.InstrumentationTestRunner.REPORT_KEY_NAME_CLASS;
import static android.test.InstrumentationTestRunner.REPORT_KEY_NAME_TEST;
import static android.test.InstrumentationTestRunner.REPORT_KEY_NUM_CURRENT;
@@ -47,7 +47,7 @@
* Listens to result of running tests, collates details and sends intermediate status information
* back to the host.
*/
-class IcuRunListener extends RunListener {
+class StatusUpdaterRunListener extends RunListener {
/**
* The {@link Instrumentation} for which this will report information.
@@ -77,7 +77,8 @@
private long testStartTime;
- public IcuRunListener(Instrumentation instrumentation, AndroidRunnerParams runnerParams,
+ public StatusUpdaterRunListener(Instrumentation instrumentation,
+ AndroidRunnerParams runnerParams,
int totalTestCount) {
this.instrumentation = instrumentation;
this.runnerParams = runnerParams;
@@ -135,6 +136,7 @@
} else {
resultStatus = REPORT_VALUE_RESULT_ERROR;
}
+
String information = failure.getTrace();
currentTestResult.putString(REPORT_KEY_STACK, information);
String output = "Error: " + description + "\n" + information;
@@ -165,7 +167,7 @@
public Bundle getFinalResults() {
int totalTests = totalFailures + totalSuccess;
- Log.d(IcuTestRunner.TAG, (runnerParams.isSkipExecution() ? "Skipped " : "Ran ")
+ Log.d(CoreTestRunner.TAG, (runnerParams.isSkipExecution() ? "Skipped " : "Ran ")
+ totalTests + " tests, " + totalSuccess + " passed, " + totalFailures + " failed");
Bundle results = new Bundle();
results.putString(REPORT_KEY_IDENTIFIER, REPORT_VALUE_ID);
@@ -189,7 +191,7 @@
}
public Bundle getCountResults() {
- Log.d(IcuTestRunner.TAG, "Counted " + (totalFailures + totalSuccess) + " tests, "
+ Log.d(CoreTestRunner.TAG, "Counted " + (totalFailures + totalSuccess) + " tests, "
+ totalSuccess + " passed, " + totalFailures + " failed");
Bundle results = new Bundle();
results.putString(REPORT_KEY_IDENTIFIER, REPORT_VALUE_ID);
diff --git a/tests/tests/icu/src/android/icu/cts/IcuTestFilter.java b/tests/core/runner/src/com/android/cts/core/runner/TestFilter.java
similarity index 90%
rename from tests/tests/icu/src/android/icu/cts/IcuTestFilter.java
rename to tests/core/runner/src/com/android/cts/core/runner/TestFilter.java
index 3da2976..8cadbcf 100644
--- a/tests/tests/icu/src/android/icu/cts/IcuTestFilter.java
+++ b/tests/core/runner/src/com/android/cts/core/runner/TestFilter.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.icu.cts;
+package com.android.cts.core.runner;
import android.util.Log;
import java.util.List;
@@ -61,15 +61,15 @@
* {@link ParentRunner}, as that would prevent it from traversing the hierarchy and finding
* the leaf nodes.
*/
-class IcuTestFilter extends Filter {
+class TestFilter extends Filter {
private final ExpectationStore expectationStore;
- private final IcuTestList icuTestList;
+ private final TestList testList;
- public IcuTestFilter(IcuTestList icuTestList, @Nullable ExpectationStore expectationStore) {
+ public TestFilter(TestList testList, @Nullable ExpectationStore expectationStore) {
this.expectationStore = expectationStore;
- this.icuTestList = icuTestList;
+ this.testList = testList;
}
@Override
@@ -84,14 +84,14 @@
String testName = className + "#" + methodName;
// If the test isn't in the list of tests to run then do not run it.
- if (!icuTestList.shouldRunTest(testName)) {
+ if (!testList.shouldRunTest(testName)) {
return false;
}
if (expectationStore != null) {
Expectation expectation = expectationStore.get(testName);
if (expectation.getResult() != Result.SUCCESS) {
- Log.d(IcuTestRunner.TAG, "Excluding test " + description
+ Log.d(CoreTestRunner.TAG, "Excluding test " + testDescription
+ " as it matches expectation: " + expectation);
return false;
}
@@ -126,6 +126,6 @@
@Override
public String describe() {
- return "IcuTestFilter";
+ return "TestFilter";
}
}
diff --git a/tests/tests/icu/src/android/icu/cts/IcuTestList.java b/tests/core/runner/src/com/android/cts/core/runner/TestList.java
similarity index 84%
rename from tests/tests/icu/src/android/icu/cts/IcuTestList.java
rename to tests/core/runner/src/com/android/cts/core/runner/TestList.java
index a9c3c5f..4b0452d 100644
--- a/tests/tests/icu/src/android/icu/cts/IcuTestList.java
+++ b/tests/core/runner/src/com/android/cts/core/runner/TestList.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.icu.cts;
+package com.android.cts.core.runner;
import android.util.Log;
import java.util.ArrayList;
@@ -25,7 +25,7 @@
/**
* A list of the tests to run.
*/
-class IcuTestList {
+class TestList {
/**
* The names of the set of tests to run, if null then all tests should be run.
@@ -35,7 +35,7 @@
private final List<Class<?>> classesToRun;
- public static IcuTestList exclusiveList(List<String> testNameList) {
+ public static TestList exclusiveList(List<String> testNameList) {
Set<String> classNamesToRun = new LinkedHashSet<>();
Set<String> testsToRun = new LinkedHashSet<>(testNameList);
@@ -50,19 +50,19 @@
classNamesToRun.add(className);
}
- Log.d(IcuTestRunner.TAG, "Running only the following tests: " + testsToRun);
- return new IcuTestList(getClasses(classNamesToRun), testsToRun);
+ Log.d(CoreTestRunner.TAG, "Running only the following tests: " + testsToRun);
+ return new TestList(getClasses(classNamesToRun), testsToRun);
}
- public static IcuTestList rootList(List<String> rootList) {
+ public static TestList rootList(List<String> rootList) {
// Run from the root test class.
Set<String> classNamesToRun = new LinkedHashSet<>(rootList);
- Log.d(IcuTestRunner.TAG, "Running all tests rooted at " + classNamesToRun);
+ Log.d(CoreTestRunner.TAG, "Running all tests rooted at " + classNamesToRun);
List<Class<?>> classesToRun1 = getClasses(classNamesToRun);
- return new IcuTestList(classesToRun1, null);
+ return new TestList(classesToRun1, null);
}
private static List<Class<?>> getClasses(Set<String> classNames) {
@@ -83,7 +83,7 @@
* @param testsToRun The exclusive set of tests to run or null if all tests reachable from the
* classes are to be run.
*/
- private IcuTestList(List<Class<?>> classes, Set<String> testsToRun) {
+ private TestList(List<Class<?>> classes, Set<String> testsToRun) {
this.testsToRun = testsToRun;
this.classesToRun = classes;
}
diff --git a/tests/core/runner/src/com/android/cts/core/runner/support/AndroidRunnerBuilder.java b/tests/core/runner/src/com/android/cts/core/runner/support/AndroidRunnerBuilder.java
new file mode 100644
index 0000000..bdb3e57
--- /dev/null
+++ b/tests/core/runner/src/com/android/cts/core/runner/support/AndroidRunnerBuilder.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * 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 com.android.cts.core.runner.support;
+
+import android.support.test.internal.runner.junit3.AndroidJUnit3Builder;
+import android.support.test.internal.runner.junit3.AndroidSuiteBuilder;
+import android.support.test.internal.runner.junit4.AndroidAnnotatedBuilder;
+import android.support.test.internal.runner.junit4.AndroidJUnit4Builder;
+import android.support.test.internal.util.AndroidRunnerParams;
+
+import org.junit.internal.builders.AllDefaultPossibilitiesBuilder;
+import org.junit.internal.builders.AnnotatedBuilder;
+import org.junit.internal.builders.IgnoredBuilder;
+import org.junit.internal.builders.JUnit3Builder;
+import org.junit.internal.builders.JUnit4Builder;
+import org.junit.runners.model.RunnerBuilder;
+
+/**
+ * A {@link RunnerBuilder} that can handle all types of tests.
+ */
+// A copy of package private class android.support.test.internal.runner.AndroidRunnerBuilder.
+// Copied here so that it can be extended.
+class AndroidRunnerBuilder extends AllDefaultPossibilitiesBuilder {
+
+ private final AndroidJUnit3Builder mAndroidJUnit3Builder;
+ private final AndroidJUnit4Builder mAndroidJUnit4Builder;
+ private final AndroidSuiteBuilder mAndroidSuiteBuilder;
+ private final AndroidAnnotatedBuilder mAndroidAnnotatedBuilder;
+ // TODO: customize for Android ?
+ private final IgnoredBuilder mIgnoredBuilder;
+
+ /**
+ * @param runnerParams {@link AndroidRunnerParams} that stores common runner parameters
+ */
+ AndroidRunnerBuilder(AndroidRunnerParams runnerParams) {
+ super(true);
+ mAndroidJUnit3Builder = new AndroidJUnit3Builder(runnerParams);
+ mAndroidJUnit4Builder = new AndroidJUnit4Builder(runnerParams);
+ mAndroidSuiteBuilder = new AndroidSuiteBuilder(runnerParams);
+ mAndroidAnnotatedBuilder = new AndroidAnnotatedBuilder(this, runnerParams);
+ mIgnoredBuilder = new IgnoredBuilder();
+ }
+
+ @Override
+ protected JUnit4Builder junit4Builder() {
+ return mAndroidJUnit4Builder;
+ }
+
+ @Override
+ protected JUnit3Builder junit3Builder() {
+ return mAndroidJUnit3Builder;
+ }
+
+ @Override
+ protected AnnotatedBuilder annotatedBuilder() {
+ return mAndroidAnnotatedBuilder;
+ }
+
+ @Override
+ protected IgnoredBuilder ignoredBuilder() {
+ return mIgnoredBuilder;
+ }
+
+ @Override
+ protected RunnerBuilder suiteMethodBuilder() {
+ return mAndroidSuiteBuilder;
+ }
+}
diff --git a/tests/core/runner/src/com/android/cts/core/runner/support/ExtendedAndroidAnnotatedBuilder.java b/tests/core/runner/src/com/android/cts/core/runner/support/ExtendedAndroidAnnotatedBuilder.java
new file mode 100644
index 0000000..05c6623
--- /dev/null
+++ b/tests/core/runner/src/com/android/cts/core/runner/support/ExtendedAndroidAnnotatedBuilder.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * 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 com.android.cts.core.runner.support;
+
+import android.support.test.internal.runner.junit4.AndroidAnnotatedBuilder;
+import android.support.test.internal.util.AndroidRunnerParams;
+import android.support.test.runner.AndroidJUnit4;
+import junit.framework.TestCase;
+import org.junit.runner.RunWith;
+import org.junit.runner.Runner;
+import org.junit.runners.BlockJUnit4ClassRunner;
+import org.junit.runners.JUnit4;
+import org.junit.runners.model.RunnerBuilder;
+
+/**
+ * Extends {@link AndroidAnnotatedBuilder} to add support for passing the
+ * {@link AndroidRunnerParams} object to the constructor of any {@link RunnerBuilder}
+ * implementation that is not a {@link BlockJUnit4ClassRunner}.
+ *
+ * <p>If {@link AndroidRunnerParams#isSkipExecution()} is {@code true} the super class will create
+ * a {@link RunnerBuilder} that will fire appropriate events as if the tests are being run but will
+ * not actually run the test. Unfortunately, when it does that it appears to assume that the runner
+ * extends {@link BlockJUnit4ClassRunner}, returns a skipping {@link RunnerBuilder} appropriate for
+ * that and ignores the actual {@code runnerClass}. That is a problem because it will not work for
+ * custom {@link RunnerBuilder} instances that do not extend {@link BlockJUnit4ClassRunner}.
+ *
+ * <p>Therefore, when skipping execution this does some additional checks to make sure that the
+ * {@code runnerClass} does extend {@link BlockJUnit4ClassRunner} before calling the overridden
+ * method.
+ *
+ * <p>It then attempts to construct a {@link RunnerBuilder} by calling the constructor with the
+ * signature {@code <init>(Class, AndroidRunnerParams)}. If that doesn't exist it falls back to
+ * the overridden behavior.
+ */
+class ExtendedAndroidAnnotatedBuilder extends AndroidAnnotatedBuilder {
+
+ private final AndroidRunnerParams runnerParams;
+
+ public ExtendedAndroidAnnotatedBuilder(RunnerBuilder suiteBuilder,
+ AndroidRunnerParams runnerParams) {
+ super(suiteBuilder, runnerParams);
+ this.runnerParams = runnerParams;
+ }
+
+ @Override
+ public Runner runnerForClass(Class<?> testClass) throws Exception {
+
+ RunWith annotation = testClass.getAnnotation(RunWith.class);
+ if (annotation != null) {
+ Class<? extends Runner> runnerClass = annotation.value();
+
+ // If the runner is expected to skip execution and it is a JUnit4, AndroidJUnit4 or
+ // a JUnit3 test class then return a special skipping runner.
+ if (runnerParams.isSkipExecution()) {
+ if (runnerClass == AndroidJUnit4.class || runnerClass == JUnit4.class
+ || TestCase.class.isAssignableFrom(testClass)) {
+ return super.runnerForClass(testClass);
+ }
+ }
+
+ try {
+ // try to build an AndroidJUnit4 runner
+ Runner runner = buildAndroidRunner(runnerClass, testClass);
+ if (runner != null) {
+ return runner;
+ }
+ } catch (NoSuchMethodException e) {
+ // let the super class handle the error for us and throw an InitializationError
+ // exception.
+ return super.buildRunner(runnerClass, testClass);
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/tests/core/runner/src/com/android/cts/core/runner/support/ExtendedAndroidRunnerBuilder.java b/tests/core/runner/src/com/android/cts/core/runner/support/ExtendedAndroidRunnerBuilder.java
new file mode 100644
index 0000000..ed16318
--- /dev/null
+++ b/tests/core/runner/src/com/android/cts/core/runner/support/ExtendedAndroidRunnerBuilder.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * 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 com.android.cts.core.runner.support;
+
+import android.support.test.internal.runner.junit4.AndroidAnnotatedBuilder;
+import android.support.test.internal.util.AndroidRunnerParams;
+import org.junit.internal.builders.AnnotatedBuilder;
+import org.junit.runners.model.RunnerBuilder;
+
+/**
+ * Extends {@link AndroidRunnerBuilder} in order to provide alternate {@link RunnerBuilder}
+ * implementations.
+ */
+public class ExtendedAndroidRunnerBuilder extends AndroidRunnerBuilder {
+
+ private final AndroidAnnotatedBuilder mAndroidAnnotatedBuilder;
+
+ /**
+ * @param runnerParams {@link AndroidRunnerParams} that stores common runner parameters
+ */
+ public ExtendedAndroidRunnerBuilder(AndroidRunnerParams runnerParams) {
+ super(runnerParams);
+ mAndroidAnnotatedBuilder = new ExtendedAndroidAnnotatedBuilder(this, runnerParams);
+ }
+
+ @Override
+ protected AnnotatedBuilder annotatedBuilder() {
+ return mAndroidAnnotatedBuilder;
+ }
+}
diff --git a/tests/core/runner/src/com/android/cts/core/runner/support/package-info.java b/tests/core/runner/src/com/android/cts/core/runner/support/package-info.java
new file mode 100644
index 0000000..3ccec3c
--- /dev/null
+++ b/tests/core/runner/src/com/android/cts/core/runner/support/package-info.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * 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.
+ */
+
+/**
+ * Contains all the changes needed to the {@code android.support.test.internal.runner} classes.
+ *
+ * <p>As its name suggests {@code android.support.test.internal.runner} are internal classes that
+ * are not designed to be extended from outside those packages. This package encapsulates all the
+ * workarounds needed to overcome that limitation, from duplicating classes to using reflection.
+ * The intention is that these changes are temporary and they (or a better equivalent) will be
+ * quickly integrated into the internal classes.
+ */
+package com.android.cts.core.runner.support;
diff --git a/tests/tests/icu/Android.mk b/tests/tests/icu/Android.mk
index 39a4b53..6f183d5 100644
--- a/tests/tests/icu/Android.mk
+++ b/tests/tests/icu/Android.mk
@@ -31,9 +31,7 @@
# The aim of this package is to run tests against the implementation in use by
# the current android system.
LOCAL_STATIC_JAVA_LIBRARIES := \
- compatibility-device-util \
- android-support-test \
- vogarexpect \
+ cts-core-test-runner \
android-icu4j-tests
# Tag this module as a cts test artifact
diff --git a/tests/tests/icu/AndroidManifest.xml b/tests/tests/icu/AndroidManifest.xml
index 7d99c0a..c743375 100644
--- a/tests/tests/icu/AndroidManifest.xml
+++ b/tests/tests/icu/AndroidManifest.xml
@@ -22,7 +22,7 @@
<uses-library android:name="android.test.runner" />
</application>
- <instrumentation android:name="android.icu.cts.IcuTestRunner"
+ <instrumentation android:name="com.android.cts.core.runner.CoreTestRunner"
android:targetPackage="android.icu.cts"
- android:label="ICU4J library tests."/>
+ android:label="CTS Repackaged ICU4J library tests."/>
</manifest>
diff --git a/tests/tests/icu/AndroidTest.xml b/tests/tests/icu/AndroidTest.xml
index 18c95cd..769b789 100644
--- a/tests/tests/icu/AndroidTest.xml
+++ b/tests/tests/icu/AndroidTest.xml
@@ -18,8 +18,13 @@
<option name="test-file-name" value="CtsIcuTestCases.apk" />
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
- <option name="runner" value="android.icu.cts.IcuTestRunner" /><!-- override AJUR -->
+ <!-- override AJUR -->
+ <option name="runner" value="com.android.cts.core.runner.CoreTestRunner" />
<option name="package" value="android.icu.cts" />
+ <option name="instrumentation-arg" key="core-root-classes"
+ value="android.icu.cts.coverage.TestAll,android.icu.dev.test.TestAll" />
+ <option name="instrumentation-arg" key="core-expectations"
+ value="/android/icu/cts/expectations/icu-known-failures.txt" />
<option name="runtime-hint" value="30m19s" />
</test>
</configuration>