/*
* 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();
}
}