/*
* Copyright 2013 Harald Wellmann
*
* 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.ops4j.pax.exam.junit.impl;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.junit.runner.Description;
import org.junit.runner.Runner;
import org.junit.runner.notification.Failure;
import org.junit.runner.notification.RunNotifier;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import org.junit.runners.Suite;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.InitializationError;
import org.ops4j.pax.exam.spi.StagedExamReactor;
import org.ops4j.pax.exam.spi.reactors.ReactorManager;
/**
* JUnit runner for parameterized Pax Exam tests without an invoker. This runner is used for CDI
* mode only.
* <p>
* See {@link Parameterized} for more details on specifying parameter sets.
* <p>
* Based on {@code org.junit.runners.Parameterized}.
*
* @author Harald Wellmann
*
*/
public class ParameterizedInjectingRunner extends Suite {
private static final List<Runner> NO_RUNNERS = Collections.<Runner> emptyList();
private final ArrayList<Runner> runners = new ArrayList<Runner>();
private ReactorManager manager;
private StagedExamReactor stagedReactor;
public ParameterizedInjectingRunner(Class<?> klass) throws InitializationError {
super(klass, NO_RUNNERS);
manager = ReactorManager.getInstance();
manager.prepareReactor(klass, null);
stagedReactor = manager.stageReactor();
Parameters parameters = getParametersMethod().getAnnotation(Parameters.class);
createRunnersForParameters(allParameters(), parameters.name());
}
@Override
protected List<Runner> getChildren() {
return runners;
}
@Override
public void run(RunNotifier notifier) {
Class<?> testClass = getTestClass().getJavaClass();
try {
manager.beforeClass(stagedReactor, testClass);
super.run(notifier);
}
// CHECKSTYLE:SKIP : catch all wanted
catch (Throwable e) {
// rethrowing the exception does not help, we have to use the notifier here
Description description = Description.createSuiteDescription(testClass);
notifier.fireTestFailure(new Failure(description, e));
}
finally {
manager.afterClass(stagedReactor, testClass);
}
}
@SuppressWarnings("unchecked")
private Iterable<Object[]> allParameters() throws InitializationError {
Object parameters;
try {
parameters = getParametersMethod().invokeExplosively(null);
}
// CHECKSTYLE:SKIP - JUnit API
catch (Throwable t) {
throw new InitializationError(t);
}
if (parameters instanceof Iterable) {
return (Iterable<Object[]>) parameters;
}
else {
throw parametersMethodReturnedWrongType();
}
}
private FrameworkMethod getParametersMethod() throws InitializationError {
List<FrameworkMethod> methods = getTestClass().getAnnotatedMethods(Parameters.class);
for (FrameworkMethod each : methods) {
if (each.isStatic() && each.isPublic()) {
return each;
}
}
throw new InitializationError("No public static parameters method on class "
+ getTestClass().getName());
}
private void createRunnersForParameters(Iterable<Object[]> allParameters, String namePattern)
throws InitializationError {
try {
int i = 0;
for (Object[] parametersOfSingleTest : allParameters) {
String name = nameFor(namePattern, i, parametersOfSingleTest);
TestClassRunnerForParameters runner = new TestClassRunnerForParameters(
getTestClass().getJavaClass(), parametersOfSingleTest, name);
runners.add(runner);
++i;
}
}
catch (ClassCastException e) {
throw parametersMethodReturnedWrongType();
}
}
private String nameFor(String namePattern, int index, Object[] parameters) {
String finalPattern = namePattern.replaceAll("\\{index\\}", Integer.toString(index));
String name = MessageFormat.format(finalPattern, parameters);
return "[" + name + "]";
}
private InitializationError parametersMethodReturnedWrongType() throws InitializationError {
String className = getTestClass().getName();
String methodName = getParametersMethod().getName();
String message = MessageFormat.format("{0}.{1}() must return an Iterable of arrays.",
className, methodName);
return new InitializationError(message);
}
}