Update of /cvsroot/junit/junit/org/junit/internal/javamodel In directory sc8-pr-cvs6.sourceforge.net:/tmp/cvs-serv29935/org/junit/internal/javamodel Added Files: Tag: saff_r41_runner_refactoring JavaModelElement.java JavaMethod.java JavaMethodList.java WrappedJavaModelElement.java JavaClass.java Log Message: Moved model elements into their own package (although this leads to circularities), for easier review. Also introduced WrappedJavaModelElement --- NEW FILE: JavaModelElement.java --- package org.junit.internal.javamodel; import org.junit.runner.Description; import org.junit.runner.notification.Failure; import org.junit.runner.notification.RunNotifier; public abstract class JavaModelElement { public abstract String getName(); public void addFailure(RunNotifier runNotifier, Throwable targetException) { runNotifier .fireTestFailure(new Failure(description(), targetException)); } protected abstract Description description(); } --- NEW FILE: JavaMethod.java --- /** * */ package org.junit.internal.javamodel; import java.lang.annotation.Annotation; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import org.junit.After; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.junit.Test.None; import org.junit.internal.runners.MethodAnnotation; import org.junit.internal.runners.TestEnvironment; import org.junit.runner.Description; // TODO: check names of various "run" methods public class JavaMethod extends WrappedJavaModelElement { // TODO: push out private final Method fMethod; private final JavaClass fJavaClass; public JavaMethod(JavaClass javaClass, Method current) { fJavaClass= javaClass; fMethod= current; } public Annotation getAnnotation(MethodAnnotation methodAnnotation) { return fMethod.getAnnotation(methodAnnotation.getAnnotationClass()); } boolean isIgnored() { return fMethod.getAnnotation(Ignore.class) != null; } long getTimeout() { return getTestAnnotation().timeout(); } private Test getTestAnnotation() { return fMethod.getAnnotation(Test.class); } Class<? extends Throwable> expectedException() { Test annotation= getTestAnnotation(); if (annotation.expected() == None.class) return null; else return annotation.expected(); } boolean isUnexpected(Throwable exception) { return !expectedException().isAssignableFrom(exception.getClass()); } boolean expectsException() { return expectedException() != null; } public Object invoke(Object object) throws IllegalAccessException, InvocationTargetException { return fMethod.invoke(object); } @Override public String getName() { return fMethod.getName(); } // TODO: push out @Override public Description description() { return Description.createTestDescription(fJavaClass.getTestClass(), getName()); } // TODO: push out @Override public JavaClass getJavaClass() { return fJavaClass; } @Override public Class<? extends Annotation> getAfterAnnotation() { return After.class; } @Override public Class<? extends Annotation> getBeforeAnnotation() { return Before.class; } public void runWithoutBeforeAndAfter(TestEnvironment environment, Object test) { // TODO: is this envious of environment? try { environment.getInterpreter().executeMethodBody(test, this); if (expectsException()) addFailure(environment.getRunNotifier(), new AssertionError( "Expected exception: " + expectedException().getName())); } catch (InvocationTargetException e) { Throwable actual= e.getTargetException(); if (!expectsException()) addFailure(environment.getRunNotifier(), actual); else if (isUnexpected(actual)) { String message= "Unexpected exception, expected<" + expectedException().getName() + "> but was<" + actual.getClass().getName() + ">"; addFailure(environment.getRunNotifier(), new Exception(message, actual)); } } catch (Throwable e) { // TODO: DUP on environment.getRunNotifier addFailure(environment.getRunNotifier(), e); } } void invokeTestMethod(TestEnvironment testEnvironment) { Object test; try { test= getJavaClass().newInstance(); } catch (Exception e) { testEnvironment.getRunNotifier().testAborted(description(), e); return; } run(testEnvironment, test); } void runWithoutTimeout(final Object test, final TestEnvironment testEnvironment) { // TODO: is this envious now? Yes runWithBeforeAndAfter(new Runnable() { public void run() { runWithoutBeforeAndAfter(testEnvironment, test); } }, test, testEnvironment.getRunNotifier()); // TODO: ugly } void runWiteTimeout(long timeout, final Object test, final TestEnvironment testEnvironment) { ExecutorService service= Executors.newSingleThreadExecutor(); Callable<Object> callable= new Callable<Object>() { public Object call() throws Exception { runWithoutTimeout(test, testEnvironment); return null; } }; Future<Object> result= service.submit(callable); service.shutdown(); try { boolean terminated= service.awaitTermination(timeout, TimeUnit.MILLISECONDS); if (!terminated) service.shutdownNow(); result.get(timeout, TimeUnit.MILLISECONDS); // throws the exception // if one occurred // during the invocation } catch (TimeoutException e) { addFailure(testEnvironment.getRunNotifier(), new Exception(String .format("test timed out after %d milliseconds", timeout))); } catch (Exception e) { // TODO: DUP addFailure(testEnvironment.getRunNotifier(), e); } } void run(TestEnvironment environment, Object test) { if (isIgnored()) { environment.getRunNotifier().fireTestIgnored(description()); return; } environment.getRunNotifier().fireTestStarted(description()); try { long timeout= getTimeout(); if (timeout > 0) runWiteTimeout(timeout, test, environment); else runWithoutTimeout(test, environment); } finally { environment.getRunNotifier().fireTestFinished(description()); } } } --- NEW FILE: JavaMethodList.java --- package org.junit.internal.javamodel; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List; import org.junit.internal.runners.TestEnvironment; import org.junit.runner.Description; import org.junit.runner.manipulation.Filter; import org.junit.runner.manipulation.NoTestsRemainException; import org.junit.runner.manipulation.Sorter; public class JavaMethodList extends JavaModelElement implements Iterable<JavaMethod> { private static final long serialVersionUID= 1L; private final JavaClass fJavaClass; private List<JavaMethod> fMethods= new ArrayList<JavaMethod>(); public JavaMethodList(JavaClass javaClass) { fJavaClass= javaClass; } public void filter(Filter filter) throws NoTestsRemainException { for (Iterator<JavaMethod> iter= fMethods.iterator(); iter.hasNext();) { JavaMethod method= iter.next(); if (!filter.shouldRun(method.description())) iter.remove(); } if (fMethods.isEmpty()) throw new NoTestsRemainException(); } public void filter(final Sorter sorter) { Collections.sort(fMethods, new Comparator<JavaMethod>() { public int compare(JavaMethod o1, JavaMethod o2) { return sorter.compare(o1.description(), o2.description()); } }); } @Override public String getName() { return String.format("%s methods", fJavaClass.getName()); } public Iterator<JavaMethod> iterator() { return fMethods.iterator(); } public void add(JavaMethod eachMethod) { fMethods.add(eachMethod); } public boolean isEmpty() { return fMethods.isEmpty(); } public void reverse() { Collections.reverse(fMethods); } @Override public Description description() { Description spec= Description.createSuiteDescription(fJavaClass .getName()); for (JavaMethod method : this) spec.addChild(method.description()); return spec; } public void run(TestEnvironment environment) { if (isEmpty()) // TODO: DUP environment.getRunNotifier().testAborted(description(), new Exception( "No runnable methods")); for (JavaMethod method : this) { method.invokeTestMethod(environment); } } } --- NEW FILE: WrappedJavaModelElement.java --- package org.junit.internal.javamodel; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.util.List; import org.junit.internal.runners.FailedBefore; import org.junit.runner.notification.RunNotifier; public abstract class WrappedJavaModelElement extends JavaModelElement { public abstract Class<? extends Annotation> getBeforeAnnotation(); public abstract Class<? extends Annotation> getAfterAnnotation(); public abstract JavaClass getJavaClass(); void runAfters(Object test, RunNotifier runNotifier) { // TODO: train wreck for (Method after : getJavaClass().getMethods( getAfterAnnotation())) { try { after.invoke(test); } catch (Throwable e) { addFailure(runNotifier, e); } } } void runBefores(Object test, RunNotifier runNotifier) throws FailedBefore { try { List<Method> befores= getJavaClass().getMethods( getBeforeAnnotation()); // TODO: no auto-correct if wrong type on left side of new-style // for? for (Method before : befores) before.invoke(test); } catch (Throwable e) { addFailure(runNotifier, e); throw new FailedBefore(); } } public void runWithBeforeAndAfter(Runnable protectThis, Object test, RunNotifier runNotifier) { try { runBefores(test, runNotifier); protectThis.run(); } catch (FailedBefore e) { } finally { runAfters(test, runNotifier); } } } --- NEW FILE: JavaClass.java --- /** * */ package org.junit.internal.javamodel; import java.lang.annotation.Annotation; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; import org.junit.internal.runners.JavaTestInterpreter; import org.junit.internal.runners.MethodAnnotation; import org.junit.runner.Description; public class JavaClass extends WrappedJavaModelElement { // TODO: push out private final Class<?> fClass; public JavaClass(Class<?> type) { fClass= type; } public List<JavaClass> getSuperClasses() { ArrayList<JavaClass> results= new ArrayList<JavaClass>(); results.add(this); // TODO: this will not add parameterized superclasses (need to use // interpreter here?) if (fClass.getSuperclass() != null) results.addAll(new JavaClass(fClass.getSuperclass()) .getSuperClasses()); return results; } public List<Method> getMethods(MethodAnnotation methodAnnotation) { List<Method> results= new ArrayList<Method>(); for (JavaClass eachClass : getSuperClasses()) { for (Method eachMethod : eachClass.getDeclaredMethods()) { Annotation annotation= eachMethod .getAnnotation(methodAnnotation.getAnnotationClass()); if (annotation != null && !isShadowedBy(eachMethod, results)) results.add(eachMethod); } } if (methodAnnotation.runsTopToBottom()) Collections.reverse(results); return results; } private boolean isShadowedBy(Method target, Method previous) { if (!previous.getName().equals(target.getName())) return false; if (previous.getParameterTypes().length != target.getParameterTypes().length) return false; for (int i= 0; i < previous.getParameterTypes().length; i++) { if (!previous.getParameterTypes()[i].equals(target .getParameterTypes()[i])) return false; } return true; } boolean isShadowedBy(Method target, List<Method> results) { for (Method each : results) { if (isShadowedBy(target, each)) return true; } return false; } private Method[] getDeclaredMethods() { return fClass.getDeclaredMethods(); } public List<Method> getMethods(Class<? extends Annotation> type) { return getMethods(new MethodAnnotation(type)); } public Class getTestClass() { return fClass; } public void validateNoArgConstructor(List<Throwable> errors) { try { getTestClass().getConstructor(); } catch (Exception e) { errors.add(new Exception( "Test class should have public zero-argument constructor", e)); } } @Override public String getName() { return fClass.getName(); } protected Object newInstance() throws InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException { return getTestClass().getConstructor().newInstance(); } @Override public Class<? extends Annotation> getAfterAnnotation() { return AfterClass.class; } @Override public Class<? extends Annotation> getBeforeAnnotation() { return BeforeClass.class; } @Override public JavaClass getJavaClass() { return this; } public JavaMethodList getTestMethods(JavaTestInterpreter javaTestInterpreter) { List<Method> methods= getMethods(Test.class); JavaMethodList list= new JavaMethodList(this); for (Method method : methods) { list.add(javaTestInterpreter.interpretJavaMethod(this, method)); } return list; } @Override protected Description description() { return Description.createSuiteDescription(fClass); } } |