/* * Copyright 2004-2015 the Seasar Foundation and the Others. * * 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.seasar.framework.unit; import java.lang.annotation.Annotation; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List; 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.RunNotifier; import org.junit.runners.Parameterized.Parameters; import static org.junit.Assert.*; /** * {@link Parameters}が注釈されたメソッドを持つテストクラスを扱うランナーです。 * * @author taedium */ public class S2Parameterized extends S2TestClassRunner { private static class TestClassRunnerForParameters extends S2TestClassMethodsRunner { private final Object[] parameters; private final int parameterSetNumber; private final Constructor<?> constructor; private TestClassRunnerForParameters(final Class<?> klass, final Object[] parameters, int i) { super(klass); this.parameters = parameters; this.parameterSetNumber = i; this.constructor = getOnlyConstructor(); } @Override protected Object createTest() throws Exception { return constructor.newInstance(parameters); } @Override protected String getName() { return String.format("[%s]", parameterSetNumber); } @Override protected String testName(final Method method) { return String .format("%s[%s]", method.getName(), parameterSetNumber); } private Constructor<?> getOnlyConstructor() { final Constructor<?>[] constructors = getTestClass() .getConstructors(); assertEquals(1, constructors.length); return constructors[0]; } @Override public void run(final RunNotifier notifier) { runMethods(notifier); } } /* * copy from: org.junit.internal.runners.CompositeRunner @JUnit4.4 * * JUnit license: Eclipse Public License - v 1.0 * https://github.com/junit-team/junit/blob/master/LICENSE-junit.txt */ static class MyCompositeRunner extends Runner implements Filterable, Sortable { private final List<Runner> fRunners = new ArrayList<Runner>(); private final String fName; public MyCompositeRunner(final String name) { fName = name; } @Override public void run(final RunNotifier notifier) { runChildren(notifier); } protected void runChildren(final RunNotifier notifier) { for (final Runner each : fRunners) each.run(notifier); } @Override public Description getDescription() { final Description spec = Description.createSuiteDescription(fName); for (final Runner runner : fRunners) spec.addChild(runner.getDescription()); return spec; } public List<Runner> getRunners() { return fRunners; } public void addAll(final List<? extends Runner> runners) { fRunners.addAll(runners); } public void add(final Runner runner) { fRunners.add(runner); } public void filter(final Filter filter) throws NoTestsRemainException { for (final Iterator<Runner> iter = fRunners.iterator(); iter .hasNext();) { final Runner runner = iter.next(); if (filter.shouldRun(runner.getDescription())) filter.apply(runner); else iter.remove(); } } protected String getName() { return fName; } public void sort(final Sorter sorter) { Collections.sort(fRunners, new Comparator<Runner>() { public int compare(final Runner o1, final Runner o2) { return sorter.compare(o1.getDescription(), o2.getDescription()); } }); for (final Runner each : fRunners) { sorter.apply(each); } } } /** * {@link Parameters}が注釈されたすべてのメソッドを実行するランナーです。 * * @author taedium */ public static class RunAllParameterMethods extends MyCompositeRunner { private final Class<?> klass; /** * インスタンスを構築します。 * * @param klass * テストクラス * @throws Exception * 何らかの例外が発生した場合 */ public RunAllParameterMethods(final Class<?> klass) throws Exception { super(klass.getName()); this.klass = klass; int i = 0; for (final Object each : getParametersList()) { if (each instanceof Object[]) { super.add(new TestClassRunnerForParameters(klass, Object[].class.cast(each), i++)); } else { throw new Exception(String.format( "%s.%s() must return a Collection of arrays.", this.klass.getName(), getParametersMethod() .getName())); } } } private Collection<?> getParametersList() throws IllegalAccessException, InvocationTargetException, Exception { return Collection.class.cast(getParametersMethod().invoke(null)); } private Method getParametersMethod() throws Exception { for (final Method each : klass.getMethods()) { if (each.isBridge() || each.isSynthetic()) { continue; } if (Modifier.isStatic(each.getModifiers())) { final Annotation[] annotations = each.getAnnotations(); for (final Annotation annotation : annotations) { if (annotation.annotationType() == Parameters.class) return each; } } } throw new Exception("No public static parameters method on class " + getName()); } @Override public void run(final RunNotifier notifier) { new S2TestClassMethodsRunner(klass) { @Override protected void runMethods(final RunNotifier notifier) { runChildren(notifier); } }.run(notifier); } } /** * インスタンスを構築します。 * * @param klass * テストクラス * @throws Exception * 何らかの例外が発生した場合 */ public S2Parameterized(final Class<?> klass) throws Exception { super(klass, new RunAllParameterMethods(klass)); } @Override protected void validate(final S2MethodValidator methodValidator) { methodValidator.validateStaticMethods(); methodValidator.validateInstanceMethods(); } }