package com.uphyca.testing.junit.internal.runners;
import junit.extensions.TestDecorator;
import junit.framework.AssertionFailedError;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestListener;
import junit.framework.TestResult;
import junit.framework.TestSuite;
import org.junit.runner.Describable;
import org.junit.runner.Description;
import org.junit.runner.Runner;
import org.junit.runner.manipulation.Filter;
import org.junit.runner.manipulation.Filterable;
import org.junit.runner.manipulation.NoTestsRemainException;
import org.junit.runner.manipulation.Sortable;
import org.junit.runner.manipulation.Sorter;
import org.junit.runner.notification.Failure;
import org.junit.runner.notification.RunNotifier;
import android.app.Instrumentation;
import android.content.Context;
import android.os.PerformanceCollector.PerformanceResultsWriter;
import com.uphyca.testing.Infrastructure;
/**
* Modified version of org.junit.internal.runners.JUnit38ClassRunner.
*/
public class AndroidJUnit38ClassRunner extends Runner implements Filterable, Sortable {
private final class OldTestClassAdaptingListener implements
TestListener {
private final RunNotifier fNotifier;
private OldTestClassAdaptingListener(RunNotifier notifier) {
fNotifier= notifier;
}
public void endTest(Test test) {
fNotifier.fireTestFinished(asDescription(test));
}
public void startTest(Test test) {
fNotifier.fireTestStarted(asDescription(test));
}
// Implement junit.framework.TestListener
public void addError(Test test, Throwable t) {
Failure failure= new Failure(asDescription(test), t);
fNotifier.fireTestFailure(failure);
}
private Description asDescription(Test test) {
if (test instanceof Describable) {
Describable facade= (Describable) test;
return facade.getDescription();
}
return Description.createTestDescription(getEffectiveClass(test), getName(test));
}
private Class<? extends Test> getEffectiveClass(Test test) {
return test.getClass();
}
//Set class name for suite to avoid display as "junit.framework.TestStuite.1"
//this(TestSuite.createTest(klass.asSubclass(TestCase.class), klass.getName()));
private String getName(Test test) {
if (test instanceof TestCase)
return ((TestCase) test).getName();
else
return test.toString();
}
public void addFailure(Test test, AssertionFailedError t) {
addError(test, t);
}
}
private Test fTest;
public AndroidJUnit38ClassRunner(final Class<?> klass) {
this(new TestSuite(klass.asSubclass(TestCase.class)));
}
public AndroidJUnit38ClassRunner(Test test) {
super();
setTest(test);
}
@Override
public void run(RunNotifier notifier) {
//For Android
AndroidTestResult result= new AndroidTestResult();
result.addListener(createAdaptingListener(notifier));
getTest().run(result);
}
public TestListener createAdaptingListener(final RunNotifier notifier) {
return new OldTestClassAdaptingListener(notifier);
}
@Override
public Description getDescription() {
return makeDescription(getTest());
}
private Description makeDescription(Test test) {
if (test instanceof TestCase) {
TestCase tc= (TestCase) test;
//FIXME When test constructed fail then tc.getClass() returns junit.framework.TestSuite.1 that created in TestSuite.warring()
return Description.createTestDescription(tc.getClass(), tc.getName());
} else if (test instanceof TestSuite) {
TestSuite ts= (TestSuite) test;
String name= ts.getName() == null ? createSuiteDescription(ts) : ts.getName();
Description description= Description.createSuiteDescription(name);
int n= ts.testCount();
for (int i= 0; i < n; i++) {
Description made= makeDescription(ts.testAt(i));
description.addChild(made);
}
return description;
} else if (test instanceof Describable) {
Describable adapter= (Describable) test;
return adapter.getDescription();
} else if (test instanceof TestDecorator) {
TestDecorator decorator= (TestDecorator) test;
return makeDescription(decorator.getTest());
} else {
// This is the best we can do in this case
return Description.createSuiteDescription(test.getClass());
}
}
private static String createSuiteDescription(TestSuite ts) {
int count= ts.countTestCases();
String example = count == 0 ? "" : String.format(" [example: %s]", ts.testAt(0));
return String.format("TestSuite with %s tests%s", count, example);
}
public void filter(Filter filter) throws NoTestsRemainException {
if (getTest() instanceof Filterable) {
Filterable adapter= (Filterable) getTest();
adapter.filter(filter);
} else if (getTest() instanceof TestSuite) {
TestSuite suite= (TestSuite) getTest();
TestSuite filtered= new TestSuite(suite.getName());
int n= suite.testCount();
for (int i= 0; i < n; i++) {
Test test= suite.testAt(i);
if (filter.shouldRun(makeDescription(test)))
filtered.addTest(test);
}
setTest(filtered);
}
}
public void sort(Sorter sorter) {
if (getTest() instanceof Sortable) {
Sortable adapter= (Sortable) getTest();
adapter.sort(sorter);
}
}
private void setTest(Test test) {
fTest = test;
}
private Test getTest() {
return fTest;
}
//For Android
private static final class AndroidTestResult extends TestResult {
private final Context fContext;
private final Context fTestContext;
private final Instrumentation fInstrumentation;
private final PerformanceResultsWriter fPerformanceResultsWriter;
public AndroidTestResult() {
fContext = Infrastructure.getContext();
fTestContext = Infrastructure.getTestContext();
fInstrumentation = Infrastructure.getInstrumentation();
fPerformanceResultsWriter = Infrastructure.getPerformanceResultsWriter();
}
@Override
protected void run(TestCase test) {
Infrastructure.setContextIfAndroidTestCase(test, fContext, fTestContext);
Infrastructure.setInstrumentationIfInstrumentationTestCase(test, fInstrumentation);
Infrastructure.setPerformanceWriterIfPerformanceCollectorTestCase(test, fPerformanceResultsWriter);
super.run(test);
}
}
}