/*
* Copyright (C) 2012 uPhyca Inc.
*
* 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.uphyca.testing;
import java.lang.reflect.InvocationTargetException;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
import android.app.Instrumentation;
import android.os.Bundle;
import android.test.FlakyTest;
import android.test.RepetitiveTest;
import android.test.UiThreadTest;
class AndroidAnnotatedMethodRule implements TestRule {
private Instrumentation fInstrumentation;
public AndroidAnnotatedMethodRule() {
}
public AndroidAnnotatedMethodRule(Instrumentation instrumentation) {
fInstrumentation = instrumentation;
}
@Override
public Statement apply(final Statement statement,
final Description description) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
//String methodName = description.getMethodName();
//methodName.
//FIXME How to get annotations via description ?
//Method method = description.getTestClass().getMethod(methodName);
//Following code taken from android.test.InstrumentationTestCase.
int runCount = 1;
boolean isRepetitive = false;
if (description.getAnnotation(FlakyTest.class) != null) {
runCount = description.getAnnotation(FlakyTest.class).tolerance();
} else if (description.getAnnotation(RepetitiveTest.class) != null) {
runCount = description.getAnnotation(RepetitiveTest.class).numIterations();
isRepetitive = true;
}
if (fInstrumentation != null && description.getAnnotation(UiThreadTest.class) != null) {
final int tolerance = runCount;
final boolean repetitive = isRepetitive;
final Throwable[] exceptions = new Throwable[1];
fInstrumentation.runOnMainSync(new Runnable() {
public void run() {
try {
runMethod(statement,
tolerance,
repetitive);
} catch (Throwable throwable) {
exceptions[0] = throwable;
}
}
});
if (exceptions[0] != null) {
throw exceptions[0];
}
} else {
runMethod(statement,
runCount,
isRepetitive);
}
}
};
}
//Taken from android.test.InstrumentationTestCase
private void runMethod(Statement statement,
int tolerance,
boolean isRepetitive) throws Throwable {
Throwable exception = null;
int runCount = 0;
do {
try {
statement.evaluate();
exception = null;
} catch (Throwable e) {
if (e instanceof InvocationTargetException) {
e.fillInStackTrace();
exception = ((InvocationTargetException)e).getTargetException();
} else if (e instanceof IllegalAccessException) {
e.fillInStackTrace();
exception = e;
} else {
exception = e;
}
} finally {
runCount++;
// Report current iteration number, if test is repetitive
if (isRepetitive) {
Bundle iterations = new Bundle();
iterations.putInt("currentiterations",
runCount);
fInstrumentation.sendStatus(2,
iterations);
}
}
} while ((runCount < tolerance) && (isRepetitive || exception != null));
if (exception != null) {
throw exception;
}
}
}