diff options
9 files changed, 568 insertions, 107 deletions
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/Dnf.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/Dnf.java index 64790f42..c5b51b81 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/Dnf.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/Dnf.java | |||
@@ -119,6 +119,11 @@ public final class Dnf implements Constraint { | |||
119 | if (arity() != other.arity()) { | 119 | if (arity() != other.arity()) { |
120 | return false; | 120 | return false; |
121 | } | 121 | } |
122 | for (int i = 0; i < arity(); i++) { | ||
123 | if (!symbolicParameters.get(i).getDirection().equals(other.getSymbolicParameters().get(i).getDirection())) { | ||
124 | return false; | ||
125 | } | ||
126 | } | ||
122 | int numClauses = clauses.size(); | 127 | int numClauses = clauses.size(); |
123 | if (numClauses != other.clauses.size()) { | 128 | if (numClauses != other.clauses.size()) { |
124 | return false; | 129 | return false; |
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/DeepDnfEqualityChecker.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/DeepDnfEqualityChecker.java index bb60ccc9..1eeb5723 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/DeepDnfEqualityChecker.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/DeepDnfEqualityChecker.java | |||
@@ -6,6 +6,9 @@ | |||
6 | package tools.refinery.store.query.equality; | 6 | package tools.refinery.store.query.equality; |
7 | 7 | ||
8 | import tools.refinery.store.query.dnf.Dnf; | 8 | import tools.refinery.store.query.dnf.Dnf; |
9 | import tools.refinery.store.query.dnf.DnfClause; | ||
10 | import tools.refinery.store.query.dnf.SymbolicParameter; | ||
11 | import tools.refinery.store.query.literal.Literal; | ||
9 | import tools.refinery.store.util.CycleDetectingMapper; | 12 | import tools.refinery.store.util.CycleDetectingMapper; |
10 | 13 | ||
11 | import java.util.List; | 14 | import java.util.List; |
@@ -19,6 +22,45 @@ public class DeepDnfEqualityChecker implements DnfEqualityChecker { | |||
19 | return mapper.map(new Pair(left, right)); | 22 | return mapper.map(new Pair(left, right)); |
20 | } | 23 | } |
21 | 24 | ||
25 | public boolean dnfEqualRaw(List<SymbolicParameter> symbolicParameters, | ||
26 | List<? extends List<? extends Literal>> clauses, Dnf other) { | ||
27 | int arity = symbolicParameters.size(); | ||
28 | if (arity != other.arity()) { | ||
29 | return false; | ||
30 | } | ||
31 | for (int i = 0; i < arity; i++) { | ||
32 | if (!symbolicParameters.get(i).getDirection().equals(other.getSymbolicParameters().get(i).getDirection())) { | ||
33 | return false; | ||
34 | } | ||
35 | } | ||
36 | int numClauses = clauses.size(); | ||
37 | if (numClauses != other.getClauses().size()) { | ||
38 | return false; | ||
39 | } | ||
40 | for (int i = 0; i < numClauses; i++) { | ||
41 | var literalEqualityHelper = new LiteralEqualityHelper(this, symbolicParameters, | ||
42 | other.getSymbolicParameters()); | ||
43 | if (!equalsWithSubstitutionRaw(literalEqualityHelper, clauses.get(i), other.getClauses().get(i))) { | ||
44 | return false; | ||
45 | } | ||
46 | } | ||
47 | return true; | ||
48 | } | ||
49 | |||
50 | private boolean equalsWithSubstitutionRaw(LiteralEqualityHelper helper, List<? extends Literal> literals, | ||
51 | DnfClause other) { | ||
52 | int size = literals.size(); | ||
53 | if (size != other.literals().size()) { | ||
54 | return false; | ||
55 | } | ||
56 | for (int i = 0; i < size; i++) { | ||
57 | if (!literals.get(i).equalsWithSubstitution(helper, other.literals().get(i))) { | ||
58 | return false; | ||
59 | } | ||
60 | } | ||
61 | return true; | ||
62 | } | ||
63 | |||
22 | protected boolean doCheckEqual(Pair pair) { | 64 | protected boolean doCheckEqual(Pair pair) { |
23 | return pair.left.equalsWithSubstitution(this, pair.right); | 65 | return pair.left.equalsWithSubstitution(this, pair.right); |
24 | } | 66 | } |
diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/DnfBuilderVariableUnificationTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/DnfBuilderVariableUnificationTest.java index a54ad4d6..4a85fe32 100644 --- a/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/DnfBuilderVariableUnificationTest.java +++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/DnfBuilderVariableUnificationTest.java | |||
@@ -6,6 +6,8 @@ | |||
6 | package tools.refinery.store.query.dnf; | 6 | package tools.refinery.store.query.dnf; |
7 | 7 | ||
8 | import org.junit.jupiter.api.Test; | 8 | import org.junit.jupiter.api.Test; |
9 | import tools.refinery.store.query.term.ParameterDirection; | ||
10 | import tools.refinery.store.query.term.Variable; | ||
9 | import tools.refinery.store.query.view.KeyOnlyView; | 11 | import tools.refinery.store.query.view.KeyOnlyView; |
10 | import tools.refinery.store.query.view.SymbolView; | 12 | import tools.refinery.store.query.view.SymbolView; |
11 | import tools.refinery.store.representation.Symbol; | 13 | import tools.refinery.store.representation.Symbol; |
@@ -17,7 +19,7 @@ import static tools.refinery.store.query.tests.QueryMatchers.structurallyEqualTo | |||
17 | 19 | ||
18 | class DnfBuilderVariableUnificationTest { | 20 | class DnfBuilderVariableUnificationTest { |
19 | private final Symbol<Boolean> friend = new Symbol<>("friend", 2, Boolean.class, false); | 21 | private final Symbol<Boolean> friend = new Symbol<>("friend", 2, Boolean.class, false); |
20 | private final Symbol<Boolean> children = new Symbol<>("friend", 2, Boolean.class, false); | 22 | private final Symbol<Boolean> children = new Symbol<>("children", 2, Boolean.class, false); |
21 | private final SymbolView<Boolean> friendView = new KeyOnlyView<>(friend); | 23 | private final SymbolView<Boolean> friendView = new KeyOnlyView<>(friend); |
22 | private final SymbolView<Boolean> childrenView = new KeyOnlyView<>(children); | 24 | private final SymbolView<Boolean> childrenView = new KeyOnlyView<>(children); |
23 | 25 | ||
@@ -30,12 +32,14 @@ class DnfBuilderVariableUnificationTest { | |||
30 | p.isEquivalent(q) | 32 | p.isEquivalent(q) |
31 | )); | 33 | )); |
32 | }); | 34 | }); |
33 | var expected = Dnf.of(builder -> { | ||
34 | var p = builder.parameter("p"); | ||
35 | builder.clause(friendView.call(p, p)); | ||
36 | }); | ||
37 | 35 | ||
38 | assertThat(actual, structurallyEqualTo(expected)); | 36 | var expectedP = Variable.of("p"); |
37 | assertThat(actual, structurallyEqualTo( | ||
38 | List.of(new SymbolicParameter(expectedP, ParameterDirection.OUT)), | ||
39 | List.of( | ||
40 | List.of(friendView.call(expectedP, expectedP)) | ||
41 | ) | ||
42 | )); | ||
39 | } | 43 | } |
40 | 44 | ||
41 | @Test | 45 | @Test |
@@ -47,12 +51,14 @@ class DnfBuilderVariableUnificationTest { | |||
47 | q.isEquivalent(p) | 51 | q.isEquivalent(p) |
48 | )); | 52 | )); |
49 | }); | 53 | }); |
50 | var expected = Dnf.of(builder -> { | ||
51 | var p = builder.parameter("p"); | ||
52 | builder.clause(friendView.call(p, p)); | ||
53 | }); | ||
54 | 54 | ||
55 | assertThat(actual, structurallyEqualTo(expected)); | 55 | var expectedP = Variable.of("p"); |
56 | assertThat(actual, structurallyEqualTo( | ||
57 | List.of(new SymbolicParameter(expectedP, ParameterDirection.OUT)), | ||
58 | List.of( | ||
59 | List.of(friendView.call(expectedP, expectedP)) | ||
60 | ) | ||
61 | )); | ||
56 | } | 62 | } |
57 | 63 | ||
58 | @Test | 64 | @Test |
@@ -61,9 +67,14 @@ class DnfBuilderVariableUnificationTest { | |||
61 | friendView.call(p, q), | 67 | friendView.call(p, q), |
62 | p.isEquivalent(q) | 68 | p.isEquivalent(q) |
63 | ))); | 69 | ))); |
64 | var expected = Dnf.of(builder -> builder.clause(p -> List.of(friendView.call(p, p)))); | ||
65 | 70 | ||
66 | assertThat(actual, structurallyEqualTo(expected)); | 71 | var expectedP = Variable.of("p"); |
72 | assertThat(actual, structurallyEqualTo( | ||
73 | List.of(), | ||
74 | List.of( | ||
75 | List.of(friendView.call(expectedP, expectedP)) | ||
76 | ) | ||
77 | )); | ||
67 | } | 78 | } |
68 | 79 | ||
69 | @Test | 80 | @Test |
@@ -74,12 +85,14 @@ class DnfBuilderVariableUnificationTest { | |||
74 | childrenView.call(p, r), | 85 | childrenView.call(p, r), |
75 | q.isEquivalent(r) | 86 | q.isEquivalent(r) |
76 | ))); | 87 | ))); |
77 | var expected = Dnf.of(builder -> builder.clause(p -> List.of( | ||
78 | friendView.call(p, p), | ||
79 | childrenView.call(p, p) | ||
80 | ))); | ||
81 | 88 | ||
82 | assertThat(actual, structurallyEqualTo(expected)); | 89 | var expectedP = Variable.of("p"); |
90 | assertThat(actual, structurallyEqualTo( | ||
91 | List.of(), | ||
92 | List.of( | ||
93 | List.of(friendView.call(expectedP, expectedP), childrenView.call(expectedP, expectedP)) | ||
94 | ) | ||
95 | )); | ||
83 | } | 96 | } |
84 | 97 | ||
85 | @Test | 98 | @Test |
@@ -90,9 +103,14 @@ class DnfBuilderVariableUnificationTest { | |||
90 | friendView.call(p, r), | 103 | friendView.call(p, r), |
91 | q.isEquivalent(r) | 104 | q.isEquivalent(r) |
92 | ))); | 105 | ))); |
93 | var expected = Dnf.of(builder -> builder.clause(p -> List.of(friendView.call(p, p)))); | ||
94 | 106 | ||
95 | assertThat(actual, structurallyEqualTo(expected)); | 107 | var expectedP = Variable.of("p"); |
108 | assertThat(actual, structurallyEqualTo( | ||
109 | List.of(), | ||
110 | List.of( | ||
111 | List.of(friendView.call(expectedP, expectedP)) | ||
112 | ) | ||
113 | )); | ||
96 | } | 114 | } |
97 | 115 | ||
98 | @Test | 116 | @Test |
@@ -105,16 +123,18 @@ class DnfBuilderVariableUnificationTest { | |||
105 | p.isEquivalent(q) | 123 | p.isEquivalent(q) |
106 | ); | 124 | ); |
107 | }); | 125 | }); |
108 | var expected = Dnf.of(builder -> { | ||
109 | var p = builder.parameter("p"); | ||
110 | var q = builder.parameter("q"); | ||
111 | builder.clause( | ||
112 | q.isEquivalent(p), | ||
113 | friendView.call(p, p) | ||
114 | ); | ||
115 | }); | ||
116 | 126 | ||
117 | assertThat(actual, structurallyEqualTo(expected)); | 127 | var expectedP = Variable.of("p"); |
128 | var expectedQ = Variable.of("q"); | ||
129 | assertThat(actual, structurallyEqualTo( | ||
130 | List.of( | ||
131 | new SymbolicParameter(expectedP, ParameterDirection.OUT), | ||
132 | new SymbolicParameter(expectedQ, ParameterDirection.OUT) | ||
133 | ), | ||
134 | List.of( | ||
135 | List.of(friendView.call(expectedP, expectedP), expectedQ.isEquivalent(expectedP)) | ||
136 | ) | ||
137 | )); | ||
118 | } | 138 | } |
119 | 139 | ||
120 | @Test | 140 | @Test |
@@ -130,19 +150,25 @@ class DnfBuilderVariableUnificationTest { | |||
130 | r.isEquivalent(q) | 150 | r.isEquivalent(q) |
131 | ); | 151 | ); |
132 | }); | 152 | }); |
133 | var expected = Dnf.of(builder -> { | ||
134 | var p = builder.parameter("p"); | ||
135 | var q = builder.parameter("q"); | ||
136 | var r = builder.parameter("r"); | ||
137 | builder.clause( | ||
138 | q.isEquivalent(p), | ||
139 | r.isEquivalent(p), | ||
140 | friendView.call(p, p), | ||
141 | childrenView.call(p, p) | ||
142 | ); | ||
143 | }); | ||
144 | 153 | ||
145 | assertThat(actual, structurallyEqualTo(expected)); | 154 | var expectedP = Variable.of("p"); |
155 | var expectedQ = Variable.of("q"); | ||
156 | var expectedR = Variable.of("r"); | ||
157 | assertThat(actual, structurallyEqualTo( | ||
158 | List.of( | ||
159 | new SymbolicParameter(expectedP, ParameterDirection.OUT), | ||
160 | new SymbolicParameter(expectedQ, ParameterDirection.OUT), | ||
161 | new SymbolicParameter(expectedR, ParameterDirection.OUT) | ||
162 | ), | ||
163 | List.of( | ||
164 | List.of( | ||
165 | friendView.call(expectedP, expectedP), | ||
166 | expectedQ.isEquivalent(expectedP), | ||
167 | expectedR.isEquivalent(expectedP), | ||
168 | childrenView.call(expectedP, expectedP) | ||
169 | ) | ||
170 | ) | ||
171 | )); | ||
146 | } | 172 | } |
147 | 173 | ||
148 | @Test | 174 | @Test |
@@ -157,17 +183,23 @@ class DnfBuilderVariableUnificationTest { | |||
157 | q.isEquivalent(r) | 183 | q.isEquivalent(r) |
158 | )); | 184 | )); |
159 | }); | 185 | }); |
160 | var expected = Dnf.of(builder -> { | ||
161 | var p = builder.parameter("p"); | ||
162 | var q = builder.parameter("q"); | ||
163 | builder.clause( | ||
164 | q.isEquivalent(p), | ||
165 | friendView.call(p, p), | ||
166 | childrenView.call(p, p) | ||
167 | ); | ||
168 | }); | ||
169 | 186 | ||
170 | assertThat(actual, structurallyEqualTo(expected)); | 187 | |
188 | var expectedP = Variable.of("p"); | ||
189 | var expectedQ = Variable.of("q"); | ||
190 | assertThat(actual, structurallyEqualTo( | ||
191 | List.of( | ||
192 | new SymbolicParameter(expectedP, ParameterDirection.OUT), | ||
193 | new SymbolicParameter(expectedQ, ParameterDirection.OUT) | ||
194 | ), | ||
195 | List.of( | ||
196 | List.of( | ||
197 | friendView.call(expectedP, expectedP), | ||
198 | expectedQ.isEquivalent(expectedP), | ||
199 | childrenView.call(expectedP, expectedP) | ||
200 | ) | ||
201 | ) | ||
202 | )); | ||
171 | } | 203 | } |
172 | 204 | ||
173 | @Test | 205 | @Test |
@@ -182,17 +214,22 @@ class DnfBuilderVariableUnificationTest { | |||
182 | q.isEquivalent(r) | 214 | q.isEquivalent(r) |
183 | )); | 215 | )); |
184 | }); | 216 | }); |
185 | var expected = Dnf.of(builder -> { | ||
186 | var p = builder.parameter("p"); | ||
187 | var q = builder.parameter("q"); | ||
188 | builder.clause( | ||
189 | q.isEquivalent(p), | ||
190 | friendView.call(p, p), | ||
191 | childrenView.call(p, p) | ||
192 | ); | ||
193 | }); | ||
194 | 217 | ||
195 | assertThat(actual, structurallyEqualTo(expected)); | 218 | var expectedP = Variable.of("p"); |
219 | var expectedQ = Variable.of("q"); | ||
220 | assertThat(actual, structurallyEqualTo( | ||
221 | List.of( | ||
222 | new SymbolicParameter(expectedP, ParameterDirection.OUT), | ||
223 | new SymbolicParameter(expectedQ, ParameterDirection.OUT) | ||
224 | ), | ||
225 | List.of( | ||
226 | List.of( | ||
227 | friendView.call(expectedP, expectedP), | ||
228 | expectedQ.isEquivalent(expectedP), | ||
229 | childrenView.call(expectedP, expectedP) | ||
230 | ) | ||
231 | ) | ||
232 | )); | ||
196 | } | 233 | } |
197 | 234 | ||
198 | @Test | 235 | @Test |
@@ -207,17 +244,22 @@ class DnfBuilderVariableUnificationTest { | |||
207 | r.isEquivalent(q) | 244 | r.isEquivalent(q) |
208 | )); | 245 | )); |
209 | }); | 246 | }); |
210 | var expected = Dnf.of(builder -> { | ||
211 | var p = builder.parameter("p"); | ||
212 | var q = builder.parameter("q"); | ||
213 | builder.clause( | ||
214 | q.isEquivalent(p), | ||
215 | friendView.call(p, p), | ||
216 | childrenView.call(p, p) | ||
217 | ); | ||
218 | }); | ||
219 | 247 | ||
220 | assertThat(actual, structurallyEqualTo(expected)); | 248 | var expectedP = Variable.of("p"); |
249 | var expectedQ = Variable.of("q"); | ||
250 | assertThat(actual, structurallyEqualTo( | ||
251 | List.of( | ||
252 | new SymbolicParameter(expectedP, ParameterDirection.OUT), | ||
253 | new SymbolicParameter(expectedQ, ParameterDirection.OUT) | ||
254 | ), | ||
255 | List.of( | ||
256 | List.of( | ||
257 | friendView.call(expectedP, expectedP), | ||
258 | expectedQ.isEquivalent(expectedP), | ||
259 | childrenView.call(expectedP, expectedP) | ||
260 | ) | ||
261 | ) | ||
262 | )); | ||
221 | } | 263 | } |
222 | 264 | ||
223 | @Test | 265 | @Test |
@@ -232,17 +274,22 @@ class DnfBuilderVariableUnificationTest { | |||
232 | r.isEquivalent(q) | 274 | r.isEquivalent(q) |
233 | )); | 275 | )); |
234 | }); | 276 | }); |
235 | var expected = Dnf.of(builder -> { | ||
236 | var p = builder.parameter("p"); | ||
237 | var q = builder.parameter("q"); | ||
238 | builder.clause( | ||
239 | q.isEquivalent(p), | ||
240 | friendView.call(p, p), | ||
241 | childrenView.call(p, p) | ||
242 | ); | ||
243 | }); | ||
244 | 277 | ||
245 | assertThat(actual, structurallyEqualTo(expected)); | 278 | var expectedP = Variable.of("p"); |
279 | var expectedQ = Variable.of("q"); | ||
280 | assertThat(actual, structurallyEqualTo( | ||
281 | List.of( | ||
282 | new SymbolicParameter(expectedP, ParameterDirection.OUT), | ||
283 | new SymbolicParameter(expectedQ, ParameterDirection.OUT) | ||
284 | ), | ||
285 | List.of( | ||
286 | List.of( | ||
287 | friendView.call(expectedP, expectedP), | ||
288 | expectedQ.isEquivalent(expectedP), | ||
289 | childrenView.call(expectedP, expectedP) | ||
290 | ) | ||
291 | ) | ||
292 | )); | ||
246 | } | 293 | } |
247 | 294 | ||
248 | @Test | 295 | @Test |
@@ -258,16 +305,21 @@ class DnfBuilderVariableUnificationTest { | |||
258 | q.isEquivalent(s) | 305 | q.isEquivalent(s) |
259 | )); | 306 | )); |
260 | }); | 307 | }); |
261 | var expected = Dnf.of(builder -> { | ||
262 | var p = builder.parameter("p"); | ||
263 | var q = builder.parameter("q"); | ||
264 | builder.clause( | ||
265 | q.isEquivalent(p), | ||
266 | friendView.call(p, p), | ||
267 | childrenView.call(p, p) | ||
268 | ); | ||
269 | }); | ||
270 | 308 | ||
271 | assertThat(actual, structurallyEqualTo(expected)); | 309 | var expectedP = Variable.of("p"); |
310 | var expectedQ = Variable.of("q"); | ||
311 | assertThat(actual, structurallyEqualTo( | ||
312 | List.of( | ||
313 | new SymbolicParameter(expectedP, ParameterDirection.OUT), | ||
314 | new SymbolicParameter(expectedQ, ParameterDirection.OUT) | ||
315 | ), | ||
316 | List.of( | ||
317 | List.of( | ||
318 | friendView.call(expectedP, expectedP), | ||
319 | expectedQ.isEquivalent(expectedP), | ||
320 | childrenView.call(expectedP, expectedP) | ||
321 | ) | ||
322 | ) | ||
323 | )); | ||
272 | } | 324 | } |
273 | } | 325 | } |
diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/tests/StructurallyEqualToRawTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/tests/StructurallyEqualToRawTest.java new file mode 100644 index 00000000..07a55ff3 --- /dev/null +++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/tests/StructurallyEqualToRawTest.java | |||
@@ -0,0 +1,189 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.tests; | ||
7 | |||
8 | import org.junit.jupiter.api.Test; | ||
9 | import tools.refinery.store.query.dnf.Dnf; | ||
10 | import tools.refinery.store.query.dnf.SymbolicParameter; | ||
11 | import tools.refinery.store.query.term.ParameterDirection; | ||
12 | import tools.refinery.store.query.term.Variable; | ||
13 | import tools.refinery.store.query.view.KeyOnlyView; | ||
14 | import tools.refinery.store.representation.Symbol; | ||
15 | |||
16 | import java.util.List; | ||
17 | |||
18 | import static org.hamcrest.CoreMatchers.containsString; | ||
19 | import static org.hamcrest.MatcherAssert.assertThat; | ||
20 | import static org.hamcrest.Matchers.allOf; | ||
21 | import static org.junit.jupiter.api.Assertions.assertThrows; | ||
22 | import static tools.refinery.store.query.tests.QueryMatchers.structurallyEqualTo; | ||
23 | |||
24 | class StructurallyEqualToRawTest { | ||
25 | @Test | ||
26 | void flatEqualsTest() { | ||
27 | var p = Variable.of("p"); | ||
28 | var q = Variable.of("q"); | ||
29 | var person = new Symbol<>("Person", 1, Boolean.class, false); | ||
30 | var personView = new KeyOnlyView<>(person); | ||
31 | |||
32 | var actual = Dnf.builder("Actual").parameters(p).clause(personView.call(p)).build(); | ||
33 | |||
34 | assertThat(actual, structurallyEqualTo( | ||
35 | List.of(new SymbolicParameter(q, ParameterDirection.OUT)), | ||
36 | List.of(List.of(personView.call(q))) | ||
37 | )); | ||
38 | } | ||
39 | |||
40 | @Test | ||
41 | void flatNotEqualsTest() { | ||
42 | var p = Variable.of("p"); | ||
43 | var q = Variable.of("q"); | ||
44 | var friend = new Symbol<>("friend", 2, Boolean.class, false); | ||
45 | var friendView = new KeyOnlyView<>(friend); | ||
46 | |||
47 | var actual = Dnf.builder("Actual").parameters(p).clause(friendView.call(p, q)).build(); | ||
48 | |||
49 | var assertion = structurallyEqualTo( | ||
50 | List.of(new SymbolicParameter(q, ParameterDirection.OUT)), | ||
51 | List.of(List.of(friendView.call(q, q))) | ||
52 | ); | ||
53 | assertThrows(AssertionError.class, () -> assertThat(actual, assertion)); | ||
54 | } | ||
55 | |||
56 | @Test | ||
57 | void deepEqualsTest() { | ||
58 | var p = Variable.of("p"); | ||
59 | var q = Variable.of("q"); | ||
60 | var person = new Symbol<>("Person", 1, Boolean.class, false); | ||
61 | var personView = new KeyOnlyView<>(person); | ||
62 | |||
63 | var actual = Dnf.builder("Actual").parameters(q).clause( | ||
64 | Dnf.builder("Actual2").parameters(p).clause(personView.call(p)).build().call(q) | ||
65 | ).build(); | ||
66 | |||
67 | assertThat(actual, structurallyEqualTo( | ||
68 | List.of(new SymbolicParameter(q, ParameterDirection.OUT)), | ||
69 | List.of( | ||
70 | List.of( | ||
71 | Dnf.builder("Expected2").parameters(p).clause(personView.call(p)).build().call(q) | ||
72 | ) | ||
73 | ) | ||
74 | )); | ||
75 | } | ||
76 | |||
77 | @Test | ||
78 | void deepNotEqualsTest() { | ||
79 | var p = Variable.of("p"); | ||
80 | var q = Variable.of("q"); | ||
81 | var friend = new Symbol<>("friend", 2, Boolean.class, false); | ||
82 | var friendView = new KeyOnlyView<>(friend); | ||
83 | |||
84 | var actual = Dnf.builder("Actual").parameter(q).clause( | ||
85 | Dnf.builder("Actual2").parameters(p).clause(friendView.call(p, q)).build().call(q) | ||
86 | ).build(); | ||
87 | |||
88 | var assertion = structurallyEqualTo( | ||
89 | List.of(new SymbolicParameter(q, ParameterDirection.OUT)), | ||
90 | List.of( | ||
91 | List.of( | ||
92 | Dnf.builder("Expected2") | ||
93 | .parameters(p) | ||
94 | .clause(friendView.call(p, p)) | ||
95 | .build() | ||
96 | .call(q) | ||
97 | ) | ||
98 | ) | ||
99 | ); | ||
100 | var error = assertThrows(AssertionError.class, () -> assertThat(actual, assertion)); | ||
101 | assertThat(error.getMessage(), allOf(containsString("Expected2"), containsString("Actual2"))); | ||
102 | } | ||
103 | |||
104 | @Test | ||
105 | void parameterListLengthMismatchTest() { | ||
106 | var p = Variable.of("p"); | ||
107 | var q = Variable.of("q"); | ||
108 | var friend = new Symbol<>("friend", 2, Boolean.class, false); | ||
109 | var friendView = new KeyOnlyView<>(friend); | ||
110 | |||
111 | var actual = Dnf.builder("Actual").parameters(p, q).clause( | ||
112 | friendView.call(p, q) | ||
113 | ).build(); | ||
114 | |||
115 | var assertion = structurallyEqualTo( | ||
116 | List.of(new SymbolicParameter(p, ParameterDirection.OUT)), | ||
117 | List.of(List.of(friendView.call(p, p))) | ||
118 | ); | ||
119 | |||
120 | assertThrows(AssertionError.class, () -> assertThat(actual, assertion)); | ||
121 | } | ||
122 | |||
123 | @Test | ||
124 | void parameterDirectionMismatchTest() { | ||
125 | var p = Variable.of("p"); | ||
126 | var person = new Symbol<>("Person", 1, Boolean.class, false); | ||
127 | var personView = new KeyOnlyView<>(person); | ||
128 | |||
129 | var actual = Dnf.builder("Actual").parameter(p, ParameterDirection.IN).clause( | ||
130 | personView.call(p) | ||
131 | ).build(); | ||
132 | |||
133 | var assertion = structurallyEqualTo( | ||
134 | List.of(new SymbolicParameter(p, ParameterDirection.OUT)), | ||
135 | List.of(List.of(personView.call(p))) | ||
136 | ); | ||
137 | |||
138 | assertThrows(AssertionError.class, () -> assertThat(actual, assertion)); | ||
139 | } | ||
140 | |||
141 | @Test | ||
142 | void clauseCountMismatchTest() { | ||
143 | var p = Variable.of("p"); | ||
144 | var q = Variable.of("q"); | ||
145 | var friend = new Symbol<>("friend", 2, Boolean.class, false); | ||
146 | var friendView = new KeyOnlyView<>(friend); | ||
147 | |||
148 | var actual = Dnf.builder("Actual").parameters(p, q).clause( | ||
149 | friendView.call(p, q) | ||
150 | ).build(); | ||
151 | |||
152 | var assertion = structurallyEqualTo( | ||
153 | List.of( | ||
154 | new SymbolicParameter(p, ParameterDirection.OUT), | ||
155 | new SymbolicParameter(q, ParameterDirection.OUT) | ||
156 | ), | ||
157 | List.of( | ||
158 | List.of(friendView.call(p, q)), | ||
159 | List.of(friendView.call(q, p)) | ||
160 | ) | ||
161 | ); | ||
162 | |||
163 | assertThrows(AssertionError.class, () -> assertThat(actual, assertion)); | ||
164 | } | ||
165 | |||
166 | @Test | ||
167 | void literalCountMismatchTest() { | ||
168 | var p = Variable.of("p"); | ||
169 | var q = Variable.of("q"); | ||
170 | var friend = new Symbol<>("friend", 2, Boolean.class, false); | ||
171 | var friendView = new KeyOnlyView<>(friend); | ||
172 | |||
173 | var actual = Dnf.builder("Actual").parameters(p, q).clause( | ||
174 | friendView.call(p, q) | ||
175 | ).build(); | ||
176 | |||
177 | var assertion = structurallyEqualTo( | ||
178 | List.of( | ||
179 | new SymbolicParameter(p, ParameterDirection.OUT), | ||
180 | new SymbolicParameter(q, ParameterDirection.OUT) | ||
181 | ), | ||
182 | List.of( | ||
183 | List.of(friendView.call(p, q), friendView.call(q, p)) | ||
184 | ) | ||
185 | ); | ||
186 | |||
187 | assertThrows(AssertionError.class, () -> assertThat(actual, assertion)); | ||
188 | } | ||
189 | } | ||
diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/tests/StructurallyEqualToTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/tests/StructurallyEqualToTest.java index a1407288..e2983a3a 100644 --- a/subprojects/store-query/src/test/java/tools/refinery/store/query/tests/StructurallyEqualToTest.java +++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/tests/StructurallyEqualToTest.java | |||
@@ -7,6 +7,7 @@ package tools.refinery.store.query.tests; | |||
7 | 7 | ||
8 | import org.junit.jupiter.api.Test; | 8 | import org.junit.jupiter.api.Test; |
9 | import tools.refinery.store.query.dnf.Dnf; | 9 | import tools.refinery.store.query.dnf.Dnf; |
10 | import tools.refinery.store.query.term.ParameterDirection; | ||
10 | import tools.refinery.store.query.term.Variable; | 11 | import tools.refinery.store.query.term.Variable; |
11 | import tools.refinery.store.query.view.KeyOnlyView; | 12 | import tools.refinery.store.query.view.KeyOnlyView; |
12 | import tools.refinery.store.representation.Symbol; | 13 | import tools.refinery.store.representation.Symbol; |
@@ -34,11 +35,11 @@ class StructurallyEqualToTest { | |||
34 | void flatNotEqualsTest() { | 35 | void flatNotEqualsTest() { |
35 | var p = Variable.of("p"); | 36 | var p = Variable.of("p"); |
36 | var q = Variable.of("q"); | 37 | var q = Variable.of("q"); |
37 | var person = new Symbol<>("Person", 1, Boolean.class, false); | 38 | var friend = new Symbol<>("friend", 2, Boolean.class, false); |
38 | var personView = new KeyOnlyView<>(person); | 39 | var friendView = new KeyOnlyView<>(friend); |
39 | 40 | ||
40 | var expected = Dnf.builder("Expected").parameters(q).clause(personView.call(q)).build(); | 41 | var expected = Dnf.builder("Expected").parameters(q).clause(friendView.call(q, q)).build(); |
41 | var actual = Dnf.builder("Actual").parameters(p).clause(personView.call(q)).build(); | 42 | var actual = Dnf.builder("Actual").parameters(p).clause(friendView.call(p, q)).build(); |
42 | 43 | ||
43 | var assertion = structurallyEqualTo(expected); | 44 | var assertion = structurallyEqualTo(expected); |
44 | assertThrows(AssertionError.class, () -> assertThat(actual, assertion)); | 45 | assertThrows(AssertionError.class, () -> assertThat(actual, assertion)); |
@@ -65,18 +66,92 @@ class StructurallyEqualToTest { | |||
65 | void deepNotEqualsTest() { | 66 | void deepNotEqualsTest() { |
66 | var p = Variable.of("p"); | 67 | var p = Variable.of("p"); |
67 | var q = Variable.of("q"); | 68 | var q = Variable.of("q"); |
68 | var person = new Symbol<>("Person", 1, Boolean.class, false); | 69 | var friend = new Symbol<>("friend", 2, Boolean.class, false); |
69 | var personView = new KeyOnlyView<>(person); | 70 | var friendView = new KeyOnlyView<>(friend); |
70 | 71 | ||
71 | var expected = Dnf.builder("Expected").parameters(q).clause( | 72 | var expected = Dnf.builder("Expected").parameters(q).clause( |
72 | Dnf.builder("Expected2").parameters(p).clause(personView.call(p)).build().call(q) | 73 | Dnf.builder("Expected2").parameters(p).clause(friendView.call(p, p)).build().call(q) |
73 | ).build(); | 74 | ).build(); |
74 | var actual = Dnf.builder("Actual").parameters(q).clause( | 75 | var actual = Dnf.builder("Actual").parameter(q).clause( |
75 | Dnf.builder("Actual2").parameters(p).clause(personView.call(q)).build().call(q) | 76 | Dnf.builder("Actual2").parameters(p).clause(friendView.call(p, q)).build().call(q) |
76 | ).build(); | 77 | ).build(); |
77 | 78 | ||
78 | var assertion = structurallyEqualTo(expected); | 79 | var assertion = structurallyEqualTo(expected); |
79 | var error = assertThrows(AssertionError.class, () -> assertThat(actual, assertion)); | 80 | var error = assertThrows(AssertionError.class, () -> assertThat(actual, assertion)); |
80 | assertThat(error.getMessage(), containsString(" called from Expected/1 ")); | 81 | assertThat(error.getMessage(), containsString(" called from Expected/1 ")); |
81 | } | 82 | } |
83 | |||
84 | @Test | ||
85 | void parameterListLengthMismatchTest() { | ||
86 | var p = Variable.of("p"); | ||
87 | var q = Variable.of("q"); | ||
88 | var friend = new Symbol<>("friend", 2, Boolean.class, false); | ||
89 | var friendView = new KeyOnlyView<>(friend); | ||
90 | |||
91 | var expected = Dnf.builder("Expected").parameter(p).clause( | ||
92 | friendView.call(p, p) | ||
93 | ).build(); | ||
94 | var actual = Dnf.builder("Actual").parameters(p, q).clause( | ||
95 | friendView.call(p, q) | ||
96 | ).build(); | ||
97 | |||
98 | var assertion = structurallyEqualTo(expected); | ||
99 | assertThrows(AssertionError.class, () -> assertThat(actual, assertion)); | ||
100 | } | ||
101 | |||
102 | @Test | ||
103 | void parameterDirectionMismatchTest() { | ||
104 | var p = Variable.of("p"); | ||
105 | var person = new Symbol<>("Person", 1, Boolean.class, false); | ||
106 | var personView = new KeyOnlyView<>(person); | ||
107 | |||
108 | var expected = Dnf.builder("Expected").parameter(p, ParameterDirection.OUT).clause( | ||
109 | personView.call(p) | ||
110 | ).build(); | ||
111 | var actual = Dnf.builder("Actual").parameter(p, ParameterDirection.IN).clause( | ||
112 | personView.call(p) | ||
113 | ).build(); | ||
114 | |||
115 | var assertion = structurallyEqualTo(expected); | ||
116 | assertThrows(AssertionError.class, () -> assertThat(actual, assertion)); | ||
117 | } | ||
118 | |||
119 | @Test | ||
120 | void clauseCountMismatchTest() { | ||
121 | var p = Variable.of("p"); | ||
122 | var q = Variable.of("q"); | ||
123 | var friend = new Symbol<>("friend", 2, Boolean.class, false); | ||
124 | var friendView = new KeyOnlyView<>(friend); | ||
125 | |||
126 | var expected = Dnf.builder("Expected") | ||
127 | .parameters(p, q) | ||
128 | .clause(friendView.call(p, q)) | ||
129 | .clause(friendView.call(q, p)) | ||
130 | .build(); | ||
131 | var actual = Dnf.builder("Actual").parameters(p, q).clause( | ||
132 | friendView.call(p, q) | ||
133 | ).build(); | ||
134 | |||
135 | var assertion = structurallyEqualTo(expected); | ||
136 | assertThrows(AssertionError.class, () -> assertThat(actual, assertion)); | ||
137 | } | ||
138 | |||
139 | @Test | ||
140 | void literalCountMismatchTest() { | ||
141 | var p = Variable.of("p"); | ||
142 | var q = Variable.of("q"); | ||
143 | var friend = new Symbol<>("friend", 2, Boolean.class, false); | ||
144 | var friendView = new KeyOnlyView<>(friend); | ||
145 | |||
146 | var expected = Dnf.builder("Expected").parameters(p, q).clause( | ||
147 | friendView.call(p, q), | ||
148 | friendView.call(q, p) | ||
149 | ).build(); | ||
150 | var actual = Dnf.builder("Actual").parameters(p, q).clause( | ||
151 | friendView.call(p, q) | ||
152 | ).build(); | ||
153 | |||
154 | var assertion = structurallyEqualTo(expected); | ||
155 | assertThrows(AssertionError.class, () -> assertThat(actual, assertion)); | ||
156 | } | ||
82 | } | 157 | } |
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 @@ | |||
6 | package tools.refinery.store.query.tests; | 6 | package tools.refinery.store.query.tests; |
7 | 7 | ||
8 | import org.hamcrest.Description; | 8 | import org.hamcrest.Description; |
9 | import tools.refinery.store.query.dnf.Dnf; | ||
10 | import tools.refinery.store.query.dnf.SymbolicParameter; | ||
9 | import tools.refinery.store.query.equality.DeepDnfEqualityChecker; | 11 | import tools.refinery.store.query.equality.DeepDnfEqualityChecker; |
12 | import tools.refinery.store.query.literal.Literal; | ||
13 | |||
14 | import java.util.List; | ||
10 | 15 | ||
11 | class MismatchDescribingDnfEqualityChecker extends DeepDnfEqualityChecker { | 16 | class MismatchDescribingDnfEqualityChecker extends DeepDnfEqualityChecker { |
12 | private final Description description; | 17 | private final Description description; |
13 | private boolean described; | 18 | private boolean raw; |
19 | private boolean needsDescription = true; | ||
14 | 20 | ||
15 | MismatchDescribingDnfEqualityChecker(Description description) { | 21 | MismatchDescribingDnfEqualityChecker(Description description) { |
16 | this.description = description; | 22 | this.description = description; |
17 | } | 23 | } |
18 | 24 | ||
19 | public boolean isDescribed() { | 25 | public boolean needsDescription() { |
20 | return described; | 26 | return needsDescription; |
27 | } | ||
28 | |||
29 | @Override | ||
30 | public boolean dnfEqualRaw(List<SymbolicParameter> symbolicParameters, List<? extends List<? extends Literal>> clauses, Dnf other) { | ||
31 | try { | ||
32 | raw = true; | ||
33 | boolean result = super.dnfEqualRaw(symbolicParameters, clauses, other); | ||
34 | if (!result && needsDescription) { | ||
35 | description.appendText("was ").appendText(other.toDefinitionString()); | ||
36 | } | ||
37 | return false; | ||
38 | } finally { | ||
39 | raw = false; | ||
40 | } | ||
21 | } | 41 | } |
22 | 42 | ||
23 | @Override | 43 | @Override |
24 | protected boolean doCheckEqual(Pair pair) { | 44 | protected boolean doCheckEqual(Pair pair) { |
25 | boolean result = super.doCheckEqual(pair); | 45 | boolean result = super.doCheckEqual(pair); |
26 | if (!result && !described) { | 46 | if (!result && needsDescription) { |
27 | describeMismatch(pair); | 47 | describeMismatch(pair); |
28 | // Only describe the first found (innermost) mismatch. | 48 | // Only describe the first found (innermost) mismatch. |
29 | described = true; | 49 | needsDescription = false; |
30 | } | 50 | } |
31 | return result; | 51 | return result; |
32 | } | 52 | } |
@@ -34,7 +54,7 @@ class MismatchDescribingDnfEqualityChecker extends DeepDnfEqualityChecker { | |||
34 | private void describeMismatch(Pair pair) { | 54 | private void describeMismatch(Pair pair) { |
35 | var inProgress = getInProgress(); | 55 | var inProgress = getInProgress(); |
36 | int size = inProgress.size(); | 56 | int size = inProgress.size(); |
37 | if (size <= 1) { | 57 | if (size <= 1 && !raw) { |
38 | description.appendText("was ").appendText(pair.right().toDefinitionString()); | 58 | description.appendText("was ").appendText(pair.right().toDefinitionString()); |
39 | return; | 59 | return; |
40 | } | 60 | } |
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; | |||
7 | 7 | ||
8 | import org.hamcrest.Matcher; | 8 | import org.hamcrest.Matcher; |
9 | import tools.refinery.store.query.dnf.Dnf; | 9 | import tools.refinery.store.query.dnf.Dnf; |
10 | import tools.refinery.store.query.dnf.SymbolicParameter; | ||
11 | import tools.refinery.store.query.literal.Literal; | ||
12 | |||
13 | import java.util.List; | ||
10 | 14 | ||
11 | public final class QueryMatchers { | 15 | public final class QueryMatchers { |
12 | private QueryMatchers() { | 16 | private QueryMatchers() { |
13 | throw new IllegalStateException("This is a static utility class and should not be instantiated directly"); | 17 | throw new IllegalStateException("This is a static utility class and should not be instantiated directly"); |
14 | } | 18 | } |
15 | 19 | ||
20 | /** | ||
21 | * Compare two {@link Dnf} instances up to renaming of variables. | ||
22 | * | ||
23 | * @param expected The expected {@link Dnf} instance. | ||
24 | * @return A Hamcrest matcher for equality up to renaming of variables. | ||
25 | */ | ||
16 | public static Matcher<Dnf> structurallyEqualTo(Dnf expected) { | 26 | public static Matcher<Dnf> structurallyEqualTo(Dnf expected) { |
17 | return new StructurallyEqualTo(expected); | 27 | return new StructurallyEqualTo(expected); |
18 | } | 28 | } |
29 | |||
30 | /** | ||
31 | * Compare a {@link Dnf} instance to another predicate in DNF form without constructing it. | ||
32 | * <p> | ||
33 | * This matcher should be used instead of {@link #structurallyEqualTo(Dnf)} when the validation and | ||
34 | * pre-processing associated with the {@link Dnf} constructor, i.e., validation of parameter directions, | ||
35 | * topological sorting of literals, and the reduction of trivial predicates is not desired. In particular, this | ||
36 | * matcher can be used to test for exact order of literal after pre-processing. | ||
37 | * | ||
38 | * @param expectedSymbolicParameters The expected list of symbolic parameters. | ||
39 | * @param expectedLiterals The expected clauses. Each clause is represented by a list of literals. | ||
40 | * @return A Hamcrest matcher for equality up to renaming of variables. | ||
41 | */ | ||
42 | public static Matcher<Dnf> structurallyEqualTo(List<SymbolicParameter> expectedSymbolicParameters, | ||
43 | List<? extends List<? extends Literal>> expectedLiterals) { | ||
44 | return new StructurallyEqualToRaw(expectedSymbolicParameters, expectedLiterals); | ||
45 | } | ||
19 | } | 46 | } |
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<Dnf> { | |||
29 | if (describingChecker.dnfEqual(expected, item)) { | 29 | if (describingChecker.dnfEqual(expected, item)) { |
30 | throw new IllegalStateException("Mismatched Dnf was matching on repeated comparison"); | 30 | throw new IllegalStateException("Mismatched Dnf was matching on repeated comparison"); |
31 | } | 31 | } |
32 | if (!describingChecker.isDescribed()) { | 32 | if (describingChecker.needsDescription()) { |
33 | super.describeMismatchSafely(item, mismatchDescription); | 33 | super.describeMismatchSafely(item, mismatchDescription); |
34 | } | 34 | } |
35 | } | 35 | } |
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 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.tests; | ||
7 | |||
8 | import org.hamcrest.Description; | ||
9 | import org.hamcrest.TypeSafeMatcher; | ||
10 | import tools.refinery.store.query.dnf.Dnf; | ||
11 | import tools.refinery.store.query.dnf.SymbolicParameter; | ||
12 | import tools.refinery.store.query.equality.DeepDnfEqualityChecker; | ||
13 | import tools.refinery.store.query.literal.Literal; | ||
14 | |||
15 | import java.util.List; | ||
16 | |||
17 | public class StructurallyEqualToRaw extends TypeSafeMatcher<Dnf> { | ||
18 | private final List<SymbolicParameter> expectedSymbolicParameters; | ||
19 | private final List<? extends List<? extends Literal>> expectedClauses; | ||
20 | |||
21 | public StructurallyEqualToRaw(List<SymbolicParameter> expectedSymbolicParameters, | ||
22 | List<? extends List<? extends Literal>> expectedClauses) { | ||
23 | this.expectedSymbolicParameters = expectedSymbolicParameters; | ||
24 | this.expectedClauses = expectedClauses; | ||
25 | } | ||
26 | |||
27 | @Override | ||
28 | protected boolean matchesSafely(Dnf item) { | ||
29 | var checker = new DeepDnfEqualityChecker(); | ||
30 | return checker.dnfEqualRaw(expectedSymbolicParameters, expectedClauses, item); | ||
31 | } | ||
32 | |||
33 | @Override | ||
34 | protected void describeMismatchSafely(Dnf item, Description mismatchDescription) { | ||
35 | var describingChecker = new MismatchDescribingDnfEqualityChecker(mismatchDescription); | ||
36 | if (describingChecker.dnfEqualRaw(expectedSymbolicParameters, expectedClauses, item)) { | ||
37 | throw new IllegalStateException("Mismatched Dnf was matching on repeated comparison"); | ||
38 | } | ||
39 | if (describingChecker.needsDescription()) { | ||
40 | super.describeMismatchSafely(item, mismatchDescription); | ||
41 | } | ||
42 | } | ||
43 | |||
44 | @Override | ||
45 | public void describeTo(Description description) { | ||
46 | description.appendText("structurally equal to ") | ||
47 | .appendValueList("(", ", ", ")", expectedSymbolicParameters) | ||
48 | .appendText(" <-> ") | ||
49 | .appendValueList("", ", ", ".", expectedClauses); | ||
50 | } | ||
51 | } | ||