/*
* Copyright 2008 the original author or authors.
*
* 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 org.powermock.modules.junit3.internal.impl;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestResult;
import junit.framework.TestSuite;
import org.powermock.core.spi.PowerMockTestListener;
import org.powermock.modules.junit3.internal.PowerMockJUnit3RunnerDelegate;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Vector;
@SuppressWarnings("unchecked")
public class PowerMockJUnit3RunnerDelegateImpl extends TestSuite implements PowerMockJUnit3RunnerDelegate {
private final Method[] methodsToRun;
private Class<?> testClass;
public PowerMockJUnit3RunnerDelegateImpl(final Class<?> theClass, Method[] methodsToRun, String name,
PowerMockTestListener[] powerListeners) {
this(theClass, methodsToRun, powerListeners);
testClass = theClass;
setName(name);
}
/**
* Constructs a TestSuite from the given class. Adds all the methods
* starting with "test" as test cases to the suite. Parts of this method was
* cut'n'pasted on the train between Malm� and Stockholm.
*/
public PowerMockJUnit3RunnerDelegateImpl(final Class<?> theClass, Method[] methodsToRun, PowerMockTestListener[] powerMockTestListeners) {
testClass = theClass;
this.methodsToRun = methodsToRun;
setName(theClass.getName());
try {
getTestConstructor(theClass); // Avoid generating multiple error
// messages
} catch (NoSuchMethodException e) {
addTest(warning("Class " + theClass.getName() + " has no public constructor TestCase(String name) or TestCase()"));
return;
}
if (!Modifier.isPublic(theClass.getModifiers())) {
addTest(warning("Class " + theClass.getName() + " is not public"));
return;
}
Class<?> superClass = theClass;
Vector<?> names = new Vector<Object>();
Method addTestMethod = null;
Method[] declaredMethods = TestSuite.class.getDeclaredMethods();
for (Method method : declaredMethods) {
/*
* Since the TestSuite class is loaded by another classloader we
* look up the method this way (which is not fail-proof, but good
* enough).
*/
if (method.getName().equals("addTestMethod")) {
addTestMethod = method;
}
}
if (addTestMethod == null) {
throw new RuntimeException("Internal error: Failed to get addTestMethod for JUnit3.");
}
addTestMethod.setAccessible(true);
while (Test.class.isAssignableFrom(superClass)) {
for (int i = 0; i < methodsToRun.length; i++) {
try {
addTestMethod.invoke(this, methodsToRun[i], names, theClass);
} catch (Exception e) {
throw new RuntimeException("Internal error: Failed to execute addTestMethod for JUnit3.");
}
}
superClass = superClass.getSuperclass();
}
if (testCount() == 0) {
addTest(warning("No tests found in " + theClass.getName()));
}
}
@Override
public Class<?> getTestClass() {
return testClass;
}
@Override
public void run(TestResult result) {
final ClassLoader classloader = this.getClass().getClassLoader();
final Thread currentThread = Thread.currentThread();
final ClassLoader originalClassLoader = currentThread.getContextClassLoader();
currentThread.setContextClassLoader(classloader);
try {
super.run(result);
} finally {
currentThread.setContextClassLoader(originalClassLoader);
}
}
/**
* Returns a test which will fail and log a warning message.
*/
public static Test warning(final String message) {
return new TestCase("warning") {
@Override
protected void runTest() {
fail(message);
}
};
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("Methods ran by this test runner delegate:\n");
for (Method method : methodsToRun) {
builder.append(method).append("\n");
}
return builder.toString();
}
}