NodeUtils.java
- package com.github.dakusui.jcunitx.runners.core;
- import com.github.dakusui.jcunitx.core.AArray;
- import com.github.dakusui.jcunitx.exceptions.FrameworkException;
- import com.github.dakusui.jcunitx.factorspace.Constraint;
- import com.github.dakusui.jcunitx.runners.junit4.annotations.Condition;
- import com.github.dakusui.jcunitx.runners.junit4.annotations.ConfigureWith;
- import com.github.dakusui.jcunitx.runners.junit4.annotations.From;
- import org.junit.runners.model.FrameworkMethod;
- import org.junit.runners.model.TestClass;
- import java.lang.reflect.Method;
- import java.util.*;
- import java.util.concurrent.atomic.AtomicInteger;
- import java.util.function.Function;
- import java.util.function.Predicate;
- import java.util.stream.Collectors;
- import java.util.stream.Stream;
- import static com.github.dakusui.jcunitx.utils.Utils.createInstanceOf;
- import static com.github.dakusui.jcunitx.exceptions.FrameworkException.unexpectedByDesign;
- import static java.util.stream.Collectors.toList;
- public enum NodeUtils {
- ;
- public static TestInputPredicate buildPredicate(String[] values, SortedMap<String, TestInputPredicate> predicates_) {
- class Builder implements Node.Visitor {
- private final SortedMap<String, TestInputPredicate> predicates = predicates_;
- private Predicate<AArray> result;
- private final SortedSet<String> involvedKeys = new TreeSet<>();
- @Override
- public void visitLeaf(Node.Leaf leaf) {
- TestInputPredicate predicate = lookupTestPredicate(leaf.id()).orElseThrow(FrameworkException::unexpectedByDesign);
- involvedKeys.addAll(predicate.involvedKeys());
- if (leaf.args().length == 0)
- result = predicate;
- else
- result = tuple -> predicate.test(appendArgs(tuple, leaf));
- }
- private AArray appendArgs(AArray tuple, Node.Leaf leaf) {
- return new AArray.Builder() {{
- putAll(tuple);
- for (int i = 0; i < leaf.args().length; i++) {
- put(String.format("@arg[%s]", i), expandFactorValueIfNecessary(tuple, leaf.args()[i]));
- }
- }}.build();
- }
- private Object expandFactorValueIfNecessary(AArray tuple, String arg) {
- if (arg.startsWith("@"))
- return tuple.get(arg.substring(1));
- return arg;
- }
- @Override
- public void visitAnd(Node.And and) {
- and.children().forEach(
- node -> {
- Predicate<AArray> previous = result;
- node.accept(this);
- if (previous != null) {
- result = previous.and(result);
- }
- });
- }
- @Override
- public void visitOr(Node.Or or) {
- or.children().forEach(
- node -> {
- Predicate<AArray> previous = result;
- node.accept(this);
- if (previous != null) {
- result = previous.or(result);
- }
- });
- }
- @Override
- public void visitNot(Node.Not not) {
- not.target().accept(this);
- result = result.negate();
- }
- private Optional<TestInputPredicate> lookupTestPredicate(String name) {
- return this.predicates.containsKey(name) ?
- Optional.of(this.predicates.get(name)) :
- Optional.empty();
- }
- }
- Builder builder = new Builder();
- parse(values).accept(builder);
- return TestInputPredicate.of(
- Arrays.toString(values),
- new ArrayList<>(builder.involvedKeys),
- builder.result
- );
- }
- public static List<String> allLeaves(String[] values) {
- return new LinkedList<String>() {
- {
- parse(values).accept(
- new Node.Visitor.Base() {
- @Override
- public void visitLeaf(Node.Leaf leaf) {
- add(leaf.id());
- }
- });
- }
- };
- }
- public static SortedMap<String, TestInputPredicate> allTestPredicates(TestClass testClass) {
- ////
- // TestClass <>--------------> parameterSpace class
- // constraints
- // non-constraint-condition non-constraint-condition?
- // TestClass
- // constraints
- // non-constraint-condition
- return new TreeMap<>((Objects.equals(testClass.getJavaClass(), getParameterSpaceDefinitionClass(testClass)) ?
- streamTestPredicatesIn(testClass.getJavaClass()) :
- Stream.concat(
- streamTestPredicatesIn(getParameterSpaceDefinitionClass(testClass)),
- streamTestPredicatesIn(testClass.getJavaClass()).filter(
- each -> !(each instanceof Constraint)
- )
- )
- ).collect(Collectors.toMap(
- TestInputPredicate::getName,
- each -> each
- )));
- }
- private static Class<?> getParameterSpaceDefinitionClass(TestClass testClass) {
- ConfigureWith configureWith = testClass.getAnnotation(ConfigureWith.class);
- configureWith = configureWith == null ?
- ConfigureWith.DEFAULT_INSTANCE :
- configureWith;
- return Objects.equals(configureWith.parameterSpace(), Object.class) ?
- testClass.getJavaClass() :
- configureWith.parameterSpace();
- }
- private static Stream<TestInputPredicate> streamTestPredicatesIn(Class<?> parameterSpaceDefinitionClass) {
- TestClass wrapper = new TestClass(parameterSpaceDefinitionClass);
- Object testObject = createInstanceOf(wrapper);
- return wrapper.getAnnotatedMethods(Condition.class).stream(
- ).map(
- frameworkMethod -> createTestPredicate(testObject, frameworkMethod)
- );
- }
- public static TestInputPredicate createTestPredicate(Object testObject, FrameworkMethod frameworkMethod) {
- Method method = frameworkMethod.getMethod();
- //noinspection RedundantTypeArguments (to suppress a compilation error)
- List<String> involvedKeys = Stream.of(method.getParameterAnnotations())
- .map(annotations -> Stream.of(annotations)
- .filter(annotation -> annotation instanceof From)
- .map(From.class::cast)
- .map(From::value)
- .findFirst()
- .<FrameworkException>orElseThrow(FrameworkException::unexpectedByDesign))
- .collect(toList());
- int varargsIndex = method.isVarArgs() ?
- frameworkMethod.getMethod().getParameterCount() - 1 :
- -1;
- Predicate<AArray> predicate = (AArray tuple) -> {
- try {
- return (boolean) frameworkMethod.invokeExplosively(
- testObject,
- involvedKeys.stream()
- .map(new Function<String, Object>() {
- final AtomicInteger cur = new AtomicInteger(0);
- @Override
- public Object apply(String key) {
- if (key.equals("@arg"))
- return isVarArgs(cur.get()) ?
- getVarArgs() :
- getArg();
- return tuple.get(key);
- }
- private Object getArg() {
- return tuple.get(key(cur.getAndIncrement()));
- }
- private Object getVarArgs() {
- List<Object> work = new LinkedList<>();
- while (tuple.containsKey(key(cur.get()))) {
- work.add(getArg());
- }
- return work.toArray();
- }
- private boolean isVarArgs(int argIndex) {
- return argIndex == varargsIndex;
- }
- private String key(int i) {
- return String.format("@arg[%d]", i);
- }
- })
- .toArray());
- } catch (Throwable e) {
- throw unexpectedByDesign(e);
- }
- };
- return frameworkMethod.getAnnotation(Condition.class).constraint() ?
- Constraint.create(frameworkMethod.getName(), predicate, involvedKeys) :
- new TestInputPredicate() {
- @Override
- public String getName() {
- return frameworkMethod.getName();
- }
- @Override
- public boolean test(AArray tuple) {
- return predicate.test(tuple);
- }
- @Override
- public List<String> involvedKeys() {
- return involvedKeys;
- }
- };
- }
- public static Node parse(String[] values) {
- return new Node.Or.Impl(Stream.of(values)
- .map(NodeUtils::parseLine)
- .collect(toList()));
- }
- public static Node parseLine(String value) {
- return new Node.And.Impl(
- Stream.of(value.split("&&"))
- .map(s -> s.startsWith("!") ?
- new Node.Not.Impl(new Node.Leaf.Impl(s.substring(1))) :
- new Node.Leaf.Impl(s)
- )
- .collect(toList())
- );
- }
- }