diff options
Diffstat (limited to 'base/test/android/junit/src/org/chromium')
15 files changed, 1639 insertions, 0 deletions
diff --git a/base/test/android/junit/src/org/chromium/base/test/BaseRobolectricTestRunner.java b/base/test/android/junit/src/org/chromium/base/test/BaseRobolectricTestRunner.java new file mode 100644 index 0000000000..3ca756ad9a --- /dev/null +++ b/base/test/android/junit/src/org/chromium/base/test/BaseRobolectricTestRunner.java @@ -0,0 +1,49 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.base.test; + +import org.junit.runners.model.InitializationError; +import org.robolectric.DefaultTestLifecycle; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.TestLifecycle; + +import org.chromium.base.ApplicationStatus; +import org.chromium.base.CommandLine; +import org.chromium.base.ContextUtils; +import org.chromium.testing.local.LocalRobolectricTestRunner; + +import java.lang.reflect.Method; + +/** + * A Robolectric Test Runner that initializes base globals. + */ +public class BaseRobolectricTestRunner extends LocalRobolectricTestRunner { + /** + * Enables a per-test setUp / tearDown hook. + */ + public static class BaseTestLifecycle extends DefaultTestLifecycle { + @Override + public void beforeTest(Method method) { + ContextUtils.initApplicationContextForTests(RuntimeEnvironment.application); + CommandLine.init(null); + super.beforeTest(method); + } + + @Override + public void afterTest(Method method) { + ApplicationStatus.destroyForJUnitTests(); + super.afterTest(method); + } + } + + public BaseRobolectricTestRunner(Class<?> testClass) throws InitializationError { + super(testClass); + } + + @Override + protected Class<? extends TestLifecycle> getTestLifecycleClass() { + return BaseTestLifecycle.class; + } +} diff --git a/base/test/android/junit/src/org/chromium/base/test/SetUpStatementTest.java b/base/test/android/junit/src/org/chromium/base/test/SetUpStatementTest.java new file mode 100644 index 0000000000..722bd1acfe --- /dev/null +++ b/base/test/android/junit/src/org/chromium/base/test/SetUpStatementTest.java @@ -0,0 +1,64 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.base.test; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.rules.TestRule; +import org.junit.runner.RunWith; +import org.junit.runners.BlockJUnit4ClassRunner; +import org.junit.runners.model.Statement; + +import java.util.ArrayList; +import java.util.List; + +/** + * Test SetUpStatement is working as intended with SetUpTestRule. + */ +@RunWith(BlockJUnit4ClassRunner.class) +public class SetUpStatementTest { + private Statement mBase; + private SetUpTestRule<TestRule> mRule; + private List<Integer> mList; + + @Before + public void setUp() { + mBase = new Statement() { + @Override + public void evaluate() { + mList.add(1); + } + }; + mList = new ArrayList<>(); + mRule = new SetUpTestRule<TestRule>() { + @Override + public void setUp() { + mList.add(0); + } + + @Override + public TestRule shouldSetUp(boolean toSetUp) { + return null; + } + }; + } + + @Test + public void testSetUpStatementShouldSetUp() throws Throwable { + SetUpStatement statement = new SetUpStatement(mBase, mRule, true); + statement.evaluate(); + Integer[] expected = {0, 1}; + Assert.assertArrayEquals(expected, mList.toArray()); + } + + @Test + public void testSetUpStatementShouldNotSetUp() throws Throwable { + SetUpStatement statement = new SetUpStatement(mBase, mRule, false); + statement.evaluate(); + Integer[] expected = {1}; + Assert.assertArrayEquals(expected, mList.toArray()); + } +} diff --git a/base/test/android/junit/src/org/chromium/base/test/TestListInstrumentationRunListenerTest.java b/base/test/android/junit/src/org/chromium/base/test/TestListInstrumentationRunListenerTest.java new file mode 100644 index 0000000000..63fa5601fb --- /dev/null +++ b/base/test/android/junit/src/org/chromium/base/test/TestListInstrumentationRunListenerTest.java @@ -0,0 +1,119 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.base.test; + +import static org.chromium.base.test.TestListInstrumentationRunListener.getAnnotationJSON; +import static org.chromium.base.test.TestListInstrumentationRunListener.getTestMethodJSON; + +import org.json.JSONObject; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.Description; +import org.junit.runner.RunWith; +import org.robolectric.annotation.Config; + +import org.chromium.base.test.util.CommandLineFlags; + +import java.util.Arrays; + +/** + * Robolectric test to ensure static methods in TestListInstrumentationRunListener works properly. + */ +@RunWith(BaseRobolectricTestRunner.class) +@Config(manifest = Config.NONE) +public class TestListInstrumentationRunListenerTest { + @CommandLineFlags.Add("hello") + private static class ParentClass { + public void testA() {} + + @CommandLineFlags.Add("world") + public void testB() {} + } + + @CommandLineFlags.Remove("hello") + private static class ChildClass extends ParentClass { + } + + @Test + public void testGetTestMethodJSON_testA() throws Throwable { + Description desc = Description.createTestDescription( + ParentClass.class, "testA", + ParentClass.class.getMethod("testA").getAnnotations()); + JSONObject json = getTestMethodJSON(desc); + String expectedJsonString = + "{" + + "'method': 'testA'," + + "'annotations': {}" + + "}"; + expectedJsonString = expectedJsonString + .replaceAll("\\s", "") + .replaceAll("'", "\""); + Assert.assertEquals(expectedJsonString, json.toString()); + } + + @Test + public void testGetTestMethodJSON_testB() throws Throwable { + Description desc = Description.createTestDescription( + ParentClass.class, "testB", + ParentClass.class.getMethod("testB").getAnnotations()); + JSONObject json = getTestMethodJSON(desc); + String expectedJsonString = + "{" + + "'method': 'testB'," + + "'annotations': {" + + " 'Add': {" + + " 'value': ['world']" + + " }" + + " }" + + "}"; + expectedJsonString = expectedJsonString + .replaceAll("\\s", "") + .replaceAll("'", "\""); + Assert.assertEquals(expectedJsonString, json.toString()); + } + + + @Test + public void testGetTestMethodJSONForInheritedClass() throws Throwable { + Description desc = Description.createTestDescription( + ChildClass.class, "testB", + ChildClass.class.getMethod("testB").getAnnotations()); + JSONObject json = getTestMethodJSON(desc); + String expectedJsonString = + "{" + + "'method': 'testB'," + + "'annotations': {" + + " 'Add': {" + + " 'value': ['world']" + + " }" + + " }" + + "}"; + expectedJsonString = expectedJsonString + .replaceAll("\\s", "") + .replaceAll("'", "\""); + Assert.assertEquals(expectedJsonString, json.toString()); + } + + @Test + public void testGetAnnotationJSONForParentClass() throws Throwable { + JSONObject json = getAnnotationJSON(Arrays.asList(ParentClass.class.getAnnotations())); + String expectedJsonString = "{'Add':{'value':['hello']}}"; + expectedJsonString = expectedJsonString + .replaceAll("\\s", "") + .replaceAll("'", "\""); + Assert.assertEquals(expectedJsonString, json.toString()); + } + + @Test + public void testGetAnnotationJSONForChildClass() throws Throwable { + JSONObject json = getAnnotationJSON(Arrays.asList(ChildClass.class.getAnnotations())); + String expectedJsonString = "{'Add':{'value':['hello']},'Remove':{'value':['hello']}}"; + expectedJsonString = expectedJsonString + .replaceAll("\\s", "") + .replaceAll("'", "\""); + Assert.assertEquals(expectedJsonString, json.toString()); + } +} + diff --git a/base/test/android/junit/src/org/chromium/base/test/asynctask/BackgroundShadowAsyncTask.java b/base/test/android/junit/src/org/chromium/base/test/asynctask/BackgroundShadowAsyncTask.java new file mode 100644 index 0000000000..c75e7948f0 --- /dev/null +++ b/base/test/android/junit/src/org/chromium/base/test/asynctask/BackgroundShadowAsyncTask.java @@ -0,0 +1,72 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.base.test.asynctask; + +import static org.junit.Assert.fail; + +import org.robolectric.annotation.Implementation; +import org.robolectric.annotation.Implements; +import org.robolectric.shadows.ShadowApplication; + +import org.chromium.base.AsyncTask; + +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +/** + * Executes async tasks on a background thread and waits on the result on the main thread. + * This is useful for users of AsyncTask on Roboelectric who check if the code is actually being + * run on a background thread (i.e. through the use of {@link ThreadUtils#runningOnUiThread()}). + * @param <Params> type for execute function parameters + * @param <Progress> type for reporting Progress + * @param <Result> type for reporting result + */ +@Implements(AsyncTask.class) +public class BackgroundShadowAsyncTask<Params, Progress, Result> + extends ShadowAsyncTask<Params, Progress, Result> { + private static final ExecutorService sExecutorService = Executors.newSingleThreadExecutor(); + + @Override + @Implementation + @SafeVarargs + public final AsyncTask<Params, Progress, Result> execute(final Params... params) { + try { + return sExecutorService + .submit(new Callable<AsyncTask<Params, Progress, Result>>() { + @Override + public AsyncTask<Params, Progress, Result> call() throws Exception { + return BackgroundShadowAsyncTask.super.execute(params); + } + }) + .get(); + } catch (Exception ex) { + fail(ex.getMessage()); + return null; + } + } + + @Override + @Implementation + public final Result get() { + try { + runBackgroundTasks(); + return BackgroundShadowAsyncTask.super.get(); + } catch (Exception e) { + return null; + } + } + + public static void runBackgroundTasks() throws Exception { + sExecutorService + .submit(new Runnable() { + @Override + public void run() { + ShadowApplication.runBackgroundTasks(); + } + }) + .get(); + } +} diff --git a/base/test/android/junit/src/org/chromium/base/test/asynctask/CustomShadowAsyncTask.java b/base/test/android/junit/src/org/chromium/base/test/asynctask/CustomShadowAsyncTask.java new file mode 100644 index 0000000000..bd581c1377 --- /dev/null +++ b/base/test/android/junit/src/org/chromium/base/test/asynctask/CustomShadowAsyncTask.java @@ -0,0 +1,32 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.base.test.asynctask; + +import org.robolectric.annotation.Implementation; +import org.robolectric.annotation.Implements; + +import org.chromium.base.AsyncTask; + +import java.util.concurrent.Executor; + +/** + * Forces async tasks to execute with the default executor. + * This works around Robolectric not working out of the box with custom executors. + * + * @param <Params> + * @param <Progress> + * @param <Result> + */ +@Implements(AsyncTask.class) +public class CustomShadowAsyncTask<Params, Progress, Result> + extends ShadowAsyncTask<Params, Progress, Result> { + @SafeVarargs + @Override + @Implementation + public final AsyncTask<Params, Progress, Result> executeOnExecutor( + Executor executor, Params... params) { + return super.execute(params); + } +} diff --git a/base/test/android/junit/src/org/chromium/base/test/params/ExampleParameterizedTest.java b/base/test/android/junit/src/org/chromium/base/test/params/ExampleParameterizedTest.java new file mode 100644 index 0000000000..6ffccad44b --- /dev/null +++ b/base/test/android/junit/src/org/chromium/base/test/params/ExampleParameterizedTest.java @@ -0,0 +1,105 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.base.test.params; + +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.MethodRule; +import org.junit.runner.RunWith; + +import org.chromium.base.test.params.ParameterAnnotations.ClassParameter; +import org.chromium.base.test.params.ParameterAnnotations.UseMethodParameter; +import org.chromium.base.test.params.ParameterAnnotations.UseMethodParameterAfter; +import org.chromium.base.test.params.ParameterAnnotations.UseMethodParameterBefore; +import org.chromium.base.test.params.ParameterAnnotations.UseRunnerDelegate; + +import java.util.Arrays; +import java.util.List; + +/** + * Example test that uses ParameterizedRunner + */ +@RunWith(ParameterizedRunner.class) +@UseRunnerDelegate(BlockJUnit4RunnerDelegate.class) +public class ExampleParameterizedTest { + @ClassParameter + private static List<ParameterSet> sClassParams = + Arrays.asList(new ParameterSet().value("hello", "world").name("HelloWorld"), + new ParameterSet().value("Xxxx", "Yyyy").name("XxxxYyyy"), + new ParameterSet().value("aa", "yy").name("AaYy")); + + public static class MethodParamsA implements ParameterProvider { + private static List<ParameterSet> sMethodParamA = + Arrays.asList(new ParameterSet().value(1, 2).name("OneTwo"), + new ParameterSet().value(2, 3).name("TwoThree"), + new ParameterSet().value(3, 4).name("ThreeFour")); + + @Override + public List<ParameterSet> getParameters() { + return sMethodParamA; + } + } + + public static class MethodParamsB implements ParameterProvider { + private static List<ParameterSet> sMethodParamB = + Arrays.asList(new ParameterSet().value("a", "b").name("Ab"), + new ParameterSet().value("b", "c").name("Bc"), + new ParameterSet().value("c", "d").name("Cd"), + new ParameterSet().value("d", "e").name("De")); + + @Override + public List<ParameterSet> getParameters() { + return sMethodParamB; + } + } + + private String mStringA; + private String mStringB; + + public ExampleParameterizedTest(String a, String b) { + mStringA = a; + mStringB = b; + } + + @Test + public void testSimple() { + Assert.assertEquals( + "A and B string length aren't equal", mStringA.length(), mStringB.length()); + } + + @Rule + public MethodRule mMethodParamAnnotationProcessor = new MethodParamAnnotationRule(); + + private Integer mSum; + + @UseMethodParameterBefore(MethodParamsA.class) + public void setupWithOnlyA(int intA, int intB) { + mSum = intA + intB; + } + + @Test + @UseMethodParameter(MethodParamsA.class) + public void testWithOnlyA(int intA, int intB) { + Assert.assertEquals(intA + 1, intB); + Assert.assertEquals(mSum, Integer.valueOf(intA + intB)); + mSum = null; + } + + private String mConcatenation; + + @Test + @UseMethodParameter(MethodParamsB.class) + public void testWithOnlyB(String a, String b) { + Assert.assertTrue(!a.equals(b)); + mConcatenation = a + b; + } + + @UseMethodParameterAfter(MethodParamsB.class) + public void teardownWithOnlyB(String a, String b) { + Assert.assertEquals(mConcatenation, a + b); + mConcatenation = null; + } +} diff --git a/base/test/android/junit/src/org/chromium/base/test/params/ParameterizedRunnerDelegateCommonTest.java b/base/test/android/junit/src/org/chromium/base/test/params/ParameterizedRunnerDelegateCommonTest.java new file mode 100644 index 0000000000..6d854c57e6 --- /dev/null +++ b/base/test/android/junit/src/org/chromium/base/test/params/ParameterizedRunnerDelegateCommonTest.java @@ -0,0 +1,77 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.base.test.params; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.BlockJUnit4ClassRunner; +import org.junit.runners.model.TestClass; + +import org.chromium.base.test.params.ParameterizedRunner.ParameterizedTestInstantiationException; + +import java.util.Collections; + +@RunWith(BlockJUnit4ClassRunner.class) +public class ParameterizedRunnerDelegateCommonTest { + /** + * Create a test object using the list of class parameter set + * + * @param testClass the {@link TestClass} object for current test class + * @param classParameterSet the parameter set needed for the test class constructor + */ + private static Object createTest(TestClass testClass, ParameterSet classParameterSet) + throws ParameterizedTestInstantiationException { + return new ParameterizedRunnerDelegateCommon( + testClass, classParameterSet, Collections.emptyList()) + .createTest(); + } + + static class BadTestClassWithMoreThanOneConstructor { + public BadTestClassWithMoreThanOneConstructor() {} + @SuppressWarnings("unused") + public BadTestClassWithMoreThanOneConstructor(String argument) {} + } + + static class BadTestClassWithTwoArgumentConstructor { + @SuppressWarnings("unused") + public BadTestClassWithTwoArgumentConstructor(int a, int b) {} + } + + static abstract class BadTestClassAbstract { + public BadTestClassAbstract() {} + } + + static class BadTestClassConstructorThrows { + public BadTestClassConstructorThrows() { + throw new RuntimeException(); + } + } + + @Test(expected = IllegalArgumentException.class) + public void testCreateTestWithMoreThanOneConstructor() throws Throwable { + TestClass testClass = new TestClass(BadTestClassWithMoreThanOneConstructor.class); + createTest(testClass, null); + } + + @Test(expected = IllegalArgumentException.class) + public void testCreateTestWithIncorrectArguments() throws Throwable { + TestClass testClass = new TestClass(BadTestClassWithTwoArgumentConstructor.class); + ParameterSet pSet = new ParameterSet().value(1, 2, 3); + createTest(testClass, pSet); + } + + @Test(expected = ParameterizedTestInstantiationException.class) + public void testCreateTestWithAbstractClass() throws ParameterizedTestInstantiationException { + TestClass testClass = new TestClass(BadTestClassAbstract.class); + createTest(testClass, null); + } + + @Test(expected = ParameterizedTestInstantiationException.class) + public void testCreateTestWithThrowingConstructor() + throws ParameterizedTestInstantiationException { + TestClass testClass = new TestClass(BadTestClassConstructorThrows.class); + createTest(testClass, null); + } +} diff --git a/base/test/android/junit/src/org/chromium/base/test/params/ParameterizedRunnerDelegateFactoryTest.java b/base/test/android/junit/src/org/chromium/base/test/params/ParameterizedRunnerDelegateFactoryTest.java new file mode 100644 index 0000000000..723382d71d --- /dev/null +++ b/base/test/android/junit/src/org/chromium/base/test/params/ParameterizedRunnerDelegateFactoryTest.java @@ -0,0 +1,133 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.base.test.params; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.BlockJUnit4ClassRunner; +import org.junit.runners.model.FrameworkMethod; +import org.junit.runners.model.InitializationError; +import org.junit.runners.model.TestClass; + +import org.chromium.base.test.params.ParameterAnnotations.UseMethodParameter; +import org.chromium.base.test.params.ParameterizedRunnerDelegateFactory.ParameterizedRunnerDelegateInstantiationException; + +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Test for org.chromium.base.test.params.ParameterizedRunnerDelegateFactory + */ +@RunWith(BlockJUnit4ClassRunner.class) +public class ParameterizedRunnerDelegateFactoryTest { + /** + * This RunnerDelegate calls `super.collectInitializationErrors()` and would + * cause BlockJUnit4ClassRunner to validate test classes. + */ + public static class BadExampleRunnerDelegate + extends BlockJUnit4ClassRunner implements ParameterizedRunnerDelegate { + public static class LalaTestClass {} + + private final List<FrameworkMethod> mParameterizedFrameworkMethodList; + + BadExampleRunnerDelegate(Class<?> klass, + List<FrameworkMethod> parameterizedFrameworkMethods) throws InitializationError { + super(klass); + mParameterizedFrameworkMethodList = parameterizedFrameworkMethods; + } + + @Override + public void collectInitializationErrors(List<Throwable> errors) { + super.collectInitializationErrors(errors); // This is wrong!! + } + + @Override + public List<FrameworkMethod> computeTestMethods() { + return mParameterizedFrameworkMethodList; + } + + @Override + public Object createTest() { + return null; + } + } + + static class ExampleTestClass { + static class MethodParamsA implements ParameterProvider { + @Override + public Iterable<ParameterSet> getParameters() { + return Arrays.asList( + new ParameterSet().value("a").name("testWithValue_a"), + new ParameterSet().value("b").name("testWithValue_b") + ); + } + } + + @SuppressWarnings("unused") + @UseMethodParameter(MethodParamsA.class) + @Test + public void testA(String a) {} + + static class MethodParamsB implements ParameterProvider { + @Override + public Iterable<ParameterSet> getParameters() { + return Arrays.asList( + new ParameterSet().value(1).name("testWithValue_1"), + new ParameterSet().value(2).name("testWithValue_2"), + new ParameterSet().value(3).name("testWithValue_3") + ); + } + } + + @SuppressWarnings("unused") + @UseMethodParameter(MethodParamsB.class) + @Test + public void testB(int b) {} + + @Test + public void testByMyself() {} + } + + /** + * This test validates ParameterizedRunnerDelegateFactory throws exception when + * a runner delegate does not override the collectInitializationErrors method. + */ + @Test(expected = ParameterizedRunnerDelegateInstantiationException.class) + public void testBadRunnerDelegateWithIncorrectValidationCall() throws Throwable { + ParameterizedRunnerDelegateFactory factory = new ParameterizedRunnerDelegateFactory(); + TestClass testClass = new TestClass(BadExampleRunnerDelegate.LalaTestClass.class); + factory.createRunner(testClass, null, BadExampleRunnerDelegate.class); + } + + @Test + public void testGenerateParameterizedFrameworkMethod() throws Throwable { + List<FrameworkMethod> methods = + ParameterizedRunnerDelegateFactory.generateUnmodifiableFrameworkMethodList( + new TestClass(ExampleTestClass.class), ""); + + Assert.assertEquals(methods.size(), 6); + + Map<String, Method> expectedTests = new HashMap<>(); + Method testMethodA = ExampleTestClass.class.getDeclaredMethod("testA", String.class); + Method testMethodB = ExampleTestClass.class.getDeclaredMethod("testB", int.class); + Method testMethodByMyself = ExampleTestClass.class.getDeclaredMethod("testByMyself"); + expectedTests.put("testA__testWithValue_a", testMethodA); + expectedTests.put("testA__testWithValue_b", testMethodA); + expectedTests.put("testB__testWithValue_1", testMethodB); + expectedTests.put("testB__testWithValue_2", testMethodB); + expectedTests.put("testB__testWithValue_3", testMethodB); + expectedTests.put("testByMyself", testMethodByMyself); + for (FrameworkMethod method : methods) { + Assert.assertNotNull(expectedTests.get(method.getName())); + Assert.assertEquals(expectedTests.get(method.getName()), method.getMethod()); + expectedTests.remove(method.getName()); + } + Assert.assertTrue(expectedTests.isEmpty()); + } +} diff --git a/base/test/android/junit/src/org/chromium/base/test/params/ParameterizedRunnerTest.java b/base/test/android/junit/src/org/chromium/base/test/params/ParameterizedRunnerTest.java new file mode 100644 index 0000000000..170ff69eaf --- /dev/null +++ b/base/test/android/junit/src/org/chromium/base/test/params/ParameterizedRunnerTest.java @@ -0,0 +1,108 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.base.test.params; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.BlockJUnit4ClassRunner; + +import org.chromium.base.test.params.ParameterAnnotations.ClassParameter; +import org.chromium.base.test.params.ParameterAnnotations.UseRunnerDelegate; +import org.chromium.base.test.params.ParameterizedRunner.IllegalParameterArgumentException; + +import java.util.ArrayList; +import java.util.List; + +/** + * Test for org.chromium.base.test.params.ParameterizedRunner + */ +@RunWith(BlockJUnit4ClassRunner.class) +public class ParameterizedRunnerTest { + @UseRunnerDelegate(BlockJUnit4RunnerDelegate.class) + public static class BadTestClassWithMoreThanOneConstructor { + @ClassParameter + static List<ParameterSet> sClassParams = new ArrayList<>(); + + public BadTestClassWithMoreThanOneConstructor() {} + + public BadTestClassWithMoreThanOneConstructor(String x) {} + } + + @UseRunnerDelegate(BlockJUnit4RunnerDelegate.class) + public static class BadTestClassWithNonListParameters { + @ClassParameter + static String[] sMethodParamA = {"1", "2"}; + + @Test + public void test() {} + } + + @UseRunnerDelegate(BlockJUnit4RunnerDelegate.class) + public static class BadTestClassWithoutNeedForParameterization { + @Test + public void test() {} + } + + @UseRunnerDelegate(BlockJUnit4RunnerDelegate.class) + public static class BadTestClassWithNonStaticParameterSetList { + @ClassParameter + public List<ParameterSet> mClassParams = new ArrayList<>(); + + @Test + public void test() {} + } + + @UseRunnerDelegate(BlockJUnit4RunnerDelegate.class) + public static class BadTestClassWithMultipleClassParameter { + @ClassParameter + private static List<ParameterSet> sParamA = new ArrayList<>(); + + @ClassParameter + private static List<ParameterSet> sParamB = new ArrayList<>(); + } + + @Test(expected = ParameterizedRunner.IllegalParameterArgumentException.class) + public void testEmptyParameterSet() { + List<ParameterSet> paramList = new ArrayList<>(); + paramList.add(new ParameterSet()); + ParameterizedRunner.validateWidth(paramList); + } + + @Test(expected = ParameterizedRunner.IllegalParameterArgumentException.class) + public void testUnequalWidthParameterSetList() { + List<ParameterSet> paramList = new ArrayList<>(); + paramList.add(new ParameterSet().value(1, 2)); + paramList.add(new ParameterSet().value(3, 4, 5)); + ParameterizedRunner.validateWidth(paramList); + } + + @Test(expected = ParameterizedRunner.IllegalParameterArgumentException.class) + public void testUnequalWidthParameterSetListWithNull() { + List<ParameterSet> paramList = new ArrayList<>(); + paramList.add(new ParameterSet().value(null)); + paramList.add(new ParameterSet().value(1, 2)); + ParameterizedRunner.validateWidth(paramList); + } + + @Test(expected = IllegalArgumentException.class) + public void testBadClassWithNonListParameters() throws Throwable { + new ParameterizedRunner(BadTestClassWithNonListParameters.class); + } + + @Test(expected = IllegalParameterArgumentException.class) + public void testBadClassWithNonStaticParameterSetList() throws Throwable { + new ParameterizedRunner(BadTestClassWithNonStaticParameterSetList.class); + } + + @Test(expected = IllegalArgumentException.class) + public void testBadClassWithoutNeedForParameterization() throws Throwable { + new ParameterizedRunner(BadTestClassWithoutNeedForParameterization.class); + } + + @Test(expected = Exception.class) + public void testBadClassWithMoreThanOneConstructor() throws Throwable { + new ParameterizedRunner(BadTestClassWithMoreThanOneConstructor.class); + } +} diff --git a/base/test/android/junit/src/org/chromium/base/test/params/ParameterizedTestNameTest.java b/base/test/android/junit/src/org/chromium/base/test/params/ParameterizedTestNameTest.java new file mode 100644 index 0000000000..e79f5c5304 --- /dev/null +++ b/base/test/android/junit/src/org/chromium/base/test/params/ParameterizedTestNameTest.java @@ -0,0 +1,201 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.base.test.params; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runner.Runner; +import org.junit.runners.BlockJUnit4ClassRunner; +import org.junit.runners.model.FrameworkMethod; +import org.junit.runners.model.TestClass; + +import org.chromium.base.test.params.ParameterAnnotations.ClassParameter; +import org.chromium.base.test.params.ParameterAnnotations.UseMethodParameter; +import org.chromium.base.test.params.ParameterAnnotations.UseRunnerDelegate; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; + +/** + * Test for verify the names and test method Description works properly + */ +@RunWith(BlockJUnit4ClassRunner.class) +public class ParameterizedTestNameTest { + @UseRunnerDelegate(BlockJUnit4RunnerDelegate.class) + public static class TestClassWithClassParameterAppendName { + @ClassParameter + static List<ParameterSet> sAllName = Arrays.asList( + new ParameterSet().value("hello").name("Hello"), + new ParameterSet().value("world").name("World") + ); + + public TestClassWithClassParameterAppendName(String a) {} + + @Test + public void test() {} + } + + @UseRunnerDelegate(BlockJUnit4RunnerDelegate.class) + public static class TestClassWithClassParameterDefaultName { + @ClassParameter + static List<ParameterSet> sAllName = Arrays.asList( + new ParameterSet().value("hello"), + new ParameterSet().value("world") + ); + + public TestClassWithClassParameterDefaultName(String a) {} + + @Test + public void test() {} + } + + @UseRunnerDelegate(BlockJUnit4RunnerDelegate.class) + public static class TestClassWithMethodParameter { + static class AppendNameParams implements ParameterProvider { + @Override + public Iterable<ParameterSet> getParameters() { + return Arrays.asList( + new ParameterSet().value("hello").name("Hello"), + new ParameterSet().value("world").name("World") + ); + } + } + + static class DefaultNameParams implements ParameterProvider { + @Override + public Iterable<ParameterSet> getParameters() { + return Arrays.asList( + new ParameterSet().value("hello"), + new ParameterSet().value("world") + ); + } + } + + @UseMethodParameter(AppendNameParams.class) + @Test + public void test(String a) {} + + @UseMethodParameter(DefaultNameParams.class) + @Test + public void testDefaultName(String b) {} + } + + @UseRunnerDelegate(BlockJUnit4RunnerDelegate.class) + public static class TestClassWithMixedParameter { + @ClassParameter + static List<ParameterSet> sAllName = Arrays.asList( + new ParameterSet().value("hello").name("Hello"), + new ParameterSet().value("world").name("World") + ); + + static class AppendNameParams implements ParameterProvider { + @Override + public Iterable<ParameterSet> getParameters() { + return Arrays.asList( + new ParameterSet().value("1").name("A"), + new ParameterSet().value("2").name("B") + ); + } + } + + public TestClassWithMixedParameter(String a) {} + + @UseMethodParameter(AppendNameParams.class) + @Test + public void testA(String a) {} + + @Test + public void test() {} + } + + @Test + public void testClassParameterAppendName() throws Throwable { + List<Runner> runners = ParameterizedRunner.createRunners( + new TestClass(TestClassWithClassParameterAppendName.class)); + List<String> expectedTestNames = + new LinkedList<String>(Arrays.asList("test__Hello", "test__World")); + List<String> computedMethodNames = new ArrayList<>(); + for (Runner r : runners) { + BlockJUnit4RunnerDelegate castedRunner = (BlockJUnit4RunnerDelegate) r; + for (FrameworkMethod method : castedRunner.computeTestMethods()) { + computedMethodNames.add(method.getName()); + Assert.assertTrue("This test name is not expected: " + method.getName(), + expectedTestNames.contains(method.getName())); + expectedTestNames.remove(method.getName()); + method.getName(); + } + } + Assert.assertTrue( + String.format( + "These names were provided: %s, these expected names are not found: %s", + Arrays.toString(computedMethodNames.toArray()), + Arrays.toString(expectedTestNames.toArray())), + expectedTestNames.isEmpty()); + } + + @Test + public void testClassParameterDefaultName() throws Throwable { + List<Runner> runners = ParameterizedRunner.createRunners( + new TestClass(TestClassWithClassParameterDefaultName.class)); + List<String> expectedTestNames = new LinkedList<String>(Arrays.asList("test", "test")); + for (Runner r : runners) { + @SuppressWarnings("unchecked") + BlockJUnit4RunnerDelegate castedRunner = (BlockJUnit4RunnerDelegate) r; + for (FrameworkMethod method : castedRunner.computeTestMethods()) { + Assert.assertTrue("This test name is not expected: " + method.getName(), + expectedTestNames.contains(method.getName())); + expectedTestNames.remove(method.getName()); + method.getName(); + } + } + Assert.assertTrue("These expected names are not found: " + + Arrays.toString(expectedTestNames.toArray()), + expectedTestNames.isEmpty()); + } + + @Test + public void testMethodParameter() throws Throwable { + List<Runner> runners = ParameterizedRunner.createRunners( + new TestClass(TestClassWithMethodParameter.class)); + List<String> expectedTestNames = new LinkedList<String>( + Arrays.asList("test__Hello", "test__World", "testDefaultName", "testDefaultName")); + for (Runner r : runners) { + BlockJUnit4RunnerDelegate castedRunner = (BlockJUnit4RunnerDelegate) r; + for (FrameworkMethod method : castedRunner.computeTestMethods()) { + Assert.assertTrue("This test name is not expected: " + method.getName(), + expectedTestNames.contains(method.getName())); + expectedTestNames.remove(method.getName()); + method.getName(); + } + } + Assert.assertTrue("These expected names are not found: " + + Arrays.toString(expectedTestNames.toArray()), + expectedTestNames.isEmpty()); + } + + @Test + public void testMixedParameterTestA() throws Throwable { + List<Runner> runners = + ParameterizedRunner.createRunners(new TestClass(TestClassWithMixedParameter.class)); + List<String> expectedTestNames = + new LinkedList<String>(Arrays.asList("testA__Hello_A", "testA__World_A", + "testA__Hello_B", "testA__World_B", "test__Hello", "test__World")); + for (Runner r : runners) { + BlockJUnit4RunnerDelegate castedRunner = (BlockJUnit4RunnerDelegate) r; + for (FrameworkMethod method : castedRunner.computeTestMethods()) { + Assert.assertTrue("This test name is not expected: " + method.getName(), + expectedTestNames.contains(method.getName())); + expectedTestNames.remove(method.getName()); + method.getName(); + } + } + Assert.assertTrue("These expected names are not found: " + + Arrays.toString(expectedTestNames.toArray()), + expectedTestNames.isEmpty()); + } +} diff --git a/base/test/android/junit/src/org/chromium/base/test/util/DisableIfTest.java b/base/test/android/junit/src/org/chromium/base/test/util/DisableIfTest.java new file mode 100644 index 0000000000..a147435355 --- /dev/null +++ b/base/test/android/junit/src/org/chromium/base/test/util/DisableIfTest.java @@ -0,0 +1,193 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.base.test.util; + +import android.os.Build; + +import junit.framework.TestCase; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.annotation.Config; +import org.robolectric.util.ReflectionHelpers; + +import org.chromium.base.test.BaseRobolectricTestRunner; + +/** Unit tests for the DisableIf annotation and its SkipCheck implementation. */ +@RunWith(BaseRobolectricTestRunner.class) +@Config(manifest = Config.NONE, sdk = 21) +public class DisableIfTest { + @Test + public void testSdkIsLessThanAndIsLessThan() { + TestCase sdkIsLessThan = new TestCase("sdkIsLessThan") { + @DisableIf.Build(sdk_is_less_than = 22) + public void sdkIsLessThan() {} + }; + Assert.assertTrue(new DisableIfSkipCheck().shouldSkip(sdkIsLessThan)); + } + + @Test + public void testSdkIsLessThanButIsEqual() { + TestCase sdkIsEqual = new TestCase("sdkIsEqual") { + @DisableIf.Build(sdk_is_less_than = 21) + public void sdkIsEqual() {} + }; + Assert.assertFalse(new DisableIfSkipCheck().shouldSkip(sdkIsEqual)); + } + + @Test + public void testSdkIsLessThanButIsGreaterThan() { + TestCase sdkIsGreaterThan = new TestCase("sdkIsGreaterThan") { + @DisableIf.Build(sdk_is_less_than = 20) + public void sdkIsGreaterThan() {} + }; + Assert.assertFalse(new DisableIfSkipCheck().shouldSkip(sdkIsGreaterThan)); + } + + @Test + public void testSdkIsGreaterThanButIsLessThan() { + TestCase sdkIsLessThan = new TestCase("sdkIsLessThan") { + @DisableIf.Build(sdk_is_greater_than = 22) + public void sdkIsLessThan() {} + }; + Assert.assertFalse(new DisableIfSkipCheck().shouldSkip(sdkIsLessThan)); + } + + @Test + public void testSdkIsGreaterThanButIsEqual() { + TestCase sdkIsEqual = new TestCase("sdkIsEqual") { + @DisableIf.Build(sdk_is_greater_than = 21) + public void sdkIsEqual() {} + }; + Assert.assertFalse(new DisableIfSkipCheck().shouldSkip(sdkIsEqual)); + } + + @Test + public void testSdkIsGreaterThanAndIsGreaterThan() { + TestCase sdkIsGreaterThan = new TestCase("sdkIsGreaterThan") { + @DisableIf.Build(sdk_is_greater_than = 20) + public void sdkIsGreaterThan() {} + }; + Assert.assertTrue(new DisableIfSkipCheck().shouldSkip(sdkIsGreaterThan)); + } + + @Test + public void testSupportedAbiIncludesAndCpuAbiMatches() { + TestCase supportedAbisCpuAbiMatch = new TestCase("supportedAbisCpuAbiMatch") { + @DisableIf.Build(supported_abis_includes = "foo") + public void supportedAbisCpuAbiMatch() {} + }; + String[] originalAbis = Build.SUPPORTED_ABIS; + try { + ReflectionHelpers.setStaticField(Build.class, "SUPPORTED_ABIS", + new String[] {"foo", "bar"}); + Assert.assertTrue(new DisableIfSkipCheck().shouldSkip(supportedAbisCpuAbiMatch)); + } finally { + ReflectionHelpers.setStaticField(Build.class, "SUPPORTED_ABIS", originalAbis); + } + } + + @Test + public void testSupportedAbiIncludesAndCpuAbi2Matches() { + TestCase supportedAbisCpuAbi2Match = new TestCase("supportedAbisCpuAbi2Match") { + @DisableIf.Build(supported_abis_includes = "bar") + public void supportedAbisCpuAbi2Match() {} + }; + String[] originalAbis = Build.SUPPORTED_ABIS; + try { + ReflectionHelpers.setStaticField(Build.class, "SUPPORTED_ABIS", + new String[] {"foo", "bar"}); + Assert.assertTrue(new DisableIfSkipCheck().shouldSkip(supportedAbisCpuAbi2Match)); + } finally { + ReflectionHelpers.setStaticField(Build.class, "SUPPORTED_ABIS", originalAbis); + } + } + + @Test + public void testSupportedAbiIncludesButNoMatch() { + TestCase supportedAbisNoMatch = new TestCase("supportedAbisNoMatch") { + @DisableIf.Build(supported_abis_includes = "baz") + public void supportedAbisNoMatch() {} + }; + String[] originalAbis = Build.SUPPORTED_ABIS; + try { + ReflectionHelpers.setStaticField(Build.class, "SUPPORTED_ABIS", + new String[] {"foo", "bar"}); + Assert.assertFalse(new DisableIfSkipCheck().shouldSkip(supportedAbisNoMatch)); + } finally { + ReflectionHelpers.setStaticField(Build.class, "SUPPORTED_ABIS", originalAbis); + } + } + + @Test + public void testHardwareIsMatches() { + TestCase hardwareIsMatches = new TestCase("hardwareIsMatches") { + @DisableIf.Build(hardware_is = "hammerhead") + public void hardwareIsMatches() {} + }; + String originalHardware = Build.HARDWARE; + try { + ReflectionHelpers.setStaticField(Build.class, "HARDWARE", "hammerhead"); + Assert.assertTrue(new DisableIfSkipCheck().shouldSkip(hardwareIsMatches)); + } finally { + ReflectionHelpers.setStaticField(Build.class, "HARDWARE", originalHardware); + } + } + + @Test + public void testHardwareIsDoesntMatch() { + TestCase hardwareIsDoesntMatch = new TestCase("hardwareIsDoesntMatch") { + @DisableIf.Build(hardware_is = "hammerhead") + public void hardwareIsDoesntMatch() {} + }; + String originalHardware = Build.HARDWARE; + try { + ReflectionHelpers.setStaticField(Build.class, "HARDWARE", "mako"); + Assert.assertFalse(new DisableIfSkipCheck().shouldSkip(hardwareIsDoesntMatch)); + } finally { + ReflectionHelpers.setStaticField(Build.class, "HARDWARE", originalHardware); + } + } + + @DisableIf.Build(supported_abis_includes = "foo") + private static class DisableIfSuperclassTestCase extends TestCase { + public DisableIfSuperclassTestCase(String name) { + super(name); + } + } + + @DisableIf.Build(hardware_is = "hammerhead") + private static class DisableIfTestCase extends DisableIfSuperclassTestCase { + public DisableIfTestCase(String name) { + super(name); + } + public void sampleTestMethod() {} + } + + @Test + public void testDisableClass() { + TestCase sampleTestMethod = new DisableIfTestCase("sampleTestMethod"); + String originalHardware = Build.HARDWARE; + try { + ReflectionHelpers.setStaticField(Build.class, "HARDWARE", "hammerhead"); + Assert.assertTrue(new DisableIfSkipCheck().shouldSkip(sampleTestMethod)); + } finally { + ReflectionHelpers.setStaticField(Build.class, "HARDWARE", originalHardware); + } + } + + @Test + public void testDisableSuperClass() { + TestCase sampleTestMethod = new DisableIfTestCase("sampleTestMethod"); + String[] originalAbis = Build.SUPPORTED_ABIS; + try { + ReflectionHelpers.setStaticField(Build.class, "SUPPORTED_ABIS", new String[] {"foo"}); + Assert.assertTrue(new DisableIfSkipCheck().shouldSkip(sampleTestMethod)); + } finally { + ReflectionHelpers.setStaticField(Build.class, "SUPPORTED_ABIS", originalAbis); + } + } +} diff --git a/base/test/android/junit/src/org/chromium/base/test/util/MinAndroidSdkLevelSkipCheckTest.java b/base/test/android/junit/src/org/chromium/base/test/util/MinAndroidSdkLevelSkipCheckTest.java new file mode 100644 index 0000000000..2236646938 --- /dev/null +++ b/base/test/android/junit/src/org/chromium/base/test/util/MinAndroidSdkLevelSkipCheckTest.java @@ -0,0 +1,95 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.base.test.util; + +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.isIn; + +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.Description; +import org.junit.runner.RunWith; +import org.junit.runners.model.FrameworkMethod; +import org.robolectric.annotation.Config; + +import org.chromium.base.test.BaseJUnit4ClassRunner; +import org.chromium.base.test.BaseRobolectricTestRunner; + +/** Unit tests for MinAndroidSdkLevelSkipCheck. */ +@RunWith(BaseRobolectricTestRunner.class) +@Config(manifest = Config.NONE, sdk = 18) +public class MinAndroidSdkLevelSkipCheckTest { + public static class UnannotatedBaseClass { + @Test @MinAndroidSdkLevel(17) public void min17Method() {} + @Test @MinAndroidSdkLevel(20) public void min20Method() {} + } + + @MinAndroidSdkLevel(17) + public static class Min17Class extends UnannotatedBaseClass { + @Test public void unannotatedMethod() {} + } + + @MinAndroidSdkLevel(20) + public static class Min20Class extends UnannotatedBaseClass { + @Test public void unannotatedMethod() {} + } + + public static class ExtendsMin17Class extends Min17Class { + @Override + @Test public void unannotatedMethod() {} + } + + public static class ExtendsMin20Class extends Min20Class { + @Override + @Test public void unannotatedMethod() {} + } + + private MinAndroidSdkLevelSkipCheck mSkipCheck = new MinAndroidSdkLevelSkipCheck(); + + @Rule + public TestRunnerTestRule mTestRunnerTestRule = + new TestRunnerTestRule(BaseJUnit4ClassRunner.class); + + private void expectShouldSkip(Class<?> testClass, String methodName, boolean shouldSkip) + throws Exception { + Assert.assertThat( + mSkipCheck.shouldSkip(new FrameworkMethod(testClass.getMethod(methodName))), + equalTo(shouldSkip)); + TestRunnerTestRule.TestLog runListener = mTestRunnerTestRule.runTest(testClass); + Assert.assertThat(Description.createTestDescription(testClass, methodName), + isIn(shouldSkip ? runListener.skippedTests : runListener.runTests)); + } + + @Test + public void testAnnotatedMethodAboveMin() throws Exception { + expectShouldSkip(UnannotatedBaseClass.class, "min17Method", false); + } + + @Test + public void testAnnotatedMethodBelowMin() throws Exception { + expectShouldSkip(UnannotatedBaseClass.class, "min20Method", true); + } + + @Test + public void testAnnotatedClassAboveMin() throws Exception { + expectShouldSkip(Min17Class.class, "unannotatedMethod", false); + } + + @Test + public void testAnnotatedClassBelowMin() throws Exception { + expectShouldSkip(Min20Class.class, "unannotatedMethod", true); + } + + @Test + public void testAnnotatedSuperclassAboveMin() throws Exception { + expectShouldSkip(ExtendsMin17Class.class, "unannotatedMethod", false); + } + + @Test + public void testAnnotatedSuperclassBelowMin() throws Exception { + expectShouldSkip(ExtendsMin20Class.class, "unannotatedMethod", true); + } +} diff --git a/base/test/android/junit/src/org/chromium/base/test/util/RestrictionSkipCheckTest.java b/base/test/android/junit/src/org/chromium/base/test/util/RestrictionSkipCheckTest.java new file mode 100644 index 0000000000..86285de3f0 --- /dev/null +++ b/base/test/android/junit/src/org/chromium/base/test/util/RestrictionSkipCheckTest.java @@ -0,0 +1,129 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.base.test.util; + +import android.text.TextUtils; + +import junit.framework.TestCase; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.annotation.Config; + +import org.chromium.base.test.BaseRobolectricTestRunner; + +/** Unit tests for RestrictionSkipCheck. */ +@RunWith(BaseRobolectricTestRunner.class) +@Config(manifest = Config.NONE) +public class RestrictionSkipCheckTest { + private static final String TEST_RESTRICTION_APPLIES = + "org.chromium.base.test.util.RestrictionSkipCheckTest.TEST_RESTRICTION_APPLIES"; + private static final String TEST_RESTRICTION_DOES_NOT_APPLY = + "org.chromium.base.test.util.RestrictionSkipCheckTest.TEST_RESTRICTION_DOES_NOT_APPLY"; + + private static class TestRestrictionSkipCheck extends RestrictionSkipCheck { + public TestRestrictionSkipCheck() { + super(null); + } + @Override + protected boolean restrictionApplies(String restriction) { + return TextUtils.equals(restriction, TEST_RESTRICTION_APPLIES); + } + } + + private static class UnannotatedBaseClass extends TestCase { + public UnannotatedBaseClass(String name) { + super(name); + } + @Restriction({TEST_RESTRICTION_APPLIES}) public void restrictedMethod() {} + @Restriction({TEST_RESTRICTION_DOES_NOT_APPLY}) public void unrestrictedMethod() {} + } + + @Restriction({TEST_RESTRICTION_APPLIES}) + private static class RestrictedClass extends UnannotatedBaseClass { + public RestrictedClass(String name) { + super(name); + } + public void unannotatedMethod() {} + } + + @Restriction({TEST_RESTRICTION_DOES_NOT_APPLY}) + private static class UnrestrictedClass extends UnannotatedBaseClass { + public UnrestrictedClass(String name) { + super(name); + } + public void unannotatedMethod() {} + } + + @Restriction({ + TEST_RESTRICTION_APPLIES, + TEST_RESTRICTION_DOES_NOT_APPLY}) + private static class MultipleRestrictionsRestrictedClass extends UnannotatedBaseClass { + public MultipleRestrictionsRestrictedClass(String name) { + super(name); + } + public void unannotatedMethod() {} + } + + private static class ExtendsRestrictedClass extends RestrictedClass { + public ExtendsRestrictedClass(String name) { + super(name); + } + @Override + public void unannotatedMethod() {} + } + + private static class ExtendsUnrestrictedClass extends UnrestrictedClass { + public ExtendsUnrestrictedClass(String name) { + super(name); + } + @Override + public void unannotatedMethod() {} + } + + @Test + public void testMethodRestricted() { + Assert.assertTrue(new TestRestrictionSkipCheck().shouldSkip( + new UnannotatedBaseClass("restrictedMethod"))); + } + + @Test + public void testMethodUnrestricted() { + Assert.assertFalse(new TestRestrictionSkipCheck().shouldSkip( + new UnannotatedBaseClass("unrestrictedMethod"))); + } + + @Test + public void testClassRestricted() { + Assert.assertTrue(new TestRestrictionSkipCheck().shouldSkip( + new RestrictedClass("unannotatedMethod"))); + } + + @Test + public void testClassUnrestricted() { + Assert.assertFalse(new TestRestrictionSkipCheck().shouldSkip( + new UnrestrictedClass("unannotatedMethod"))); + } + + @Test + public void testMultipleRestrictionsClassRestricted() { + Assert.assertTrue(new TestRestrictionSkipCheck().shouldSkip( + new MultipleRestrictionsRestrictedClass("unannotatedMethod"))); + } + + @Test + public void testSuperclassRestricted() { + Assert.assertTrue(new TestRestrictionSkipCheck().shouldSkip( + new ExtendsRestrictedClass("unannotatedMethod"))); + } + + @Test + public void testSuperclassUnrestricted() { + Assert.assertFalse(new TestRestrictionSkipCheck().shouldSkip( + new ExtendsUnrestrictedClass("unannotatedMethod"))); + } +} + diff --git a/base/test/android/junit/src/org/chromium/base/test/util/SkipCheckTest.java b/base/test/android/junit/src/org/chromium/base/test/util/SkipCheckTest.java new file mode 100644 index 0000000000..51c7516e71 --- /dev/null +++ b/base/test/android/junit/src/org/chromium/base/test/util/SkipCheckTest.java @@ -0,0 +1,130 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.base.test.util; + +import junit.framework.TestCase; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.model.FrameworkMethod; +import org.robolectric.annotation.Config; + +import org.chromium.base.test.BaseRobolectricTestRunner; + +import java.lang.annotation.Annotation; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Method; +import java.util.List; + +/** Unit tests for SkipCheck. */ +@RunWith(BaseRobolectricTestRunner.class) +@Config(manifest = Config.NONE) +public class SkipCheckTest { + private static class TestableSkipCheck extends SkipCheck { + public static <T extends Annotation> List<T> getAnnotationsForTesting( + AnnotatedElement element, Class<T> annotationClass) { + return AnnotationProcessingUtils.getAnnotations(element, annotationClass); + } + + @Override + public boolean shouldSkip(FrameworkMethod m) { + return false; + } + } + + @Retention(RetentionPolicy.RUNTIME) + private @interface TestAnnotation {} + + @TestAnnotation + private class AnnotatedBaseClass { + public void unannotatedMethod() {} + @TestAnnotation public void annotatedMethod() {} + } + + private class ExtendsAnnotatedBaseClass extends AnnotatedBaseClass { + public void anotherUnannotatedMethod() {} + } + + private class ExtendsTestCaseClass extends TestCase { + public ExtendsTestCaseClass(String name) { + super(name); + } + public void testMethodA() {} + } + + private class UnannotatedBaseClass { + public void unannotatedMethod() {} + @TestAnnotation public void annotatedMethod() {} + } + + @Test + public void getAnnotationsForClassNone() { + List<TestAnnotation> annotations = TestableSkipCheck.getAnnotationsForTesting( + UnannotatedBaseClass.class, TestAnnotation.class); + Assert.assertEquals(0, annotations.size()); + } + + @Test + public void getAnnotationsForClassOnClass() { + List<TestAnnotation> annotations = TestableSkipCheck.getAnnotationsForTesting( + AnnotatedBaseClass.class, TestAnnotation.class); + Assert.assertEquals(1, annotations.size()); + } + + @Test + public void getAnnotationsForClassOnSuperclass() { + List<TestAnnotation> annotations = TestableSkipCheck.getAnnotationsForTesting( + ExtendsAnnotatedBaseClass.class, TestAnnotation.class); + Assert.assertEquals(1, annotations.size()); + } + + @Test + public void getAnnotationsForMethodNone() throws NoSuchMethodException { + Method testMethod = UnannotatedBaseClass.class.getMethod("unannotatedMethod", + (Class[]) null); + List<TestAnnotation> annotations = TestableSkipCheck.getAnnotationsForTesting( + testMethod, TestAnnotation.class); + Assert.assertEquals(0, annotations.size()); + } + + @Test + public void getAnnotationsForMethodOnMethod() throws NoSuchMethodException { + Method testMethod = UnannotatedBaseClass.class.getMethod("annotatedMethod", + (Class[]) null); + List<TestAnnotation> annotations = TestableSkipCheck.getAnnotationsForTesting( + testMethod, TestAnnotation.class); + Assert.assertEquals(1, annotations.size()); + } + + @Test + public void getAnnotationsForMethodOnClass() throws NoSuchMethodException { + Method testMethod = AnnotatedBaseClass.class.getMethod("unannotatedMethod", + (Class[]) null); + List<TestAnnotation> annotations = TestableSkipCheck.getAnnotationsForTesting( + testMethod, TestAnnotation.class); + Assert.assertEquals(1, annotations.size()); + } + + @Test + public void getAnnotationsForMethodOnSuperclass() throws NoSuchMethodException { + Method testMethod = ExtendsAnnotatedBaseClass.class.getMethod("unannotatedMethod", + (Class[]) null); + List<TestAnnotation> annotations = TestableSkipCheck.getAnnotationsForTesting( + testMethod, TestAnnotation.class); + Assert.assertEquals(1, annotations.size()); + } + + @Test + public void getAnnotationsOverlapping() throws NoSuchMethodException { + Method testMethod = AnnotatedBaseClass.class.getMethod("annotatedMethod", + (Class[]) null); + List<TestAnnotation> annotations = TestableSkipCheck.getAnnotationsForTesting( + testMethod, TestAnnotation.class); + Assert.assertEquals(2, annotations.size()); + } +} diff --git a/base/test/android/junit/src/org/chromium/base/test/util/TestRunnerTestRule.java b/base/test/android/junit/src/org/chromium/base/test/util/TestRunnerTestRule.java new file mode 100644 index 0000000000..64805c124e --- /dev/null +++ b/base/test/android/junit/src/org/chromium/base/test/util/TestRunnerTestRule.java @@ -0,0 +1,132 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.base.test.util; + +import static org.hamcrest.Matchers.isIn; +import static org.junit.Assert.fail; + +import android.app.Instrumentation; +import android.content.Context; +import android.os.Bundle; +import android.support.test.InstrumentationRegistry; + +import org.junit.Assert; +import org.junit.rules.ExternalResource; +import org.junit.runner.Description; +import org.junit.runner.Runner; +import org.junit.runner.notification.Failure; +import org.junit.runner.notification.RunListener; +import org.junit.runner.notification.RunNotifier; +import org.junit.runners.BlockJUnit4ClassRunner; +import org.junit.runners.model.InitializationError; +import org.robolectric.RuntimeEnvironment; + +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.List; + +/** + * Helper rule to allow executing test runners in tests. + * + * Quis probat ipsas probas? + */ +class TestRunnerTestRule extends ExternalResource { + final Class<? extends BlockJUnit4ClassRunner> mRunnerClass; + + /** + * @param runnerClass The runner class to run the test + */ + TestRunnerTestRule(Class<? extends BlockJUnit4ClassRunner> runnerClass) { + mRunnerClass = runnerClass; + } + + @Override + protected void before() throws Throwable { + // Register a fake Instrumentation so that class runners for instrumentation tests + // can be run even in Robolectric tests. + Instrumentation instrumentation = new Instrumentation() { + @Override + public Context getTargetContext() { + return RuntimeEnvironment.application; + } + }; + InstrumentationRegistry.registerInstance(instrumentation, new Bundle()); + } + + @Override + protected void after() { + InstrumentationRegistry.registerInstance(null, new Bundle()); + } + + /** + * A struct-like class containing lists of run and skipped tests. + */ + public static class TestLog { + public final List<Description> runTests = new ArrayList<>(); + public final List<Description> skippedTests = new ArrayList<>(); + } + + /** + * Creates a new test runner and executes the test in the given {@code testClass} on it, + * returning lists of tests that were run and tests that were skipped. + * @param testClass The test class + * @return A {@link TestLog} that contains lists of run and skipped tests. + */ + public TestLog runTest(Class<?> testClass) throws InvocationTargetException, + NoSuchMethodException, InstantiationException, + IllegalAccessException { + TestLog testLog = new TestLog(); + + // TODO(bauerb): Using Mockito mock() or spy() throws a ClassCastException. + RunListener runListener = new RunListener() { + @Override + public void testStarted(Description description) throws Exception { + testLog.runTests.add(description); + } + + @Override + public void testFinished(Description description) throws Exception { + Assert.assertThat(description, isIn(testLog.runTests)); + } + + @Override + public void testFailure(Failure failure) throws Exception { + fail(failure.toString()); + } + + @Override + public void testAssumptionFailure(Failure failure) { + fail(failure.toString()); + } + + @Override + public void testIgnored(Description description) throws Exception { + testLog.skippedTests.add(description); + } + }; + RunNotifier runNotifier = new RunNotifier(); + runNotifier.addListener(runListener); + Runner runner; + try { + runner = mRunnerClass.getConstructor(Class.class).newInstance(testClass); + } catch (InvocationTargetException e) { + // If constructing the runner caused initialization errors, unwrap them from the + // InvocationTargetException. + Throwable cause = e.getCause(); + if (!(cause instanceof InitializationError)) throw e; + List<Throwable> causes = ((InitializationError) cause).getCauses(); + + // If there was exactly one initialization error, rewrap that one. + if (causes.size() == 1) { + throw new InvocationTargetException(causes.get(0), "Initialization error"); + } + + // Otherwise, serialize all initialization errors to a string and throw that. + throw new AssertionError(causes.toString()); + } + runner.run(runNotifier); + return testLog; + } +} |