com.github.dakusui.jcunit8.runners.junit4.JCUnit8 Maven / Gradle / Ivy
package com.github.dakusui.jcunit8.runners.junit4;
import com.github.dakusui.jcunit.core.tuples.Tuple;
import com.github.dakusui.jcunit8.core.Utils;
import com.github.dakusui.jcunit8.exceptions.TestDefinitionException;
import com.github.dakusui.jcunit8.factorspace.Constraint;
import com.github.dakusui.jcunit8.factorspace.ParameterSpace;
import com.github.dakusui.jcunit8.pipeline.Config;
import com.github.dakusui.jcunit8.pipeline.Pipeline;
import com.github.dakusui.jcunit8.runners.core.NodeUtils;
import com.github.dakusui.jcunit8.runners.junit4.annotations.ConfigureWith;
import com.github.dakusui.jcunit8.runners.junit4.annotations.ConfigureWith.ConfigFactory;
import com.github.dakusui.jcunit8.runners.junit4.annotations.From;
import com.github.dakusui.jcunit8.runners.junit4.annotations.Given;
import com.github.dakusui.jcunit8.runners.junit4.annotations.ParameterSource;
import com.github.dakusui.jcunit8.testsuite.TestCase;
import com.github.dakusui.jcunit8.testsuite.TestSuite;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.internal.runners.statements.InvokeMethod;
import org.junit.runner.Description;
import org.junit.runner.Runner;
import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.InitializationError;
import org.junit.runners.model.Statement;
import org.junit.runners.model.TestClass;
import org.junit.validator.AnnotationsValidator;
import org.junit.validator.PublicClassValidator;
import org.junit.validator.TestClassValidator;
import java.lang.annotation.Annotation;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.stream.Stream;
import static com.github.dakusui.jcunit8.core.Utils.createTestClassMock;
import static com.github.dakusui.jcunit8.exceptions.FrameworkException.unexpectedByDesign;
import static com.github.dakusui.jcunit8.exceptions.TestDefinitionException.parameterWithoutAnnotation;
import static com.github.dakusui.jcunit8.factorspace.Parameter.Factory;
import static java.lang.String.format;
import static java.util.stream.Collectors.joining;
import static java.util.stream.Collectors.toList;
public class JCUnit8 extends org.junit.runners.Parameterized {
private static Map PRIMITIVE_TO_WRAPPER = new HashMap() {{
put(boolean.class, Boolean.class);
put(byte.class, Byte.class);
put(char.class, Character.class);
put(double.class, Double.class);
put(float.class, Float.class);
put(int.class, Integer.class);
put(long.class, Long.class);
put(short.class, Short.class);
put(void.class, Void.class);
}};
private final TestSuite testSuite;
private final List runners;
public JCUnit8(Class> klass) throws Throwable {
super(klass);
ConfigFactory configFactory = getConfigFactory();
TestClass parameterSpaceDefinition = createParameterSpaceDefinitionTestClass();
this.testSuite = buildTestSuite(
configFactory.create(),
buildParameterSpace(
new ArrayList<>(buildParameterMap(parameterSpaceDefinition).values()),
NodeUtils.allTestPredicates(createParameterSpaceDefinitionTestClass()).values().stream()
.filter(each -> each instanceof Constraint)
.map(Constraint.class::cast)
.collect(toList())
));
this.runners = createRunners();
}
@Override
protected void collectInitializationErrors(List errors) {
this.applyValidators(errors);
}
private void applyValidators(List errors) {
if (getTestClass().getJavaClass() != null) {
for (TestClassValidator each : createValidatorsFor(createParameterSpaceDefinitionTestClass())) {
errors.addAll(each.validateTestClass(getTestClass()));
}
}
}
@Override
protected List getChildren() {
return this.runners;
}
/**
* Mock {@code Parameterized} runner of JUnit 4.12.
*/
@Override
protected TestClass createTestClass(Class> testClass) {
return createTestClassMock(super.createTestClass(testClass));
}
private TestClassValidator[] createValidatorsFor(TestClass parameterSpaceDefinitionClass) {
return new TestClassValidator[] {
new AnnotationsValidator(),
new PublicClassValidator(),
new TestClassValidator() {
@Override
public List validateTestClass(TestClass testClass) {
return new LinkedList() {{
validateFromAnnotationsAreReferencingExistingParameterSourceMethods(testClass, this);
}};
}
private void validateFromAnnotationsAreReferencingExistingParameterSourceMethods(TestClass testClass, List errors) {
testClass.getAnnotatedMethods(Test.class)
.forEach(
frameworkMethod -> Stream.of(frameworkMethod.getMethod().getParameterAnnotations())
.forEach((Annotation[] annotations) -> Stream.of(annotations)
.filter((Annotation annotation) -> annotation instanceof From)
.forEach((Annotation annotation) -> {
List methods = parameterSpaceDefinitionClass.getAnnotatedMethods(ParameterSource.class).stream()
.filter(
(FrameworkMethod each) ->
Objects.equals(each.getName(), From.class.cast(annotation).value()))
.collect(toList());
if (methods.isEmpty())
errors.add(new Exception(
format(
"A method '%s' annotated with '%s' is not defined in '%s'",
From.class.cast(annotation).value(),
ParameterSource.class.getSimpleName(),
parameterSpaceDefinitionClass.getJavaClass().getCanonicalName()
)));
})));
}
}
};
}
private ConfigFactory getConfigFactory() {
try {
//noinspection unchecked
return getConfigureWithAnnotation().value().newInstance();
} catch (InstantiationException | IllegalAccessException e) {
throw TestDefinitionException.wrap(e);
}
}
private TestClass createParameterSpaceDefinitionTestClass() {
Class parameterSpaceClass = getConfigureWithAnnotation().parameterSpace();
return Objects.equals(parameterSpaceClass, ConfigureWith.DEFAULT_INSTANCE.parameterSpace()) ?
this.getTestClass() :
new TestClass(parameterSpaceClass);
}
private ConfigureWith getConfigureWithAnnotation() {
ConfigureWith ret = this.getTestClass().getAnnotation(ConfigureWith.class);
if (ret == null)
ret = ConfigureWith.DEFAULT_INSTANCE;
return ret;
}
private ParameterSpace buildParameterSpace(List parameters, List constraints) {
return new ParameterSpace.Builder()
.addAllParameters(parameters)
.addAllConstraints(constraints)
.build();
}
private List createRunners() {
AtomicInteger i = new AtomicInteger(0);
return this.testSuite.stream()
.map((Function) tupleTestCase -> {
try {
return new MyBlockJUnit4ClassRunner(i.getAndIncrement(), tupleTestCase);
} catch (InitializationError initializationError) {
throw unexpectedByDesign(initializationError);
}
})
.collect(toList());
}
private static SortedMap buildParameterMap(TestClass parameterSpaceDefinitionTestClass) {
return new TreeMap() {
{
parameterSpaceDefinitionTestClass.getAnnotatedMethods(ParameterSource.class).forEach(
frameworkMethod -> put(frameworkMethod.getName(),
buildParameterFactoryCreatorFrom(frameworkMethod)
.apply(Utils.createInstanceOf(parameterSpaceDefinitionTestClass))
.create(frameworkMethod.getName())
));
}
};
}
private static TestSuite buildTestSuite(Config config, ParameterSpace parameterSpace) {
return Pipeline.Standard.create().execute(config, parameterSpace);
}
private static Function © 2015 - 2025 Weber Informatics LLC | Privacy Policy