From 2599ceeccbcfb531b3a95427b1b8904caf102242 Mon Sep 17 00:00:00 2001 From: Kristóf Marussy Date: Thu, 15 Jun 2023 20:41:09 +0200 Subject: refactor(query): structural equality matcher Add the ability to create assertions without pre-processing Dnf clauses (raw matchin mode). Also fix tests broken by Dnf pre-processing. --- .../MismatchDescribingDnfEqualityChecker.java | 32 +++++++++++--- .../refinery/store/query/tests/QueryMatchers.java | 27 ++++++++++++ .../store/query/tests/StructurallyEqualTo.java | 2 +- .../store/query/tests/StructurallyEqualToRaw.java | 51 ++++++++++++++++++++++ 4 files changed, 105 insertions(+), 7 deletions(-) create mode 100644 subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/StructurallyEqualToRaw.java (limited to 'subprojects/store-query/src/testFixtures/java') diff --git a/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/MismatchDescribingDnfEqualityChecker.java b/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/MismatchDescribingDnfEqualityChecker.java index a5b7f85a..6a3301b3 100644 --- a/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/MismatchDescribingDnfEqualityChecker.java +++ b/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/MismatchDescribingDnfEqualityChecker.java @@ -6,27 +6,47 @@ package tools.refinery.store.query.tests; import org.hamcrest.Description; +import tools.refinery.store.query.dnf.Dnf; +import tools.refinery.store.query.dnf.SymbolicParameter; import tools.refinery.store.query.equality.DeepDnfEqualityChecker; +import tools.refinery.store.query.literal.Literal; + +import java.util.List; class MismatchDescribingDnfEqualityChecker extends DeepDnfEqualityChecker { private final Description description; - private boolean described; + private boolean raw; + private boolean needsDescription = true; MismatchDescribingDnfEqualityChecker(Description description) { this.description = description; } - public boolean isDescribed() { - return described; + public boolean needsDescription() { + return needsDescription; + } + + @Override + public boolean dnfEqualRaw(List symbolicParameters, List> clauses, Dnf other) { + try { + raw = true; + boolean result = super.dnfEqualRaw(symbolicParameters, clauses, other); + if (!result && needsDescription) { + description.appendText("was ").appendText(other.toDefinitionString()); + } + return false; + } finally { + raw = false; + } } @Override protected boolean doCheckEqual(Pair pair) { boolean result = super.doCheckEqual(pair); - if (!result && !described) { + if (!result && needsDescription) { describeMismatch(pair); // Only describe the first found (innermost) mismatch. - described = true; + needsDescription = false; } return result; } @@ -34,7 +54,7 @@ class MismatchDescribingDnfEqualityChecker extends DeepDnfEqualityChecker { private void describeMismatch(Pair pair) { var inProgress = getInProgress(); int size = inProgress.size(); - if (size <= 1) { + if (size <= 1 && !raw) { description.appendText("was ").appendText(pair.right().toDefinitionString()); return; } diff --git a/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/QueryMatchers.java b/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/QueryMatchers.java index 8706ef70..cd449a6a 100644 --- a/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/QueryMatchers.java +++ b/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/QueryMatchers.java @@ -7,13 +7,40 @@ package tools.refinery.store.query.tests; import org.hamcrest.Matcher; import tools.refinery.store.query.dnf.Dnf; +import tools.refinery.store.query.dnf.SymbolicParameter; +import tools.refinery.store.query.literal.Literal; + +import java.util.List; public final class QueryMatchers { private QueryMatchers() { throw new IllegalStateException("This is a static utility class and should not be instantiated directly"); } + /** + * Compare two {@link Dnf} instances up to renaming of variables. + * + * @param expected The expected {@link Dnf} instance. + * @return A Hamcrest matcher for equality up to renaming of variables. + */ public static Matcher structurallyEqualTo(Dnf expected) { return new StructurallyEqualTo(expected); } + + /** + * Compare a {@link Dnf} instance to another predicate in DNF form without constructing it. + *

+ * This matcher should be used instead of {@link #structurallyEqualTo(Dnf)} when the validation and + * pre-processing associated with the {@link Dnf} constructor, i.e., validation of parameter directions, + * topological sorting of literals, and the reduction of trivial predicates is not desired. In particular, this + * matcher can be used to test for exact order of literal after pre-processing. + * + * @param expectedSymbolicParameters The expected list of symbolic parameters. + * @param expectedLiterals The expected clauses. Each clause is represented by a list of literals. + * @return A Hamcrest matcher for equality up to renaming of variables. + */ + public static Matcher structurallyEqualTo(List expectedSymbolicParameters, + List> expectedLiterals) { + return new StructurallyEqualToRaw(expectedSymbolicParameters, expectedLiterals); + } } diff --git a/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/StructurallyEqualTo.java b/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/StructurallyEqualTo.java index ba51c084..86149141 100644 --- a/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/StructurallyEqualTo.java +++ b/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/StructurallyEqualTo.java @@ -29,7 +29,7 @@ public class StructurallyEqualTo extends TypeSafeMatcher { if (describingChecker.dnfEqual(expected, item)) { throw new IllegalStateException("Mismatched Dnf was matching on repeated comparison"); } - if (!describingChecker.isDescribed()) { + if (describingChecker.needsDescription()) { super.describeMismatchSafely(item, mismatchDescription); } } diff --git a/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/StructurallyEqualToRaw.java b/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/StructurallyEqualToRaw.java new file mode 100644 index 00000000..2f8c2944 --- /dev/null +++ b/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/StructurallyEqualToRaw.java @@ -0,0 +1,51 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.tests; + +import org.hamcrest.Description; +import org.hamcrest.TypeSafeMatcher; +import tools.refinery.store.query.dnf.Dnf; +import tools.refinery.store.query.dnf.SymbolicParameter; +import tools.refinery.store.query.equality.DeepDnfEqualityChecker; +import tools.refinery.store.query.literal.Literal; + +import java.util.List; + +public class StructurallyEqualToRaw extends TypeSafeMatcher { + private final List expectedSymbolicParameters; + private final List> expectedClauses; + + public StructurallyEqualToRaw(List expectedSymbolicParameters, + List> expectedClauses) { + this.expectedSymbolicParameters = expectedSymbolicParameters; + this.expectedClauses = expectedClauses; + } + + @Override + protected boolean matchesSafely(Dnf item) { + var checker = new DeepDnfEqualityChecker(); + return checker.dnfEqualRaw(expectedSymbolicParameters, expectedClauses, item); + } + + @Override + protected void describeMismatchSafely(Dnf item, Description mismatchDescription) { + var describingChecker = new MismatchDescribingDnfEqualityChecker(mismatchDescription); + if (describingChecker.dnfEqualRaw(expectedSymbolicParameters, expectedClauses, item)) { + throw new IllegalStateException("Mismatched Dnf was matching on repeated comparison"); + } + if (describingChecker.needsDescription()) { + super.describeMismatchSafely(item, mismatchDescription); + } + } + + @Override + public void describeTo(Description description) { + description.appendText("structurally equal to ") + .appendValueList("(", ", ", ")", expectedSymbolicParameters) + .appendText(" <-> ") + .appendValueList("", ", ", ".", expectedClauses); + } +} -- cgit v1.2.3-54-g00ecf