diff options
Diffstat (limited to 'subprojects/store-query/src/test/java/tools/refinery/store/query/dnf')
5 files changed, 131 insertions, 191 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 | } |