
com.github.dakusui.crest.core.Matcher Maven / Gradle / Ivy
package com.github.dakusui.crest.core;
import com.github.dakusui.crest.functions.TransformingPredicate;
import java.util.*;
import java.util.function.Function;
import java.util.function.Predicate;
import static java.util.Collections.singletonList;
import static java.util.Objects.requireNonNull;
import static java.util.stream.Collectors.toList;
public interface Matcher {
boolean matches(T value, Assertion extends T> session);
List describeExpectation(Assertion extends T> session);
List describeMismatch(T value, Assertion extends T> session);
interface Composite extends Matcher {
abstract class Base implements Composite {
private final List> children;
private final boolean topLevel;
@SuppressWarnings("unchecked")
public Base(boolean topLevel, List> children) {
this.children = (List>) Collections.unmodifiableList((List extends T>) requireNonNull(children));
this.topLevel = topLevel;
}
@Override
public boolean matches(T value, Assertion extends T> session) {
boolean ret = first();
for (Matcher eachChild : children())
ret = op(ret, eachChild.matches(value, session));
return ret && session.exceptions().isEmpty();
}
@Override
public List describeExpectation(Assertion extends T> session) {
return new LinkedList() {{
add(String.format("%s:[", name()));
children().forEach(
(Matcher eachChild) -> {
List formattedExpectation = eachChild.describeExpectation(session);
if (formattedExpectation.size() == 1)
add(String.format(" %s", formattedExpectation.get(0)));
else {
addAll(indent(formattedExpectation));
}
}
);
add("]");
}};
}
@Override
public List describeMismatch(T value, Assertion extends T> session) {
return new LinkedList() {{
if (topLevel)
add(String.format("when x=%s; then %s:[", InternalUtils.formatValue(value), name()));
else
add(String.format("%s:[", name()));
for (Matcher eachChild : children()) {
if (eachChild.matches(value, session))
addAll(indent(eachChild.describeExpectation(session)));
else
addAll(indent(eachChild.describeMismatch(value, session)));
}
add(String.format("]->%s", matches(value, session)));
session.exceptions().forEach(
e -> {
add(e.getMessage());
addAll(
indent(Arrays.stream(e.getStackTrace()).map(
StackTraceElement::toString
).collect(toList())));
}
);
}};
}
List indent(List in) {
return in.stream().map(s -> " " + s).collect(toList());
}
List> children() {
return this.children;
}
abstract protected String name();
abstract protected boolean first();
abstract protected boolean op(boolean current, boolean next);
}
}
interface Conjunctive extends Composite {
@SuppressWarnings("unchecked")
static Matcher create(boolean topLevel, List> matchers) {
return new Conjunctive.Base(topLevel, matchers) {
@Override
protected String name() {
return "and";
}
@Override
protected boolean first() {
return true;
}
@Override
protected boolean op(boolean current, boolean next) {
return current && next;
}
};
}
}
interface Disjunctive extends Composite {
@SuppressWarnings("unchecked")
static Matcher create(boolean topLevel, List> matchers) {
return new Composite.Base(topLevel, matchers) {
@Override
protected String name() {
return "or";
}
@Override
protected boolean first() {
return false;
}
@Override
protected boolean op(boolean current, boolean next) {
return current || next;
}
};
}
}
interface Negative extends Composite {
static Matcher create(Matcher super T> matcher) {
return new Composite.Base(true, Collections.singletonList(matcher)) {
@Override
protected String name() {
return "not";
}
@Override
protected boolean first() {
return true;
}
@Override
protected boolean op(boolean current, boolean next) {
return current && !next;
}
};
}
}
interface Leaf extends Matcher {
static Matcher create(Predicate super O> p, Function super I, ? extends O> function) {
return new Matcher() {
@SuppressWarnings("unchecked")
@Override
public boolean matches(I value, Assertion extends I> session) {
return session.test((Predicate
© 2015 - 2025 Weber Informatics LLC | Privacy Policy