/*******************************************************************************
* Copyright (c) 2006, 2008 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
* David Saff (saff@mit.edu) - initial API and implementation
* (bug 102632: [JUnit] Support for JUnit 4.)
*******************************************************************************/
package org.eclipse.jdt.internal.junit.runner.junit3;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.MessageFormat;
import java.util.Iterator;
import java.util.List;
import junit.extensions.TestDecorator;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestResult;
import junit.framework.TestSuite;
import org.eclipse.jdt.internal.junit.runner.FailedComparison;
import org.eclipse.jdt.internal.junit.runner.IClassifiesThrowables;
import org.eclipse.jdt.internal.junit.runner.IListensToTestExecutions;
import org.eclipse.jdt.internal.junit.runner.IStopListener;
import org.eclipse.jdt.internal.junit.runner.ITestIdentifier;
import org.eclipse.jdt.internal.junit.runner.ITestReference;
import org.eclipse.jdt.internal.junit.runner.IVisitsTestTrees;
import org.eclipse.jdt.internal.junit.runner.MessageIds;
import org.eclipse.jdt.internal.junit.runner.TestExecution;
import org.eclipse.jdt.internal.junit.runner.TestReferenceFailure;
@SuppressWarnings({ "rawtypes" })
public class JUnit3TestReference implements ITestReference {
private final Test fTest;
public static Object getField(final Object object, final String fieldName) {
Class clazz = object.getClass();
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field.get(object);
} catch (Exception e) {
// fall through
}
return null;
}
public JUnit3TestReference(final Test test) {
if (test == null)
throw new NullPointerException();
this.fTest = test;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jdt.internal.junit.runner.TestReference#countTestCases()
*/
public int countTestCases() {
return fTest.countTestCases();
}
@Override
public boolean equals(final Object obj) {
if (!(obj instanceof JUnit3TestReference))
return false;
JUnit3TestReference ref = (JUnit3TestReference) obj;
return ref.fTest.equals(fTest);
}
@Override
public int hashCode() {
return fTest.hashCode();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jdt.internal.junit.runner.TestReference#getName()
*/
public String getName() {
if (isJUnit4TestCaseAdapter(fTest)) {
Method method = (Method) callJUnit4GetterMethod(fTest, "getTestMethod"); //$NON-NLS-1$
return MessageFormat.format(MessageIds.TEST_IDENTIFIER_MESSAGE_FORMAT, method.getName(), method.getDeclaringClass().getName());
}
if (fTest instanceof TestCase) {
TestCase testCase = (TestCase) fTest;
return MessageFormat.format(MessageIds.TEST_IDENTIFIER_MESSAGE_FORMAT, testCase.getName(), fTest.getClass().getName());
}
if (fTest instanceof TestSuite) {
TestSuite suite = (TestSuite) fTest;
if (suite.getName() != null)
return suite.getName();
return suite.getClass().getName();
}
if (fTest instanceof TestDecorator) {
TestDecorator decorator = (TestDecorator) fTest;
return decorator.getClass().getName();
}
if (isJUnit4TestSuiteAdapter(fTest)) {
Class testClass = (Class) callJUnit4GetterMethod(fTest, "getTestClass"); //$NON-NLS-1$
return testClass.getName();
}
return fTest.toString();
}
public Test getTest() {
return fTest;
}
public void run(final TestExecution execution) {
final TestResult testResult = new TestResult();
testResult.addListener(new JUnit3Listener(execution));
execution.addStopListener(new IStopListener() {
public void stop() {
testResult.stop();
}
});
TestResult tr = testResult;
fTest.run(tr);
}
public void sendTree(final IVisitsTestTrees notified) {
if (fTest instanceof TestDecorator) {
TestDecorator decorator = (TestDecorator) fTest;
notified.visitTreeEntry(getIdentifier(), true, 1);
sendTreeOfChild(decorator.getTest(), notified);
} else if (fTest instanceof TestSuite) {
TestSuite suite = (TestSuite) fTest;
notified.visitTreeEntry(getIdentifier(), true, suite.testCount());
for (int i = 0; i < suite.testCount(); i++) {
sendTreeOfChild(suite.testAt(i), notified);
}
} else if (isJUnit4TestSuiteAdapter(fTest)) {
notified.visitTreeEntry(getIdentifier(), true, fTest.countTestCases());
List tests = (List) callJUnit4GetterMethod(fTest, "getTests"); //$NON-NLS-1$
for (Iterator iter = tests.iterator(); iter.hasNext();) {
sendTreeOfChild((Test) iter.next(), notified);
}
} else {
notified.visitTreeEntry(getIdentifier(), false, fTest.countTestCases());
}
}
void sendFailure(final Throwable throwable, final IClassifiesThrowables classifier, final String status,
final IListensToTestExecutions notified) {
TestReferenceFailure failure;
try {
failure = new TestReferenceFailure(getIdentifier(), status, classifier.getTrace(throwable));
if (classifier.isComparisonFailure(throwable)) {
// transmit the expected and the actual string
Object expected = JUnit3TestReference.getField(throwable, "fExpected"); //$NON-NLS-1$
Object actual = JUnit3TestReference.getField(throwable, "fActual"); //$NON-NLS-1$
if (expected != null && actual != null) {
failure.setComparison(new FailedComparison((String) expected, (String) actual));
}
}
} catch (RuntimeException e) {
StringWriter stringWriter = new StringWriter();
e.printStackTrace(new PrintWriter(stringWriter));
failure = new TestReferenceFailure(getIdentifier(), MessageIds.TEST_FAILED, stringWriter.getBuffer().toString(), null);
}
notified.notifyTestFailed(failure);
}
private Object callJUnit4GetterMethod(final Test test, final String methodName) {
Object result;
try {
Method method = test.getClass().getMethod(methodName, new Class[0]);
result = method.invoke(test, new Object[0]);
} catch (Exception e) {
e.printStackTrace(System.err);
result = null;
}
return result;
}
private boolean isJUnit4TestCaseAdapter(final Test test) {
return test.getClass().getName().equals("junit.framework.JUnit4TestCaseAdapter"); //$NON-NLS-1$
}
private boolean isJUnit4TestSuiteAdapter(final Test test) {
String name = test.getClass().getName();
return name.endsWith("JUnit4TestAdapter") && name.startsWith("junit.framework"); //$NON-NLS-1$ //$NON-NLS-2$
}
private void sendTreeOfChild(final Test test, final IVisitsTestTrees notified) {
new JUnit3TestReference(test).sendTree(notified);
}
public ITestIdentifier getIdentifier() {
return new JUnit3Identifier(this);
}
}