1e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monk/* 2e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monk * Copyright (C) 2017 The Android Open Source Project 3e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monk * 4e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monk * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file 5e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monk * except in compliance with the License. You may obtain a copy of the License at 6e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monk * 7e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monk * http://www.apache.org/licenses/LICENSE-2.0 8e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monk * 9e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monk * Unless required by applicable law or agreed to in writing, software distributed under the 10e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monk * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 11e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monk * KIND, either express or implied. See the License for the specific language governing 12e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monk * permissions and limitations under the License. 13e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monk */ 14e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monk 15340b0e5216b4fcc435e0459b1ca46155a572100dJason Monkpackage android.testing; 16e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monk 17e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monkimport android.support.test.internal.runner.junit4.statement.RunAfters; 18e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monkimport android.support.test.internal.runner.junit4.statement.RunBefores; 19e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monkimport android.support.test.internal.runner.junit4.statement.UiThreadStatement; 20e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monk 21745d0a8b77ad3c7c8a220b6e05dbceff54154d57Jason Monkimport android.testing.TestableLooper.LooperFrameworkMethod; 22340b0e5216b4fcc435e0459b1ca46155a572100dJason Monkimport android.testing.TestableLooper.RunWithLooper; 23e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monk 24e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monkimport org.junit.After; 25e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monkimport org.junit.Before; 26e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monkimport org.junit.Test; 27e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monkimport org.junit.internal.runners.statements.FailOnTimeout; 28e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monkimport org.junit.runners.BlockJUnit4ClassRunner; 29e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monkimport org.junit.runners.model.FrameworkMethod; 30e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monkimport org.junit.runners.model.InitializationError; 31e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monkimport org.junit.runners.model.Statement; 32e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monk 33745d0a8b77ad3c7c8a220b6e05dbceff54154d57Jason Monkimport java.util.ArrayList; 34e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monkimport java.util.List; 35e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monk 36340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk/** 37340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk * A runner with support for extra annotations provided by the Testables library. 38340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk */ 39340b0e5216b4fcc435e0459b1ca46155a572100dJason Monkpublic class AndroidTestingRunner extends BlockJUnit4ClassRunner { 40e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monk 41e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monk private final long mTimeout; 42e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monk private final Class<?> mKlass; 43e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monk 44340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk public AndroidTestingRunner(Class<?> klass) throws InitializationError { 45e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monk super(klass); 46e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monk mKlass = klass; 47e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monk // Can't seem to get reference to timeout parameter from here, so set default to 10 mins. 48e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monk mTimeout = 10 * 60 * 1000; 49e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monk } 50e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monk 51e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monk @Override 52e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monk protected Statement methodInvoker(FrameworkMethod method, Object test) { 53745d0a8b77ad3c7c8a220b6e05dbceff54154d57Jason Monk method = looperWrap(method, test, method); 54745d0a8b77ad3c7c8a220b6e05dbceff54154d57Jason Monk final Statement statement = super.methodInvoker(method, test); 55745d0a8b77ad3c7c8a220b6e05dbceff54154d57Jason Monk return shouldRunOnUiThread(method) ? new UiThreadStatement(statement, true) : statement; 56e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monk } 57e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monk 58e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monk protected Statement withBefores(FrameworkMethod method, Object target, Statement statement) { 59745d0a8b77ad3c7c8a220b6e05dbceff54154d57Jason Monk List befores = looperWrap(method, target, 60745d0a8b77ad3c7c8a220b6e05dbceff54154d57Jason Monk this.getTestClass().getAnnotatedMethods(Before.class)); 61e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monk return befores.isEmpty() ? statement : new RunBefores(method, statement, 62e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monk befores, target); 63e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monk } 64e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monk 65e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monk protected Statement withAfters(FrameworkMethod method, Object target, Statement statement) { 66745d0a8b77ad3c7c8a220b6e05dbceff54154d57Jason Monk List afters = looperWrap(method, target, 67745d0a8b77ad3c7c8a220b6e05dbceff54154d57Jason Monk this.getTestClass().getAnnotatedMethods(After.class)); 68e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monk return afters.isEmpty() ? statement : new RunAfters(method, statement, afters, 69e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monk target); 70e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monk } 71e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monk 72e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monk protected Statement withPotentialTimeout(FrameworkMethod method, Object test, Statement next) { 73e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monk long timeout = this.getTimeout(method.getAnnotation(Test.class)); 74e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monk if (timeout <= 0L && mTimeout > 0L) { 75e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monk timeout = mTimeout; 76e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monk } 77e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monk 78e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monk return timeout <= 0L ? next : new FailOnTimeout(next, timeout); 79e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monk } 80e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monk 81e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monk private long getTimeout(Test annotation) { 82e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monk return annotation == null ? 0L : annotation.timeout(); 83e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monk } 84ba3643290df00210ea0011d7ae294931e2298b7eJason Monk 85745d0a8b77ad3c7c8a220b6e05dbceff54154d57Jason Monk protected List<FrameworkMethod> looperWrap(FrameworkMethod method, Object test, 86745d0a8b77ad3c7c8a220b6e05dbceff54154d57Jason Monk List<FrameworkMethod> methods) { 87745d0a8b77ad3c7c8a220b6e05dbceff54154d57Jason Monk RunWithLooper annotation = method.getAnnotation(RunWithLooper.class); 88745d0a8b77ad3c7c8a220b6e05dbceff54154d57Jason Monk if (annotation == null) annotation = mKlass.getAnnotation(RunWithLooper.class); 89745d0a8b77ad3c7c8a220b6e05dbceff54154d57Jason Monk if (annotation != null) { 90745d0a8b77ad3c7c8a220b6e05dbceff54154d57Jason Monk methods = new ArrayList<>(methods); 91745d0a8b77ad3c7c8a220b6e05dbceff54154d57Jason Monk for (int i = 0; i < methods.size(); i++) { 92745d0a8b77ad3c7c8a220b6e05dbceff54154d57Jason Monk methods.set(i, LooperFrameworkMethod.get(methods.get(i), 93745d0a8b77ad3c7c8a220b6e05dbceff54154d57Jason Monk annotation.setAsMainLooper(), test)); 94745d0a8b77ad3c7c8a220b6e05dbceff54154d57Jason Monk } 95745d0a8b77ad3c7c8a220b6e05dbceff54154d57Jason Monk } 96745d0a8b77ad3c7c8a220b6e05dbceff54154d57Jason Monk return methods; 97745d0a8b77ad3c7c8a220b6e05dbceff54154d57Jason Monk } 98745d0a8b77ad3c7c8a220b6e05dbceff54154d57Jason Monk 99745d0a8b77ad3c7c8a220b6e05dbceff54154d57Jason Monk protected FrameworkMethod looperWrap(FrameworkMethod method, Object test, 100745d0a8b77ad3c7c8a220b6e05dbceff54154d57Jason Monk FrameworkMethod base) { 101745d0a8b77ad3c7c8a220b6e05dbceff54154d57Jason Monk RunWithLooper annotation = method.getAnnotation(RunWithLooper.class); 102745d0a8b77ad3c7c8a220b6e05dbceff54154d57Jason Monk if (annotation == null) annotation = mKlass.getAnnotation(RunWithLooper.class); 103745d0a8b77ad3c7c8a220b6e05dbceff54154d57Jason Monk if (annotation != null) { 104745d0a8b77ad3c7c8a220b6e05dbceff54154d57Jason Monk return LooperFrameworkMethod.get(base, annotation.setAsMainLooper(), test); 105745d0a8b77ad3c7c8a220b6e05dbceff54154d57Jason Monk } 106745d0a8b77ad3c7c8a220b6e05dbceff54154d57Jason Monk return base; 107745d0a8b77ad3c7c8a220b6e05dbceff54154d57Jason Monk } 108745d0a8b77ad3c7c8a220b6e05dbceff54154d57Jason Monk 109ba3643290df00210ea0011d7ae294931e2298b7eJason Monk public boolean shouldRunOnUiThread(FrameworkMethod method) { 110ba3643290df00210ea0011d7ae294931e2298b7eJason Monk if (mKlass.getAnnotation(UiThreadTest.class) != null) { 111ba3643290df00210ea0011d7ae294931e2298b7eJason Monk return true; 112ba3643290df00210ea0011d7ae294931e2298b7eJason Monk } else { 113ba3643290df00210ea0011d7ae294931e2298b7eJason Monk return UiThreadStatement.shouldRunOnUiThread(method); 114ba3643290df00210ea0011d7ae294931e2298b7eJason Monk } 115ba3643290df00210ea0011d7ae294931e2298b7eJason Monk } 116e750748404c25a3b1128f6bfeaa65e2bc5550f81Jason Monk} 117