package org.hibernate.envers.test; import org.hibernate.testing.junit4.CustomRunner; import org.junit.runner.Runner; import org.junit.runner.manipulation.NoTestsRemainException; import org.junit.runners.Parameterized; import org.junit.runners.Suite; import org.junit.runners.model.FrameworkMethod; import org.junit.runners.model.InitializationError; import org.junit.runners.model.TestClass; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; /** * Copied & modified from {@link org.junit.runners.Parameterized}. * * The modification is that the generated runners extend {@link CustomRunner} instead of the default * {@code TestClassRunnerForParameters}. * * The runner itself sets the data using a setter instead of a constructor, and creates only one test instance. Moreover * it doesn't override {@code classBlock} which causes the custom {@code @BeforeClassOnce} and {@code @AfterClassOnce} * annotations to work. * @author Adam Warski (adam at warski dot org) */ public class EnversRunner extends Suite { private class TestClassCustomRunnerForParameters extends CustomRunner { private final int fParameterSetNumber; private final List<Object[]> fParameterList; TestClassCustomRunnerForParameters(Class<?> type, List<Object[]> parameterList, int i) throws InitializationError, NoTestsRemainException { super(type); fParameterList= parameterList; fParameterSetNumber= i; } @Override protected Object getTestInstance() throws Exception { Object testInstance = super.getTestInstance(); ((AbstractEnversTest) testInstance).setTestData(computeParams()); return testInstance; } private Object[] computeParams() throws Exception { try { return fParameterList.get(fParameterSetNumber); } catch (ClassCastException e) { throw new Exception(String.format( "%s.%s() must return a Collection of arrays.", getTestClass().getName(), getParametersMethod( getTestClass()).getName())); } } @Override protected String getName() { return String.format("[%s]", fParameterSetNumber); } @Override protected String testName(final FrameworkMethod method) { return String.format("%s[%s]", method.getName(), fParameterSetNumber); } @Override protected List<FrameworkMethod> doComputation() { List<FrameworkMethod> frameworkMethods = super.doComputation(); Collections.sort(frameworkMethods, new Comparator<FrameworkMethod>() { private int getPriority(FrameworkMethod fm) { Priority p = fm.getAnnotation(Priority.class); return p == null ? 0 : p.value(); } @Override public int compare(FrameworkMethod fm1, FrameworkMethod fm2) { return getPriority(fm2) - getPriority(fm1); } }); return frameworkMethods; } } private final ArrayList<Runner> runners= new ArrayList<Runner>(); /** * Only called reflectively. Do not use programmatically. */ public EnversRunner(Class<?> klass) throws Throwable { super(klass, Collections.<Runner>emptyList()); List<Object[]> parametersList= getParametersList(getTestClass()); for (int i= 0; i < parametersList.size(); i++) runners.add(new TestClassCustomRunnerForParameters(getTestClass().getJavaClass(), parametersList, i)); } @Override protected List<Runner> getChildren() { return runners; } @SuppressWarnings("unchecked") private List<Object[]> getParametersList(TestClass klass) throws Throwable { return (List<Object[]>) getParametersMethod(klass).invokeExplosively( null); } private FrameworkMethod getParametersMethod(TestClass testClass) throws Exception { List<FrameworkMethod> methods= testClass.getAnnotatedMethods(Parameterized.Parameters.class); for (FrameworkMethod each : methods) { int modifiers= each.getMethod().getModifiers(); if (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers)) return each; } throw new Exception("No public static parameters method on class " + testClass.getName()); } }