diff options
Diffstat (limited to 'subprojects/store-query/src/test/java')
10 files changed, 534 insertions, 201 deletions
diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/DnfBuilderLiteralEliminationTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/DnfBuilderLiteralEliminationTest.java index e17496e3..6a2dc0c7 100644 --- a/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/DnfBuilderLiteralEliminationTest.java +++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/DnfBuilderLiteralEliminationTest.java | |||
@@ -20,7 +20,7 @@ import tools.refinery.store.representation.Symbol; | |||
20 | import java.util.List; | 20 | import java.util.List; |
21 | 21 | ||
22 | import static org.hamcrest.MatcherAssert.assertThat; | 22 | import static org.hamcrest.MatcherAssert.assertThat; |
23 | import static tools.refinery.store.query.literal.Literals.assume; | 23 | import static tools.refinery.store.query.literal.Literals.check; |
24 | import static tools.refinery.store.query.literal.Literals.not; | 24 | import static tools.refinery.store.query.literal.Literals.not; |
25 | import static tools.refinery.store.query.tests.QueryMatchers.structurallyEqualTo; | 25 | import static tools.refinery.store.query.tests.QueryMatchers.structurallyEqualTo; |
26 | 26 | ||
@@ -47,7 +47,7 @@ class DnfBuilderLiteralEliminationTest { | |||
47 | void eliminateTrueAssumptionTest() { | 47 | void eliminateTrueAssumptionTest() { |
48 | var actual = Dnf.builder() | 48 | var actual = Dnf.builder() |
49 | .parameters(p, q) | 49 | .parameters(p, q) |
50 | .clause(assume(BoolTerms.constant(true)), friendView.call(p, q)) | 50 | .clause(check(BoolTerms.constant(true)), friendView.call(p, q)) |
51 | .build(); | 51 | .build(); |
52 | var expected = Dnf.builder().parameters(p, q).clause(friendView.call(p, q)).build(); | 52 | var expected = Dnf.builder().parameters(p, q).clause(friendView.call(p, q)).build(); |
53 | 53 | ||
@@ -75,7 +75,7 @@ class DnfBuilderLiteralEliminationTest { | |||
75 | var actual = Dnf.builder() | 75 | var actual = Dnf.builder() |
76 | .parameters(p, q) | 76 | .parameters(p, q) |
77 | .clause(friendView.call(p, q)) | 77 | .clause(friendView.call(p, q)) |
78 | .clause(friendView.call(q, p), assume(BoolTerms.constant(value))) | 78 | .clause(friendView.call(q, p), check(BoolTerms.constant(value))) |
79 | .build(); | 79 | .build(); |
80 | var expected = Dnf.builder().parameters(p, q).clause(friendView.call(p, q)).build(); | 80 | var expected = Dnf.builder().parameters(p, q).clause(friendView.call(p, q)).build(); |
81 | 81 | ||
@@ -207,4 +207,53 @@ class DnfBuilderLiteralEliminationTest { | |||
207 | 207 | ||
208 | assertThat(actual, structurallyEqualTo(expected)); | 208 | assertThat(actual, structurallyEqualTo(expected)); |
209 | } | 209 | } |
210 | |||
211 | @Test | ||
212 | void removeContradictoryTest() { | ||
213 | var actual = Dnf.of(builder -> builder.clause((p, q) -> List.of( | ||
214 | friendView.call(p, q), | ||
215 | not(friendView.call(p, q)) | ||
216 | ))); | ||
217 | var expected = Dnf.builder().build(); | ||
218 | |||
219 | assertThat(actual, structurallyEqualTo(expected)); | ||
220 | } | ||
221 | |||
222 | @Test | ||
223 | void removeContradictoryUniversalTest() { | ||
224 | var actual = Dnf.of(builder -> builder.clause((p, q) -> List.of( | ||
225 | friendView.call(q, q), | ||
226 | friendView.call(p, q), | ||
227 | not(friendView.call(p, Variable.of())) | ||
228 | ))); | ||
229 | var expected = Dnf.builder().build(); | ||
230 | |||
231 | assertThat(actual, structurallyEqualTo(expected)); | ||
232 | } | ||
233 | |||
234 | @Test | ||
235 | void removeContradictoryExistentialUniversalTest() { | ||
236 | var actual = Dnf.of(builder -> builder.clause((p) -> List.of( | ||
237 | friendView.call(p, Variable.of()), | ||
238 | not(friendView.call(p, Variable.of())) | ||
239 | ))); | ||
240 | var expected = Dnf.builder().build(); | ||
241 | |||
242 | assertThat(actual, structurallyEqualTo(expected)); | ||
243 | } | ||
244 | |||
245 | @Test | ||
246 | void removeContradictoryUniversalParameterTest() { | ||
247 | var actual = Dnf.of(builder -> { | ||
248 | var p = builder.parameter("p"); | ||
249 | builder.clause((q) -> List.of( | ||
250 | friendView.call(q, q), | ||
251 | friendView.call(p, q), | ||
252 | not(friendView.call(p, Variable.of())) | ||
253 | )); | ||
254 | }); | ||
255 | var expected = Dnf.builder().parameter(p).build(); | ||
256 | |||
257 | assertThat(actual, structurallyEqualTo(expected)); | ||
258 | } | ||
210 | } | 259 | } |
diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/DnfToDefinitionStringTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/DnfToDefinitionStringTest.java index d75d7f17..12cfaa4e 100644 --- a/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/DnfToDefinitionStringTest.java +++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/DnfToDefinitionStringTest.java | |||
@@ -50,7 +50,7 @@ class DnfToDefinitionStringTest { | |||
50 | var dnf = Dnf.builder("Example").parameter(p, ParameterDirection.IN).clause().build(); | 50 | var dnf = Dnf.builder("Example").parameter(p, ParameterDirection.IN).clause().build(); |
51 | 51 | ||
52 | assertThat(dnf.toDefinitionString(), is(""" | 52 | assertThat(dnf.toDefinitionString(), is(""" |
53 | pred Example(@In p) <-> | 53 | pred Example(in p) <-> |
54 | <empty>. | 54 | <empty>. |
55 | """)); | 55 | """)); |
56 | } | 56 | } |
@@ -73,7 +73,7 @@ class DnfToDefinitionStringTest { | |||
73 | .build(); | 73 | .build(); |
74 | 74 | ||
75 | assertThat(dnf.toDefinitionString(), is(""" | 75 | assertThat(dnf.toDefinitionString(), is(""" |
76 | pred Example(@In p) <-> | 76 | pred Example(in p) <-> |
77 | !(@RelationView("key") friend(p, q)). | 77 | !(@RelationView("key") friend(p, q)). |
78 | """)); | 78 | """)); |
79 | } | 79 | } |
diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/HashCodeTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/HashCodeTest.java new file mode 100644 index 00000000..0c8eaeed --- /dev/null +++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/HashCodeTest.java | |||
@@ -0,0 +1,67 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.dnf; | ||
7 | |||
8 | import org.junit.jupiter.api.Test; | ||
9 | import tools.refinery.store.query.term.NodeVariable; | ||
10 | import tools.refinery.store.query.term.Variable; | ||
11 | import tools.refinery.store.query.view.AnySymbolView; | ||
12 | import tools.refinery.store.query.view.KeyOnlyView; | ||
13 | import tools.refinery.store.representation.Symbol; | ||
14 | |||
15 | import static org.hamcrest.MatcherAssert.assertThat; | ||
16 | import static org.hamcrest.Matchers.is; | ||
17 | import static org.hamcrest.Matchers.not; | ||
18 | |||
19 | class HashCodeTest { | ||
20 | private static final Symbol<Boolean> person = Symbol.of("Person", 1); | ||
21 | private static final Symbol<Boolean> friend = Symbol.of("friend", 2); | ||
22 | private static final AnySymbolView personView = new KeyOnlyView<>(person); | ||
23 | private static final AnySymbolView friendView = new KeyOnlyView<>(friend); | ||
24 | private static final NodeVariable p = Variable.of("p"); | ||
25 | private static final NodeVariable q = Variable.of("q"); | ||
26 | |||
27 | @Test | ||
28 | void flatEqualsTest() { | ||
29 | var expected = Dnf.builder("Expected").parameters(q).clause(personView.call(q)).build(); | ||
30 | var actual = Dnf.builder("Actual").parameters(p).clause(personView.call(p)).build(); | ||
31 | |||
32 | assertThat(actual.hashCodeWithSubstitution(), is(expected.hashCodeWithSubstitution())); | ||
33 | } | ||
34 | |||
35 | @Test | ||
36 | void flatNotEqualsTest() { | ||
37 | var expected = Dnf.builder("Expected").parameters(q).clause(friendView.call(q, q)).build(); | ||
38 | var actual = Dnf.builder("Actual").parameters(p).clause(friendView.call(p, q)).build(); | ||
39 | |||
40 | assertThat(actual.hashCodeWithSubstitution(), not(expected.hashCodeWithSubstitution())); | ||
41 | } | ||
42 | |||
43 | @Test | ||
44 | void deepEqualsTest() { | ||
45 | var expected2 = Dnf.builder("Expected2").parameters(p).clause(personView.call(p)).build(); | ||
46 | var expected = Dnf.builder("Expected").parameters(q).clause( | ||
47 | expected2.call(q) | ||
48 | ).build(); | ||
49 | var actual = Dnf.builder("Actual").parameters(q).clause( | ||
50 | expected2.call(q) | ||
51 | ).build(); | ||
52 | |||
53 | assertThat(actual.hashCodeWithSubstitution(), is(expected.hashCodeWithSubstitution())); | ||
54 | } | ||
55 | |||
56 | @Test | ||
57 | void deepNotEqualsTest() { | ||
58 | var expected = Dnf.builder("Expected").parameters(q).clause( | ||
59 | Dnf.builder("Expected2").parameters(p).clause(personView.call(p)).build().call(q) | ||
60 | ).build(); | ||
61 | var actual = Dnf.builder("Actual").parameters(q).clause( | ||
62 | Dnf.builder("Actual2").parameters(p).clause(personView.call(p)).build().call(q) | ||
63 | ).build(); | ||
64 | |||
65 | assertThat(actual.hashCodeWithSubstitution(), not(expected.hashCodeWithSubstitution())); | ||
66 | } | ||
67 | } | ||
diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/TopologicalSortTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/TopologicalSortTest.java index e22dbb21..854bd469 100644 --- a/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/TopologicalSortTest.java +++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/TopologicalSortTest.java | |||
@@ -6,6 +6,7 @@ | |||
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.InvalidQueryException; | ||
9 | import tools.refinery.store.query.term.NodeVariable; | 10 | import tools.refinery.store.query.term.NodeVariable; |
10 | import tools.refinery.store.query.term.ParameterDirection; | 11 | import tools.refinery.store.query.term.ParameterDirection; |
11 | import tools.refinery.store.query.term.Variable; | 12 | import tools.refinery.store.query.term.Variable; |
@@ -80,7 +81,7 @@ class TopologicalSortTest { | |||
80 | example.call(r, t, q, s), | 81 | example.call(r, t, q, s), |
81 | friendView.call(r, t) | 82 | friendView.call(r, t) |
82 | ); | 83 | ); |
83 | assertThrows(IllegalArgumentException.class, builder::build); | 84 | assertThrows(InvalidQueryException.class, builder::build); |
84 | } | 85 | } |
85 | 86 | ||
86 | @Test | 87 | @Test |
@@ -93,7 +94,7 @@ class TopologicalSortTest { | |||
93 | example.call(p, q, r, s), | 94 | example.call(p, q, r, s), |
94 | example.call(r, t, q, s) | 95 | example.call(r, t, q, s) |
95 | ); | 96 | ); |
96 | assertThrows(IllegalArgumentException.class, builder::build); | 97 | assertThrows(InvalidQueryException.class, builder::build); |
97 | } | 98 | } |
98 | 99 | ||
99 | @Test | 100 | @Test |
@@ -107,6 +108,6 @@ class TopologicalSortTest { | |||
107 | example.call(r, t, q, s), | 108 | example.call(r, t, q, s), |
108 | example.call(p, q, r, t) | 109 | example.call(p, q, r, t) |
109 | ); | 110 | ); |
110 | assertThrows(IllegalArgumentException.class, builder::build); | 111 | assertThrows(InvalidQueryException.class, builder::build); |
111 | } | 112 | } |
112 | } | 113 | } |
diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/VariableDirectionTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/VariableDirectionTest.java index c52d26b2..fc3f5d48 100644 --- a/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/VariableDirectionTest.java +++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/VariableDirectionTest.java | |||
@@ -28,9 +28,8 @@ import static org.hamcrest.Matchers.hasItem; | |||
28 | import static org.hamcrest.Matchers.not; | 28 | import static org.hamcrest.Matchers.not; |
29 | import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; | 29 | import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; |
30 | import static org.junit.jupiter.api.Assertions.assertThrows; | 30 | import static org.junit.jupiter.api.Assertions.assertThrows; |
31 | import static tools.refinery.store.query.literal.Literals.assume; | ||
32 | import static tools.refinery.store.query.literal.Literals.not; | 31 | import static tools.refinery.store.query.literal.Literals.not; |
33 | import static tools.refinery.store.query.term.int_.IntTerms.*; | 32 | import static tools.refinery.store.query.term.int_.IntTerms.INT_SUM; |
34 | 33 | ||
35 | class VariableDirectionTest { | 34 | class VariableDirectionTest { |
36 | private static final Symbol<Boolean> person = Symbol.of("Person", 1); | 35 | private static final Symbol<Boolean> person = Symbol.of("Person", 1); |
@@ -49,7 +48,7 @@ class VariableDirectionTest { | |||
49 | @MethodSource("clausesWithVariableInput") | 48 | @MethodSource("clausesWithVariableInput") |
50 | void unboundOutVariableTest(List<? extends Literal> clause) { | 49 | void unboundOutVariableTest(List<? extends Literal> clause) { |
51 | var builder = Dnf.builder().parameter(p, ParameterDirection.OUT).clause(clause); | 50 | var builder = Dnf.builder().parameter(p, ParameterDirection.OUT).clause(clause); |
52 | assertThrows(IllegalArgumentException.class, builder::build); | 51 | assertThrows(InvalidClauseException.class, builder::build); |
53 | } | 52 | } |
54 | 53 | ||
55 | @ParameterizedTest | 54 | @ParameterizedTest |
@@ -101,7 +100,7 @@ class VariableDirectionTest { | |||
101 | var clauseWithEquivalence = new ArrayList<Literal>(clause); | 100 | var clauseWithEquivalence = new ArrayList<Literal>(clause); |
102 | clauseWithEquivalence.add(r.isEquivalent(p)); | 101 | clauseWithEquivalence.add(r.isEquivalent(p)); |
103 | var builder = Dnf.builder().clause(clauseWithEquivalence); | 102 | var builder = Dnf.builder().clause(clauseWithEquivalence); |
104 | assertThrows(IllegalArgumentException.class, builder::build); | 103 | assertThrows(InvalidClauseException.class, builder::build); |
105 | } | 104 | } |
106 | 105 | ||
107 | static Stream<Arguments> clausesNotBindingVariable() { | 106 | static Stream<Arguments> clausesNotBindingVariable() { |
@@ -119,7 +118,7 @@ class VariableDirectionTest { | |||
119 | @MethodSource("literalsWithPrivateVariable") | 118 | @MethodSource("literalsWithPrivateVariable") |
120 | void unboundTwicePrivateVariableTest(Literal literal) { | 119 | void unboundTwicePrivateVariableTest(Literal literal) { |
121 | var builder = Dnf.builder().clause(not(personView.call(p)), literal); | 120 | var builder = Dnf.builder().clause(not(personView.call(p)), literal); |
122 | assertThrows(IllegalArgumentException.class, builder::build); | 121 | assertThrows(InvalidClauseException.class, builder::build); |
123 | } | 122 | } |
124 | 123 | ||
125 | @ParameterizedTest | 124 | @ParameterizedTest |
@@ -127,7 +126,7 @@ class VariableDirectionTest { | |||
127 | void unboundTwiceByEquivalencePrivateVariableTest(Literal literal) { | 126 | void unboundTwiceByEquivalencePrivateVariableTest(Literal literal) { |
128 | var r = Variable.of("r"); | 127 | var r = Variable.of("r"); |
129 | var builder = Dnf.builder().clause(not(personView.call(r)), r.isEquivalent(p), literal); | 128 | var builder = Dnf.builder().clause(not(personView.call(r)), r.isEquivalent(p), literal); |
130 | assertThrows(IllegalArgumentException.class, builder::build); | 129 | assertThrows(InvalidClauseException.class, builder::build); |
131 | } | 130 | } |
132 | 131 | ||
133 | static Stream<Arguments> literalsWithPrivateVariable() { | 132 | static Stream<Arguments> literalsWithPrivateVariable() { |
@@ -160,7 +159,7 @@ class VariableDirectionTest { | |||
160 | @MethodSource("literalsWithRequiredVariableInput") | 159 | @MethodSource("literalsWithRequiredVariableInput") |
161 | void unboundPrivateVariableTest(Literal literal) { | 160 | void unboundPrivateVariableTest(Literal literal) { |
162 | var builder = Dnf.builder().clause(literal); | 161 | var builder = Dnf.builder().clause(literal); |
163 | assertThrows(IllegalArgumentException.class, builder::build); | 162 | assertThrows(InvalidClauseException.class, builder::build); |
164 | } | 163 | } |
165 | 164 | ||
166 | @ParameterizedTest | 165 | @ParameterizedTest |
@@ -246,182 +245,6 @@ class VariableDirectionTest { | |||
246 | ); | 245 | ); |
247 | } | 246 | } |
248 | 247 | ||
249 | @ParameterizedTest | ||
250 | @MethodSource("clausesWithDataVariableInput") | ||
251 | void unboundOutDataVariableTest(List<? extends Literal> clause) { | ||
252 | var builder = Dnf.builder().parameter(x, ParameterDirection.OUT).clause(clause); | ||
253 | assertThrows(IllegalArgumentException.class, builder::build); | ||
254 | } | ||
255 | |||
256 | @ParameterizedTest | ||
257 | @MethodSource("clausesWithDataVariableInput") | ||
258 | void unboundInDataVariableTest(List<? extends Literal> clause) { | ||
259 | var builder = Dnf.builder().parameter(x, ParameterDirection.IN).clause(clause); | ||
260 | var dnf = assertDoesNotThrow(builder::build); | ||
261 | var clauses = dnf.getClauses(); | ||
262 | if (clauses.size() > 0) { | ||
263 | assertThat(clauses.get(0).positiveVariables(), hasItem(x)); | ||
264 | } | ||
265 | } | ||
266 | |||
267 | @ParameterizedTest | ||
268 | @MethodSource("clausesWithDataVariableInput") | ||
269 | void boundPrivateDataVariableTest(List<? extends Literal> clause) { | ||
270 | var clauseWithBinding = new ArrayList<Literal>(clause); | ||
271 | clauseWithBinding.add(x.assign(constant(27))); | ||
272 | var builder = Dnf.builder().clause(clauseWithBinding); | ||
273 | var dnf = assertDoesNotThrow(builder::build); | ||
274 | var clauses = dnf.getClauses(); | ||
275 | if (clauses.size() > 0) { | ||
276 | assertThat(clauses.get(0).positiveVariables(), hasItem(x)); | ||
277 | } | ||
278 | } | ||
279 | |||
280 | static Stream<Arguments> clausesWithDataVariableInput() { | ||
281 | return Stream.concat( | ||
282 | clausesNotBindingDataVariable(), | ||
283 | literalToClauseArgumentStream(literalsWithRequiredDataVariableInput()) | ||
284 | ); | ||
285 | } | ||
286 | |||
287 | @ParameterizedTest | ||
288 | @MethodSource("clausesNotBindingDataVariable") | ||
289 | void unboundPrivateDataVariableTest(List<? extends Literal> clause) { | ||
290 | var builder = Dnf.builder().clause(clause); | ||
291 | var dnf = assertDoesNotThrow(builder::build); | ||
292 | var clauses = dnf.getClauses(); | ||
293 | if (clauses.size() > 0) { | ||
294 | assertThat(clauses.get(0).positiveVariables(), not(hasItem(x))); | ||
295 | } | ||
296 | } | ||
297 | |||
298 | static Stream<Arguments> clausesNotBindingDataVariable() { | ||
299 | return Stream.concat( | ||
300 | Stream.of( | ||
301 | Arguments.of(List.of()), | ||
302 | Arguments.of(List.of(BooleanLiteral.TRUE)), | ||
303 | Arguments.of(List.of(BooleanLiteral.FALSE)) | ||
304 | ), | ||
305 | literalToClauseArgumentStream(literalsWithPrivateDataVariable()) | ||
306 | ); | ||
307 | } | ||
308 | |||
309 | @ParameterizedTest | ||
310 | @MethodSource("literalsWithPrivateDataVariable") | ||
311 | void unboundTwicePrivateDataVariableTest(Literal literal) { | ||
312 | var builder = Dnf.builder().clause(not(ageView.call(p, x)), literal); | ||
313 | assertThrows(IllegalArgumentException.class, builder::build); | ||
314 | } | ||
315 | |||
316 | static Stream<Arguments> literalsWithPrivateDataVariable() { | ||
317 | var dnfWithOutput = Dnf.builder("WithDataOutput") | ||
318 | .parameter(y, ParameterDirection.OUT) | ||
319 | .parameter(q, ParameterDirection.OUT) | ||
320 | .clause(ageView.call(q, y)) | ||
321 | .build(); | ||
322 | |||
323 | return Stream.of( | ||
324 | Arguments.of(not(ageView.call(q, x))), | ||
325 | Arguments.of(y.assign(ageView.count(q, x))), | ||
326 | Arguments.of(not(dnfWithOutput.call(x, q))) | ||
327 | ); | ||
328 | } | ||
329 | |||
330 | @ParameterizedTest | ||
331 | @MethodSource("literalsWithRequiredDataVariableInput") | ||
332 | void unboundPrivateDataVariableTest(Literal literal) { | ||
333 | var builder = Dnf.builder().clause(literal); | ||
334 | assertThrows(IllegalArgumentException.class, builder::build); | ||
335 | } | ||
336 | |||
337 | static Stream<Arguments> literalsWithRequiredDataVariableInput() { | ||
338 | var dnfWithInput = Dnf.builder("WithDataInput") | ||
339 | .parameter(y, ParameterDirection.IN) | ||
340 | .parameter(q, ParameterDirection.OUT) | ||
341 | .clause(ageView.call(q, x)) | ||
342 | .build(); | ||
343 | // We are passing {@code y} to the parameter named {@code right} of {@code greaterEq}. | ||
344 | @SuppressWarnings("SuspiciousNameCombination") | ||
345 | var dnfWithInputToAggregate = Dnf.builder("WithDataInputToAggregate") | ||
346 | .parameter(y, ParameterDirection.IN) | ||
347 | .parameter(q, ParameterDirection.OUT) | ||
348 | .parameter(x, ParameterDirection.OUT) | ||
349 | .clause( | ||
350 | friendView.call(p, q), | ||
351 | ageView.call(q, x), | ||
352 | assume(greaterEq(x, y)) | ||
353 | ) | ||
354 | .build(); | ||
355 | |||
356 | return Stream.of( | ||
357 | Arguments.of(dnfWithInput.call(x, q)), | ||
358 | Arguments.of(not(dnfWithInput.call(x, q))), | ||
359 | Arguments.of(y.assign(dnfWithInput.count(x, q))), | ||
360 | Arguments.of(y.assign(dnfWithInputToAggregate.aggregateBy(z, INT_SUM, x, q, z))) | ||
361 | ); | ||
362 | } | ||
363 | |||
364 | @ParameterizedTest | ||
365 | @MethodSource("literalsWithDataVariableOutput") | ||
366 | void boundDataParameterTest(Literal literal) { | ||
367 | var builder = Dnf.builder().parameter(x, ParameterDirection.OUT).clause(literal); | ||
368 | var dnf = assertDoesNotThrow(builder::build); | ||
369 | assertThat(dnf.getClauses().get(0).positiveVariables(), hasItem(x)); | ||
370 | } | ||
371 | |||
372 | @ParameterizedTest | ||
373 | @MethodSource("literalsWithDataVariableOutput") | ||
374 | void boundTwiceDataParameterTest(Literal literal) { | ||
375 | var builder = Dnf.builder().parameter(x, ParameterDirection.IN).clause(literal); | ||
376 | assertThrows(IllegalArgumentException.class, builder::build); | ||
377 | } | ||
378 | |||
379 | @ParameterizedTest | ||
380 | @MethodSource("literalsWithDataVariableOutput") | ||
381 | void boundPrivateDataVariableOutputTest(Literal literal) { | ||
382 | var dnfWithInput = Dnf.builder("WithInput") | ||
383 | .parameter(x, ParameterDirection.IN) | ||
384 | .clause(assume(greaterEq(x, constant(24)))) | ||
385 | .build(); | ||
386 | var builder = Dnf.builder().clause(dnfWithInput.call(x), literal); | ||
387 | var dnf = assertDoesNotThrow(builder::build); | ||
388 | assertThat(dnf.getClauses().get(0).positiveVariables(), hasItem(x)); | ||
389 | } | ||
390 | |||
391 | @ParameterizedTest | ||
392 | @MethodSource("literalsWithDataVariableOutput") | ||
393 | void boundTwicePrivateDataVariableOutputTest(Literal literal) { | ||
394 | var builder = Dnf.builder().clause(x.assign(constant(27)), literal); | ||
395 | assertThrows(IllegalArgumentException.class, builder::build); | ||
396 | } | ||
397 | |||
398 | static Stream<Arguments> literalsWithDataVariableOutput() { | ||
399 | var dnfWithOutput = Dnf.builder("WithOutput") | ||
400 | .parameter(q, ParameterDirection.OUT) | ||
401 | .clause(personView.call(q)) | ||
402 | .build(); | ||
403 | var dnfWithDataOutput = Dnf.builder("WithDataOutput") | ||
404 | .parameter(y, ParameterDirection.OUT) | ||
405 | .parameter(q, ParameterDirection.OUT) | ||
406 | .clause(ageView.call(q, y)) | ||
407 | .build(); | ||
408 | var dnfWithOutputToAggregate = Dnf.builder("WithDataOutputToAggregate") | ||
409 | .parameter(q, ParameterDirection.OUT) | ||
410 | .parameter(y, ParameterDirection.OUT) | ||
411 | .clause(ageView.call(q, y)) | ||
412 | .build(); | ||
413 | |||
414 | return Stream.of( | ||
415 | Arguments.of(x.assign(constant(24))), | ||
416 | Arguments.of(ageView.call(q, x)), | ||
417 | Arguments.of(x.assign(personView.count(q))), | ||
418 | Arguments.of(x.assign(ageView.aggregate(INT_SUM, q))), | ||
419 | Arguments.of(dnfWithDataOutput.call(x, q)), | ||
420 | Arguments.of(x.assign(dnfWithOutput.count(q))), | ||
421 | Arguments.of(x.assign(dnfWithOutputToAggregate.aggregateBy(z, INT_SUM, q, z))) | ||
422 | ); | ||
423 | } | ||
424 | |||
425 | private static Stream<Arguments> literalToClauseArgumentStream(Stream<Arguments> literalArgumentsStream) { | 248 | private static Stream<Arguments> literalToClauseArgumentStream(Stream<Arguments> literalArgumentsStream) { |
426 | return literalArgumentsStream.map(arguments -> Arguments.of(List.of(arguments.get()[0]))); | 249 | return literalArgumentsStream.map(arguments -> Arguments.of(List.of(arguments.get()[0]))); |
427 | } | 250 | } |
diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/literal/AggregationLiteralTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/literal/AggregationLiteralTest.java index 35910e08..ddd57e96 100644 --- a/subprojects/store-query/src/test/java/tools/refinery/store/query/literal/AggregationLiteralTest.java +++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/literal/AggregationLiteralTest.java | |||
@@ -7,15 +7,16 @@ package tools.refinery.store.query.literal; | |||
7 | 7 | ||
8 | import org.junit.jupiter.api.Test; | 8 | import org.junit.jupiter.api.Test; |
9 | import tools.refinery.store.query.Constraint; | 9 | import tools.refinery.store.query.Constraint; |
10 | import tools.refinery.store.query.InvalidQueryException; | ||
10 | import tools.refinery.store.query.dnf.Dnf; | 11 | import tools.refinery.store.query.dnf.Dnf; |
12 | import tools.refinery.store.query.dnf.InvalidClauseException; | ||
11 | import tools.refinery.store.query.term.*; | 13 | import tools.refinery.store.query.term.*; |
12 | 14 | ||
13 | import java.util.List; | 15 | import java.util.List; |
14 | import java.util.Set; | 16 | import java.util.Set; |
15 | 17 | ||
16 | import static org.hamcrest.MatcherAssert.assertThat; | 18 | import static org.hamcrest.MatcherAssert.assertThat; |
17 | import static org.hamcrest.Matchers.containsInAnyOrder; | 19 | import static org.hamcrest.Matchers.*; |
18 | import static org.hamcrest.Matchers.empty; | ||
19 | import static org.junit.jupiter.api.Assertions.assertAll; | 20 | import static org.junit.jupiter.api.Assertions.assertAll; |
20 | import static org.junit.jupiter.api.Assertions.assertThrows; | 21 | import static org.junit.jupiter.api.Assertions.assertThrows; |
21 | import static tools.refinery.store.query.literal.Literals.not; | 22 | import static tools.refinery.store.query.literal.Literals.not; |
@@ -57,13 +58,13 @@ class AggregationLiteralTest { | |||
57 | @Test | 58 | @Test |
58 | void missingAggregationVariableTest() { | 59 | void missingAggregationVariableTest() { |
59 | var aggregation = fakeConstraint.aggregateBy(y, INT_SUM, p, z); | 60 | var aggregation = fakeConstraint.aggregateBy(y, INT_SUM, p, z); |
60 | assertThrows(IllegalArgumentException.class, () -> x.assign(aggregation)); | 61 | assertThrows(InvalidQueryException.class, () -> x.assign(aggregation)); |
61 | } | 62 | } |
62 | 63 | ||
63 | @Test | 64 | @Test |
64 | void circularAggregationVariableTest() { | 65 | void circularAggregationVariableTest() { |
65 | var aggregation = fakeConstraint.aggregateBy(x, INT_SUM, p, x); | 66 | var aggregation = fakeConstraint.aggregateBy(x, INT_SUM, p, x); |
66 | assertThrows(IllegalArgumentException.class, () -> x.assign(aggregation)); | 67 | assertThrows(InvalidQueryException.class, () -> x.assign(aggregation)); |
67 | } | 68 | } |
68 | 69 | ||
69 | @Test | 70 | @Test |
@@ -73,7 +74,7 @@ class AggregationLiteralTest { | |||
73 | not(fakeConstraint.call(p, y)), | 74 | not(fakeConstraint.call(p, y)), |
74 | x.assign(fakeConstraint.aggregateBy(y, INT_SUM, p, y)) | 75 | x.assign(fakeConstraint.aggregateBy(y, INT_SUM, p, y)) |
75 | ); | 76 | ); |
76 | assertThrows(IllegalArgumentException.class, builder::build); | 77 | assertThrows(InvalidClauseException.class, builder::build); |
77 | } | 78 | } |
78 | 79 | ||
79 | @Test | 80 | @Test |
@@ -83,6 +84,6 @@ class AggregationLiteralTest { | |||
83 | y.assign(constant(27)), | 84 | y.assign(constant(27)), |
84 | x.assign(fakeConstraint.aggregateBy(y, INT_SUM, p, y)) | 85 | x.assign(fakeConstraint.aggregateBy(y, INT_SUM, p, y)) |
85 | ); | 86 | ); |
86 | assertThrows(IllegalArgumentException.class, builder::build); | 87 | assertThrows(InvalidClauseException.class, builder::build); |
87 | } | 88 | } |
88 | } | 89 | } |
diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/rewriter/DuplicateDnfRemoverTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/rewriter/DuplicateDnfRemoverTest.java new file mode 100644 index 00000000..ebb24ab5 --- /dev/null +++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/rewriter/DuplicateDnfRemoverTest.java | |||
@@ -0,0 +1,164 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.rewriter; | ||
7 | |||
8 | import org.junit.jupiter.api.BeforeEach; | ||
9 | import org.junit.jupiter.api.Test; | ||
10 | import tools.refinery.store.query.dnf.Query; | ||
11 | import tools.refinery.store.query.literal.AbstractCallLiteral; | ||
12 | import tools.refinery.store.query.literal.Reduction; | ||
13 | import tools.refinery.store.query.term.Variable; | ||
14 | import tools.refinery.store.query.view.AnySymbolView; | ||
15 | import tools.refinery.store.query.view.KeyOnlyView; | ||
16 | import tools.refinery.store.representation.Symbol; | ||
17 | |||
18 | import java.util.List; | ||
19 | |||
20 | import static org.hamcrest.MatcherAssert.assertThat; | ||
21 | import static org.hamcrest.Matchers.is; | ||
22 | import static org.hamcrest.Matchers.not; | ||
23 | import static tools.refinery.store.query.literal.Literals.not; | ||
24 | |||
25 | class DuplicateDnfRemoverTest { | ||
26 | private final static Symbol<Boolean> friend = Symbol.of("friend", 2); | ||
27 | private final static AnySymbolView friendView = new KeyOnlyView<>(friend); | ||
28 | |||
29 | private DuplicateDnfRemover sut; | ||
30 | |||
31 | @BeforeEach | ||
32 | void beforeEach() { | ||
33 | sut = new DuplicateDnfRemover(); | ||
34 | } | ||
35 | |||
36 | @Test | ||
37 | void removeDuplicateSimpleTest() { | ||
38 | var one = Query.of("One", (builder, x, y) -> builder.clause( | ||
39 | friendView.call(x, y), | ||
40 | friendView.call(y, x) | ||
41 | )); | ||
42 | var two = Query.of("Two", (builder, x, y) -> builder.clause( | ||
43 | friendView.call(x, y), | ||
44 | friendView.call(y, x) | ||
45 | )); | ||
46 | |||
47 | var oneResult = sut.rewrite(one); | ||
48 | var twoResult = sut.rewrite(two); | ||
49 | |||
50 | assertThat(oneResult, is(twoResult)); | ||
51 | assertThat(one, is(oneResult)); | ||
52 | } | ||
53 | |||
54 | @Test | ||
55 | void notDuplicateSimpleTest() { | ||
56 | var one = Query.of("One", (builder, x, y) -> builder.clause( | ||
57 | friendView.call(x, y), | ||
58 | friendView.call(y, x) | ||
59 | )); | ||
60 | var two = Query.of("Two", (builder, x, y) -> builder.clause((z) -> List.of( | ||
61 | friendView.call(x, y), | ||
62 | friendView.call(y, z) | ||
63 | ))); | ||
64 | |||
65 | var oneResult = sut.rewrite(one); | ||
66 | var twoResult = sut.rewrite(two); | ||
67 | |||
68 | assertThat(one, is(oneResult)); | ||
69 | assertThat(two, is(twoResult)); | ||
70 | } | ||
71 | |||
72 | @Test | ||
73 | void removeDuplicateRecursiveTest() { | ||
74 | var oneSubQuery = Query.of("OneSubQuery", (builder, x, y) -> builder.clause( | ||
75 | friendView.call(x, y), | ||
76 | friendView.call(y, x) | ||
77 | )); | ||
78 | var one = Query.of("One", (builder, x) -> builder.clause( | ||
79 | oneSubQuery.call(x, Variable.of()) | ||
80 | )); | ||
81 | var twoSubQuery = Query.of("TwoSubQuery", (builder, x, y) -> builder.clause( | ||
82 | friendView.call(x, y), | ||
83 | friendView.call(y, x) | ||
84 | )); | ||
85 | var two = Query.of("Two", (builder, x) -> builder.clause( | ||
86 | twoSubQuery.call(x, Variable.of()) | ||
87 | )); | ||
88 | |||
89 | var oneResult = sut.rewrite(one); | ||
90 | var twoResult = sut.rewrite(two); | ||
91 | |||
92 | assertThat(oneResult, is(twoResult)); | ||
93 | assertThat(one, is(oneResult)); | ||
94 | } | ||
95 | |||
96 | @Test | ||
97 | void notDuplicateRecursiveTest() { | ||
98 | var oneSubQuery = Query.of("OneSubQuery", (builder, x, y) -> builder.clause( | ||
99 | friendView.call(x, y), | ||
100 | friendView.call(y, x) | ||
101 | )); | ||
102 | var one = Query.of("One", (builder, x) -> builder.clause( | ||
103 | oneSubQuery.call(x, Variable.of()) | ||
104 | )); | ||
105 | var twoSubQuery = Query.of("TwoSubQuery", (builder, x, y) -> builder.clause( | ||
106 | friendView.call(x, y), | ||
107 | friendView.call(y, x) | ||
108 | )); | ||
109 | var two = Query.of("Two", (builder, x) -> builder.clause( | ||
110 | twoSubQuery.call(Variable.of(), x) | ||
111 | )); | ||
112 | |||
113 | var oneResult = sut.rewrite(one); | ||
114 | var twoResult = sut.rewrite(two); | ||
115 | |||
116 | assertThat(one, is(oneResult)); | ||
117 | assertThat(oneResult, is(not(twoResult))); | ||
118 | |||
119 | var oneCall = (AbstractCallLiteral) oneResult.getDnf().getClauses().get(0).literals().get(0); | ||
120 | var twoCall = (AbstractCallLiteral) twoResult.getDnf().getClauses().get(0).literals().get(0); | ||
121 | |||
122 | assertThat(oneCall.getTarget(), is(twoCall.getTarget())); | ||
123 | } | ||
124 | |||
125 | @Test | ||
126 | void removeContradictionTest() { | ||
127 | var oneSubQuery = Query.of("OneSubQuery", (builder, x, y) -> builder.clause( | ||
128 | friendView.call(x, y), | ||
129 | friendView.call(y, x) | ||
130 | )); | ||
131 | var twoSubQuery = Query.of("TwoSubQuery", (builder, x, y) -> builder.clause( | ||
132 | friendView.call(x, y), | ||
133 | friendView.call(y, x) | ||
134 | )); | ||
135 | var query = Query.of("Contradiction", (builder, x, y) -> builder.clause( | ||
136 | oneSubQuery.call(x, y), | ||
137 | not(twoSubQuery.call(x, y)) | ||
138 | )); | ||
139 | |||
140 | var result = sut.rewrite(query); | ||
141 | |||
142 | assertThat(result.getDnf().getReduction(), is(Reduction.ALWAYS_FALSE)); | ||
143 | } | ||
144 | |||
145 | @Test | ||
146 | void removeQuantifiedContradictionTest() { | ||
147 | var oneSubQuery = Query.of("OneSubQuery", (builder, x, y) -> builder.clause( | ||
148 | friendView.call(x, y), | ||
149 | friendView.call(y, x) | ||
150 | )); | ||
151 | var twoSubQuery = Query.of("TwoSubQuery", (builder, x, y) -> builder.clause( | ||
152 | friendView.call(x, y), | ||
153 | friendView.call(y, x) | ||
154 | )); | ||
155 | var query = Query.of("Contradiction", (builder, x) -> builder.clause( | ||
156 | oneSubQuery.call(x, Variable.of()), | ||
157 | not(twoSubQuery.call(x, Variable.of())) | ||
158 | )); | ||
159 | |||
160 | var result = sut.rewrite(query); | ||
161 | |||
162 | assertThat(result.getDnf().getReduction(), is(Reduction.ALWAYS_FALSE)); | ||
163 | } | ||
164 | } | ||
diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/rewriter/InputParameterResolverTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/rewriter/InputParameterResolverTest.java new file mode 100644 index 00000000..ef0077e4 --- /dev/null +++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/rewriter/InputParameterResolverTest.java | |||
@@ -0,0 +1,228 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.rewriter; | ||
7 | |||
8 | import org.junit.jupiter.api.BeforeEach; | ||
9 | import org.junit.jupiter.api.Test; | ||
10 | import tools.refinery.store.query.dnf.Dnf; | ||
11 | import tools.refinery.store.query.dnf.Query; | ||
12 | import tools.refinery.store.query.term.ParameterDirection; | ||
13 | import tools.refinery.store.query.term.Variable; | ||
14 | import tools.refinery.store.query.view.AnySymbolView; | ||
15 | import tools.refinery.store.query.view.KeyOnlyView; | ||
16 | import tools.refinery.store.representation.Symbol; | ||
17 | |||
18 | import java.util.List; | ||
19 | |||
20 | import static org.hamcrest.MatcherAssert.assertThat; | ||
21 | import static org.hamcrest.Matchers.is; | ||
22 | import static tools.refinery.store.query.literal.Literals.not; | ||
23 | import static tools.refinery.store.query.tests.QueryMatchers.structurallyEqualTo; | ||
24 | |||
25 | class InputParameterResolverTest { | ||
26 | private final static Symbol<Boolean> person = Symbol.of("Person", 1); | ||
27 | private final static Symbol<Boolean> friend = Symbol.of("friend", 2); | ||
28 | private final static AnySymbolView personView = new KeyOnlyView<>(person); | ||
29 | private final static AnySymbolView friendView = new KeyOnlyView<>(friend); | ||
30 | |||
31 | private InputParameterResolver sut; | ||
32 | |||
33 | @BeforeEach | ||
34 | void beforeEach() { | ||
35 | sut = new InputParameterResolver(); | ||
36 | } | ||
37 | |||
38 | @Test | ||
39 | void inlineSingleClauseTest() { | ||
40 | var dnf = Dnf.of("SubQuery", builder -> { | ||
41 | var x = builder.parameter("x", ParameterDirection.OUT); | ||
42 | builder.clause(friendView.call(x, Variable.of())); | ||
43 | }); | ||
44 | var query = Query.of("Actual", (builder, x) -> builder.clause( | ||
45 | dnf.call(x), | ||
46 | personView.call(x) | ||
47 | )); | ||
48 | |||
49 | var actual = sut.rewrite(query); | ||
50 | |||
51 | var expected = Query.of("Expected", (builder, x) -> builder.clause( | ||
52 | friendView.call(x, Variable.of()), | ||
53 | personView.call(x) | ||
54 | )); | ||
55 | |||
56 | assertThat(actual.getDnf(), structurallyEqualTo(expected.getDnf())); | ||
57 | } | ||
58 | |||
59 | @Test | ||
60 | void inlineSingleClauseWIthInputTest() { | ||
61 | var dnf = Dnf.of("SubQuery", builder -> { | ||
62 | var x = builder.parameter("x", ParameterDirection.IN); | ||
63 | builder.clause(not(friendView.call(x, Variable.of()))); | ||
64 | }); | ||
65 | var query = Query.of("Actual", (builder, x) -> builder.clause( | ||
66 | dnf.call(x), | ||
67 | personView.call(x) | ||
68 | )); | ||
69 | |||
70 | var actual = sut.rewrite(query); | ||
71 | |||
72 | var expected = Query.of("Expected", (builder, x) -> builder.clause( | ||
73 | personView.call(x), | ||
74 | not(friendView.call(x, Variable.of())) | ||
75 | )); | ||
76 | |||
77 | assertThat(actual.getDnf(), structurallyEqualTo(expected.getDnf())); | ||
78 | } | ||
79 | |||
80 | @Test | ||
81 | void singleLiteralDemandSetTest() { | ||
82 | var dnf = Dnf.of("SubQuery", builder -> { | ||
83 | var x = builder.parameter("x", ParameterDirection.IN); | ||
84 | builder.clause(not(friendView.call(x, Variable.of()))); | ||
85 | builder.clause(not(friendView.call(Variable.of(), x))); | ||
86 | }); | ||
87 | var query = Query.of("Actual", (builder, x) -> builder.clause( | ||
88 | dnf.call(x), | ||
89 | personView.call(x) | ||
90 | )); | ||
91 | |||
92 | var actual = sut.rewrite(query); | ||
93 | |||
94 | var expectedSubQuery = Dnf.of("ExpectedSubQuery", builder -> { | ||
95 | var x = builder.parameter("x", ParameterDirection.OUT); | ||
96 | builder.clause( | ||
97 | personView.call(x), | ||
98 | not(friendView.call(x, Variable.of())) | ||
99 | ); | ||
100 | builder.clause( | ||
101 | personView.call(x), | ||
102 | not(friendView.call(Variable.of(), x)) | ||
103 | ); | ||
104 | }); | ||
105 | var expected = Query.of("Expected", (builder, x) -> builder.clause( | ||
106 | personView.call(x), | ||
107 | expectedSubQuery.call(x) | ||
108 | )); | ||
109 | |||
110 | assertThat(actual.getDnf(), structurallyEqualTo(expected.getDnf())); | ||
111 | } | ||
112 | |||
113 | @Test | ||
114 | void multipleLiteralDemandSetTest() { | ||
115 | var dnf = Dnf.of("SubQuery", builder -> { | ||
116 | var x = builder.parameter("x", ParameterDirection.IN); | ||
117 | var y = builder.parameter("y", ParameterDirection.IN); | ||
118 | builder.clause(not(friendView.call(x, y))); | ||
119 | builder.clause(not(friendView.call(y, x))); | ||
120 | }); | ||
121 | var query = Query.of("Actual", (builder, p1) -> builder.clause(p2 -> List.of( | ||
122 | not(dnf.call(p1, p2)), | ||
123 | personView.call(p1), | ||
124 | personView.call(p2) | ||
125 | ))); | ||
126 | |||
127 | var actual = sut.rewrite(query); | ||
128 | |||
129 | var context = Dnf.of("Context", builder -> { | ||
130 | var x = builder.parameter("x", ParameterDirection.OUT); | ||
131 | var y = builder.parameter("y", ParameterDirection.OUT); | ||
132 | builder.clause( | ||
133 | personView.call(x), | ||
134 | personView.call(y) | ||
135 | ); | ||
136 | }); | ||
137 | var expectedSubQuery = Dnf.of("ExpectedSubQuery", builder -> { | ||
138 | var x = builder.parameter("x", ParameterDirection.OUT); | ||
139 | var y = builder.parameter("x", ParameterDirection.OUT); | ||
140 | builder.clause( | ||
141 | context.call(x, y), | ||
142 | not(friendView.call(x, y)) | ||
143 | ); | ||
144 | builder.clause( | ||
145 | context.call(x, y), | ||
146 | not(friendView.call(y, x)) | ||
147 | ); | ||
148 | }); | ||
149 | var expected = Query.of("Expected", (builder, p1) -> builder.clause(p2 -> List.of( | ||
150 | context.call(p1, p2), | ||
151 | not(expectedSubQuery.call(p1, p2)) | ||
152 | ))); | ||
153 | |||
154 | assertThat(actual.getDnf(), structurallyEqualTo(expected.getDnf())); | ||
155 | } | ||
156 | |||
157 | @Test | ||
158 | void multipleParameterDemandSetTest() { | ||
159 | var dnf = Dnf.of("SubQuery", builder -> { | ||
160 | var x = builder.parameter("x", ParameterDirection.IN); | ||
161 | var y = builder.parameter("y", ParameterDirection.IN); | ||
162 | builder.clause(not(friendView.call(x, y))); | ||
163 | builder.clause(not(friendView.call(y, x))); | ||
164 | }); | ||
165 | var query = Query.of("Actual", (builder, p1) -> builder.clause( | ||
166 | not(dnf.call(p1, p1)), | ||
167 | personView.call(p1) | ||
168 | )); | ||
169 | |||
170 | var actual = sut.rewrite(query); | ||
171 | |||
172 | var expectedSubQuery = Dnf.of("ExpectedSubQuery", builder -> { | ||
173 | var x = builder.parameter("x", ParameterDirection.OUT); | ||
174 | var y = builder.parameter("y", ParameterDirection.OUT); | ||
175 | builder.clause( | ||
176 | y.isEquivalent(x), | ||
177 | personView.call(x), | ||
178 | not(friendView.call(x, x)) | ||
179 | ); | ||
180 | }); | ||
181 | var expected = Query.of("Expected", (builder, p1) -> builder.clause( | ||
182 | personView.call(p1), | ||
183 | not(expectedSubQuery.call(p1, p1)) | ||
184 | )); | ||
185 | |||
186 | assertThat(actual.getDnf(), structurallyEqualTo(expected.getDnf())); | ||
187 | } | ||
188 | |||
189 | @Test | ||
190 | void eliminateDoubleNegationTest() { | ||
191 | var dnf = Dnf.of("SubQuery", builder -> { | ||
192 | var x = builder.parameter("x", ParameterDirection.IN); | ||
193 | builder.clause(not(friendView.call(x, Variable.of()))); | ||
194 | }); | ||
195 | var query = Query.of("Actual", (builder, p1) -> builder.clause( | ||
196 | personView.call(p1), | ||
197 | not(dnf.call(p1)) | ||
198 | )); | ||
199 | |||
200 | var actual = sut.rewrite(query); | ||
201 | |||
202 | var expected = Query.of("Actual", (builder, p1) -> builder.clause( | ||
203 | personView.call(p1), | ||
204 | friendView.call(p1, Variable.of()) | ||
205 | )); | ||
206 | |||
207 | assertThat(actual.getDnf(), structurallyEqualTo(expected.getDnf())); | ||
208 | } | ||
209 | |||
210 | @Test | ||
211 | void identityWhenNoWorkToDoTest() { | ||
212 | var dnf = Dnf.of("SubQuery", builder -> { | ||
213 | var x = builder.parameter("x", ParameterDirection.OUT); | ||
214 | builder.clause( | ||
215 | personView.call(x), | ||
216 | not(friendView.call(x, Variable.of())) | ||
217 | ); | ||
218 | }); | ||
219 | var query = Query.of("Actual", (builder, p1) -> builder.clause( | ||
220 | personView.call(p1), | ||
221 | not(dnf.call(p1)) | ||
222 | )); | ||
223 | |||
224 | var actual = sut.rewrite(query); | ||
225 | |||
226 | assertThat(actual, is(query)); | ||
227 | } | ||
228 | } | ||
diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/term/TermSubstitutionTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/term/TermSubstitutionTest.java index 1cbc101a..1fae2492 100644 --- a/subprojects/store-query/src/test/java/tools/refinery/store/query/term/TermSubstitutionTest.java +++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/term/TermSubstitutionTest.java | |||
@@ -9,8 +9,8 @@ import org.junit.jupiter.api.Assertions; | |||
9 | import org.junit.jupiter.params.ParameterizedTest; | 9 | import org.junit.jupiter.params.ParameterizedTest; |
10 | import org.junit.jupiter.params.provider.Arguments; | 10 | import org.junit.jupiter.params.provider.Arguments; |
11 | import org.junit.jupiter.params.provider.MethodSource; | 11 | import org.junit.jupiter.params.provider.MethodSource; |
12 | import tools.refinery.store.query.dnf.Dnf; | 12 | import tools.refinery.store.query.equality.DnfEqualityChecker; |
13 | import tools.refinery.store.query.equality.LiteralEqualityHelper; | 13 | import tools.refinery.store.query.equality.SubstitutingLiteralEqualityHelper; |
14 | import tools.refinery.store.query.substitution.Substitution; | 14 | import tools.refinery.store.query.substitution.Substitution; |
15 | import tools.refinery.store.query.term.bool.BoolTerms; | 15 | import tools.refinery.store.query.term.bool.BoolTerms; |
16 | import tools.refinery.store.query.term.int_.IntTerms; | 16 | import tools.refinery.store.query.term.int_.IntTerms; |
@@ -48,7 +48,7 @@ class TermSubstitutionTest { | |||
48 | void substitutionTest(AnyTerm term) { | 48 | void substitutionTest(AnyTerm term) { |
49 | var substitutedTerm1 = term.substitute(substitution); | 49 | var substitutedTerm1 = term.substitute(substitution); |
50 | Assertions.assertNotEquals(term, substitutedTerm1, "Original term is not equal to substituted term"); | 50 | Assertions.assertNotEquals(term, substitutedTerm1, "Original term is not equal to substituted term"); |
51 | var helper = new LiteralEqualityHelper(Dnf::equals, List.of(), List.of()); | 51 | var helper = new SubstitutingLiteralEqualityHelper(DnfEqualityChecker.DEFAULT, List.of(), List.of()); |
52 | Assertions.assertTrue(term.equalsWithSubstitution(helper, substitutedTerm1), "Terms are equal by helper"); | 52 | Assertions.assertTrue(term.equalsWithSubstitution(helper, substitutedTerm1), "Terms are equal by helper"); |
53 | // The {@link #substitution} is its own inverse. | 53 | // The {@link #substitution} is its own inverse. |
54 | var substitutedTerm2 = substitutedTerm1.substitute(substitution); | 54 | var substitutedTerm2 = substitutedTerm1.substitute(substitution); |
diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/utils/OrderStatisticTreeTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/utils/OrderStatisticTreeTest.java index cbb48603..0ac88ed7 100644 --- a/subprojects/store-query/src/test/java/tools/refinery/store/query/utils/OrderStatisticTreeTest.java +++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/utils/OrderStatisticTreeTest.java | |||
@@ -2,7 +2,7 @@ | |||
2 | * Copyright (c) 2021 Rodion Efremov | 2 | * Copyright (c) 2021 Rodion Efremov |
3 | * Copyright (c) 2023 The Refinery Authors <https://refinery.tools/> | 3 | * Copyright (c) 2023 The Refinery Authors <https://refinery.tools/> |
4 | * | 4 | * |
5 | * SPDX-License-Identifier: MIT OR EPL-2.0 | 5 | * SPDX-License-Identifier: MIT |
6 | */ | 6 | */ |
7 | package tools.refinery.store.query.utils; | 7 | package tools.refinery.store.query.utils; |
8 | 8 | ||