aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/logic/src/test
diff options
context:
space:
mode:
Diffstat (limited to 'subprojects/logic/src/test')
-rw-r--r--subprojects/logic/src/test/java/tools/refinery/logic/dnf/DnfBuilderLiteralEliminationTest.java257
-rw-r--r--subprojects/logic/src/test/java/tools/refinery/logic/dnf/DnfBuilderVariableUnificationTest.java322
-rw-r--r--subprojects/logic/src/test/java/tools/refinery/logic/dnf/DnfToDefinitionStringTest.java154
-rw-r--r--subprojects/logic/src/test/java/tools/refinery/logic/dnf/HashCodeTest.java64
-rw-r--r--subprojects/logic/src/test/java/tools/refinery/logic/dnf/TopologicalSortTest.java111
-rw-r--r--subprojects/logic/src/test/java/tools/refinery/logic/dnf/VariableDirectionTest.java247
-rw-r--r--subprojects/logic/src/test/java/tools/refinery/logic/literal/AggregationLiteralTest.java89
-rw-r--r--subprojects/logic/src/test/java/tools/refinery/logic/literal/CallLiteralTest.java94
-rw-r--r--subprojects/logic/src/test/java/tools/refinery/logic/rewriter/DuplicateDnfRemoverTest.java162
-rw-r--r--subprojects/logic/src/test/java/tools/refinery/logic/rewriter/InputParameterResolverTest.java225
-rw-r--r--subprojects/logic/src/test/java/tools/refinery/logic/term/TermSubstitutionTest.java97
-rw-r--r--subprojects/logic/src/test/java/tools/refinery/logic/term/bool/BoolTermsEvaluateTest.java76
-rw-r--r--subprojects/logic/src/test/java/tools/refinery/logic/term/cardinalityinterval/CardinalityIntervalTest.java127
-rw-r--r--subprojects/logic/src/test/java/tools/refinery/logic/term/cardinalityinterval/CardinalityIntervalsTest.java27
-rw-r--r--subprojects/logic/src/test/java/tools/refinery/logic/term/cardinalityinterval/EmptyCardinalityIntervalTest.java19
-rw-r--r--subprojects/logic/src/test/java/tools/refinery/logic/term/cardinalityinterval/FiniteCardinalityIntervalTest.java27
-rw-r--r--subprojects/logic/src/test/java/tools/refinery/logic/term/int_/IntTermsEvaluateTest.java260
-rw-r--r--subprojects/logic/src/test/java/tools/refinery/logic/term/real/RealTermEvaluateTest.java239
-rw-r--r--subprojects/logic/src/test/java/tools/refinery/logic/term/uppercardinality/FiniteUpperCardinalityTest.java17
-rw-r--r--subprojects/logic/src/test/java/tools/refinery/logic/term/uppercardinality/UpperCardinalitiesTest.java30
-rw-r--r--subprojects/logic/src/test/java/tools/refinery/logic/term/uppercardinality/UpperCardinalitySumAggregatorStreamTest.java54
-rw-r--r--subprojects/logic/src/test/java/tools/refinery/logic/term/uppercardinality/UpperCardinalitySumAggregatorTest.java79
-rw-r--r--subprojects/logic/src/test/java/tools/refinery/logic/term/uppercardinality/UpperCardinalityTermsEvaluateTest.java103
-rw-r--r--subprojects/logic/src/test/java/tools/refinery/logic/term/uppercardinality/UpperCardinalityTest.java115
-rw-r--r--subprojects/logic/src/test/java/tools/refinery/logic/tests/FakeFunctionView.java57
-rw-r--r--subprojects/logic/src/test/java/tools/refinery/logic/tests/FakeKeyOnlyView.java21
-rw-r--r--subprojects/logic/src/test/java/tools/refinery/logic/tests/StructurallyEqualToRawTest.java155
-rw-r--r--subprojects/logic/src/test/java/tools/refinery/logic/tests/StructurallyEqualToTest.java123
28 files changed, 3351 insertions, 0 deletions
diff --git a/subprojects/logic/src/test/java/tools/refinery/logic/dnf/DnfBuilderLiteralEliminationTest.java b/subprojects/logic/src/test/java/tools/refinery/logic/dnf/DnfBuilderLiteralEliminationTest.java
new file mode 100644
index 00000000..d5a9ccad
--- /dev/null
+++ b/subprojects/logic/src/test/java/tools/refinery/logic/dnf/DnfBuilderLiteralEliminationTest.java
@@ -0,0 +1,257 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.logic.dnf;
7
8import org.junit.jupiter.api.Test;
9import org.junit.jupiter.params.ParameterizedTest;
10import org.junit.jupiter.params.provider.CsvSource;
11import tools.refinery.logic.Constraint;
12import tools.refinery.logic.literal.BooleanLiteral;
13import tools.refinery.logic.term.NodeVariable;
14import tools.refinery.logic.term.ParameterDirection;
15import tools.refinery.logic.term.Variable;
16import tools.refinery.logic.term.bool.BoolTerms;
17import tools.refinery.logic.tests.FakeKeyOnlyView;
18
19import java.util.List;
20
21import static org.hamcrest.MatcherAssert.assertThat;
22import static tools.refinery.logic.literal.Literals.check;
23import static tools.refinery.logic.literal.Literals.not;
24import static tools.refinery.logic.tests.QueryMatchers.structurallyEqualTo;
25
26class DnfBuilderLiteralEliminationTest {
27 private final Constraint friendView = new FakeKeyOnlyView("friend", 2);
28 private final NodeVariable p = Variable.of("p");
29 private final NodeVariable q = Variable.of("q");
30 private final Dnf trueDnf = Dnf.builder().parameter(p, ParameterDirection.IN).clause().build();
31 private final Dnf falseDnf = Dnf.builder().parameter(p).build();
32
33 @Test
34 void eliminateTrueTest() {
35 var actual = Dnf.builder()
36 .parameters(p, q)
37 .clause(BooleanLiteral.TRUE, friendView.call(p, q))
38 .build();
39 var expected = Dnf.builder().parameters(p, q).clause(friendView.call(p, q)).build();
40
41 assertThat(actual, structurallyEqualTo(expected));
42 }
43
44 @Test
45 void eliminateTrueAssumptionTest() {
46 var actual = Dnf.builder()
47 .parameters(p, q)
48 .clause(check(BoolTerms.constant(true)), friendView.call(p, q))
49 .build();
50 var expected = Dnf.builder().parameters(p, q).clause(friendView.call(p, q)).build();
51
52 assertThat(actual, structurallyEqualTo(expected));
53 }
54
55 @Test
56 void eliminateFalseTest() {
57 var actual = Dnf.builder()
58 .parameters(p, q)
59 .clause(friendView.call(p, q))
60 .clause(friendView.call(q, p), BooleanLiteral.FALSE)
61 .build();
62 var expected = Dnf.builder().parameters(p, q).clause(friendView.call(p, q)).build();
63
64 assertThat(actual, structurallyEqualTo(expected));
65 }
66
67 @ParameterizedTest
68 @CsvSource(value = {
69 "false",
70 "null"
71 }, nullValues = "null")
72 void eliminateFalseAssumptionTest(Boolean value) {
73 var actual = Dnf.builder()
74 .parameters(p, q)
75 .clause(friendView.call(p, q))
76 .clause(friendView.call(q, p), check(BoolTerms.constant(value)))
77 .build();
78 var expected = Dnf.builder().parameters(p, q).clause(friendView.call(p, q)).build();
79
80 assertThat(actual, structurallyEqualTo(expected));
81 }
82
83 @Test
84 void alwaysTrueTest() {
85 var actual = Dnf.builder()
86 .parameters(List.of(p, q), ParameterDirection.IN)
87 .clause(friendView.call(p, q))
88 .clause(BooleanLiteral.TRUE)
89 .build();
90 var expected = Dnf.builder().parameters(List.of(p, q), ParameterDirection.IN).clause().build();
91
92 assertThat(actual, structurallyEqualTo(expected));
93 }
94
95 @Test
96 void alwaysFalseTest() {
97 var actual = Dnf.builder()
98 .parameters(p, q)
99 .clause(friendView.call(p, q), BooleanLiteral.FALSE)
100 .build();
101 var expected = Dnf.builder().parameters(p, q).build();
102
103 assertThat(actual, structurallyEqualTo(expected));
104 }
105
106 @Test
107 void eliminateTrueDnfTest() {
108 var actual = Dnf.builder()
109 .parameters(p, q)
110 .clause(trueDnf.call(q), friendView.call(p, q))
111 .build();
112 var expected = Dnf.builder().parameters(p, q).clause(friendView.call(p, q)).build();
113
114 assertThat(actual, structurallyEqualTo(expected));
115 }
116
117 @Test
118 void eliminateFalseDnfTest() {
119 var actual = Dnf.builder()
120 .parameters(p, q)
121 .clause(friendView.call(p, q))
122 .clause(friendView.call(q, p), falseDnf.call(q))
123 .build();
124 var expected = Dnf.builder().parameters(p, q).clause(friendView.call(p, q)).build();
125
126 assertThat(actual, structurallyEqualTo(expected));
127 }
128
129 @Test
130 void alwaysTrueDnfTest() {
131 var actual = Dnf.builder()
132 .parameters(List.of(p, q), ParameterDirection.IN)
133 .clause(friendView.call(p, q))
134 .clause(trueDnf.call(q))
135 .build();
136 var expected = Dnf.builder().parameters(List.of(p, q), ParameterDirection.IN).clause().build();
137
138 assertThat(actual, structurallyEqualTo(expected));
139 }
140
141 @Test
142 void alwaysFalseDnfTest() {
143 var actual = Dnf.builder()
144 .parameters(p, q)
145 .clause(friendView.call(p, q), falseDnf.call(q))
146 .build();
147 var expected = Dnf.builder().parameters(p, q).build();
148
149 assertThat(actual, structurallyEqualTo(expected));
150 }
151
152 @Test
153 void eliminateNotFalseDnfTest() {
154 var actual = Dnf.builder()
155 .parameters(p, q)
156 .clause(not(falseDnf.call(q)), friendView.call(p, q))
157 .build();
158 var expected = Dnf.builder().parameters(p, q).clause(friendView.call(p, q)).build();
159
160 assertThat(actual, structurallyEqualTo(expected));
161 }
162
163 @Test
164 void eliminateNotTrueDnfTest() {
165 var actual = Dnf.builder()
166 .parameters(p, q)
167 .clause(friendView.call(p, q))
168 .clause(friendView.call(q, p), not(trueDnf.call(q)))
169 .build();
170 var expected = Dnf.builder().parameters(p, q).clause(friendView.call(p, q)).build();
171
172 assertThat(actual, structurallyEqualTo(expected));
173 }
174
175 @Test
176 void alwaysNotFalseDnfTest() {
177 var actual = Dnf.builder()
178 .parameters(List.of(p, q), ParameterDirection.IN)
179 .clause(friendView.call(p, q))
180 .clause(not(falseDnf.call(q)))
181 .build();
182 var expected = Dnf.builder().parameters(List.of(p, q), ParameterDirection.IN).clause().build();
183
184 assertThat(actual, structurallyEqualTo(expected));
185 }
186
187 @Test
188 void alwaysNotTrueDnfTest() {
189 var actual = Dnf.builder()
190 .parameters(p, q)
191 .clause(friendView.call(p, q), not(trueDnf.call(q)))
192 .build();
193 var expected = Dnf.builder().parameters(p, q).build();
194
195 assertThat(actual, structurallyEqualTo(expected));
196 }
197
198 @Test
199 void removeDuplicateTest() {
200 var actual = Dnf.of(builder -> builder.clause((p, q) -> List.of(
201 friendView.call(p, q),
202 friendView.call(p, q)
203 )));
204 var expected = Dnf.of(builder -> builder.clause((p, q) -> List.of(friendView.call(p, q))));
205
206 assertThat(actual, structurallyEqualTo(expected));
207 }
208
209 @Test
210 void removeContradictoryTest() {
211 var actual = Dnf.of(builder -> builder.clause((p, q) -> List.of(
212 friendView.call(p, q),
213 not(friendView.call(p, q))
214 )));
215 var expected = Dnf.builder().build();
216
217 assertThat(actual, structurallyEqualTo(expected));
218 }
219
220 @Test
221 void removeContradictoryUniversalTest() {
222 var actual = Dnf.of(builder -> builder.clause((p, q) -> List.of(
223 friendView.call(q, q),
224 friendView.call(p, q),
225 not(friendView.call(p, Variable.of()))
226 )));
227 var expected = Dnf.builder().build();
228
229 assertThat(actual, structurallyEqualTo(expected));
230 }
231
232 @Test
233 void removeContradictoryExistentialUniversalTest() {
234 var actual = Dnf.of(builder -> builder.clause((p) -> List.of(
235 friendView.call(p, Variable.of()),
236 not(friendView.call(p, Variable.of()))
237 )));
238 var expected = Dnf.builder().build();
239
240 assertThat(actual, structurallyEqualTo(expected));
241 }
242
243 @Test
244 void removeContradictoryUniversalParameterTest() {
245 var actual = Dnf.of(builder -> {
246 var p = builder.parameter("p");
247 builder.clause((q) -> List.of(
248 friendView.call(q, q),
249 friendView.call(p, q),
250 not(friendView.call(p, Variable.of()))
251 ));
252 });
253 var expected = Dnf.builder().parameter(p).build();
254
255 assertThat(actual, structurallyEqualTo(expected));
256 }
257}
diff --git a/subprojects/logic/src/test/java/tools/refinery/logic/dnf/DnfBuilderVariableUnificationTest.java b/subprojects/logic/src/test/java/tools/refinery/logic/dnf/DnfBuilderVariableUnificationTest.java
new file mode 100644
index 00000000..0e1f77e2
--- /dev/null
+++ b/subprojects/logic/src/test/java/tools/refinery/logic/dnf/DnfBuilderVariableUnificationTest.java
@@ -0,0 +1,322 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.logic.dnf;
7
8import org.junit.jupiter.api.Test;
9import tools.refinery.logic.Constraint;
10import tools.refinery.logic.term.ParameterDirection;
11import tools.refinery.logic.term.Variable;
12import tools.refinery.logic.tests.FakeKeyOnlyView;
13
14import java.util.List;
15
16import static org.hamcrest.MatcherAssert.assertThat;
17import static tools.refinery.logic.tests.QueryMatchers.structurallyEqualTo;
18
19class DnfBuilderVariableUnificationTest {
20 private final Constraint friendView = new FakeKeyOnlyView("friend", 2);
21 private final Constraint childrenView = new FakeKeyOnlyView("children", 2);
22
23 @Test
24 void equalToParameterTest() {
25 var actual = Dnf.of(builder -> {
26 var p = builder.parameter("p");
27 builder.clause(q -> List.of(
28 friendView.call(p, q),
29 p.isEquivalent(q)
30 ));
31 });
32
33 var expectedP = Variable.of("p");
34 assertThat(actual, structurallyEqualTo(
35 List.of(new SymbolicParameter(expectedP, ParameterDirection.OUT)),
36 List.of(
37 List.of(friendView.call(expectedP, expectedP))
38 )
39 ));
40 }
41
42 @Test
43 void equalToParameterReverseTest() {
44 var actual = Dnf.of(builder -> {
45 var p = builder.parameter("p");
46 builder.clause(q -> List.of(
47 friendView.call(p, q),
48 q.isEquivalent(p)
49 ));
50 });
51
52 var expectedP = Variable.of("p");
53 assertThat(actual, structurallyEqualTo(
54 List.of(new SymbolicParameter(expectedP, ParameterDirection.OUT)),
55 List.of(
56 List.of(friendView.call(expectedP, expectedP))
57 )
58 ));
59 }
60
61 @Test
62 void equalQuantifiedTest() {
63 var actual = Dnf.of(builder -> builder.clause((p, q) -> List.of(
64 friendView.call(p, q),
65 p.isEquivalent(q)
66 )));
67
68 var expectedP = Variable.of("p");
69 assertThat(actual, structurallyEqualTo(
70 List.of(),
71 List.of(
72 List.of(friendView.call(expectedP, expectedP))
73 )
74 ));
75 }
76
77 @Test
78 void equalQuantifiedTransitiveTest() {
79 var actual = Dnf.of(builder -> builder.clause((p, q, r) -> List.of(
80 friendView.call(p, q),
81 p.isEquivalent(q),
82 childrenView.call(p, r),
83 q.isEquivalent(r)
84 )));
85
86 var expectedP = Variable.of("p");
87 assertThat(actual, structurallyEqualTo(
88 List.of(),
89 List.of(
90 List.of(friendView.call(expectedP, expectedP), childrenView.call(expectedP, expectedP))
91 )
92 ));
93 }
94
95 @Test
96 void equalQuantifiedTransitiveRemoveDuplicateTest() {
97 var actual = Dnf.of(builder -> builder.clause((p, q, r) -> List.of(
98 friendView.call(p, q),
99 p.isEquivalent(q),
100 friendView.call(p, r),
101 q.isEquivalent(r)
102 )));
103
104 var expectedP = Variable.of("p");
105 assertThat(actual, structurallyEqualTo(
106 List.of(),
107 List.of(
108 List.of(friendView.call(expectedP, expectedP))
109 )
110 ));
111 }
112
113 @Test
114 void parametersEqualTest() {
115 var actual = Dnf.of(builder -> {
116 var p = builder.parameter("p");
117 var q = builder.parameter("q");
118 builder.clause(
119 friendView.call(p, q),
120 p.isEquivalent(q)
121 );
122 });
123
124 var expectedP = Variable.of("p");
125 var expectedQ = Variable.of("q");
126 assertThat(actual, structurallyEqualTo(
127 List.of(
128 new SymbolicParameter(expectedP, ParameterDirection.OUT),
129 new SymbolicParameter(expectedQ, ParameterDirection.OUT)
130 ),
131 List.of(
132 List.of(friendView.call(expectedP, expectedP), expectedQ.isEquivalent(expectedP))
133 )
134 ));
135 }
136
137 @Test
138 void parametersEqualTransitiveTest() {
139 var actual = Dnf.of(builder -> {
140 var p = builder.parameter("p");
141 var q = builder.parameter("q");
142 var r = builder.parameter("r");
143 builder.clause(
144 friendView.call(p, q),
145 childrenView.call(p, r),
146 p.isEquivalent(q),
147 r.isEquivalent(q)
148 );
149 });
150
151 var expectedP = Variable.of("p");
152 var expectedQ = Variable.of("q");
153 var expectedR = Variable.of("r");
154 assertThat(actual, structurallyEqualTo(
155 List.of(
156 new SymbolicParameter(expectedP, ParameterDirection.OUT),
157 new SymbolicParameter(expectedQ, ParameterDirection.OUT),
158 new SymbolicParameter(expectedR, ParameterDirection.OUT)
159 ),
160 List.of(
161 List.of(
162 friendView.call(expectedP, expectedP),
163 expectedQ.isEquivalent(expectedP),
164 expectedR.isEquivalent(expectedP),
165 childrenView.call(expectedP, expectedP)
166 )
167 )
168 ));
169 }
170
171 @Test
172 void parameterAndQuantifiedEqualsTest() {
173 var actual = Dnf.of(builder -> {
174 var p = builder.parameter("p");
175 var q = builder.parameter("q");
176 builder.clause((r) -> List.of(
177 friendView.call(p, r),
178 p.isEquivalent(r),
179 childrenView.call(q, r),
180 q.isEquivalent(r)
181 ));
182 });
183
184
185 var expectedP = Variable.of("p");
186 var expectedQ = Variable.of("q");
187 assertThat(actual, structurallyEqualTo(
188 List.of(
189 new SymbolicParameter(expectedP, ParameterDirection.OUT),
190 new SymbolicParameter(expectedQ, ParameterDirection.OUT)
191 ),
192 List.of(
193 List.of(
194 friendView.call(expectedP, expectedP),
195 expectedQ.isEquivalent(expectedP),
196 childrenView.call(expectedP, expectedP)
197 )
198 )
199 ));
200 }
201
202 @Test
203 void parameterAndQuantifiedEqualsReverseFirstTest() {
204 var actual = Dnf.of(builder -> {
205 var p = builder.parameter("p");
206 var q = builder.parameter("q");
207 builder.clause((r) -> List.of(
208 friendView.call(p, r),
209 r.isEquivalent(p),
210 childrenView.call(q, r),
211 q.isEquivalent(r)
212 ));
213 });
214
215 var expectedP = Variable.of("p");
216 var expectedQ = Variable.of("q");
217 assertThat(actual, structurallyEqualTo(
218 List.of(
219 new SymbolicParameter(expectedP, ParameterDirection.OUT),
220 new SymbolicParameter(expectedQ, ParameterDirection.OUT)
221 ),
222 List.of(
223 List.of(
224 friendView.call(expectedP, expectedP),
225 expectedQ.isEquivalent(expectedP),
226 childrenView.call(expectedP, expectedP)
227 )
228 )
229 ));
230 }
231
232 @Test
233 void parameterAndQuantifiedEqualsReverseSecondTest() {
234 var actual = Dnf.of(builder -> {
235 var p = builder.parameter("p");
236 var q = builder.parameter("q");
237 builder.clause((r) -> List.of(
238 friendView.call(p, r),
239 p.isEquivalent(r),
240 childrenView.call(q, r),
241 r.isEquivalent(q)
242 ));
243 });
244
245 var expectedP = Variable.of("p");
246 var expectedQ = Variable.of("q");
247 assertThat(actual, structurallyEqualTo(
248 List.of(
249 new SymbolicParameter(expectedP, ParameterDirection.OUT),
250 new SymbolicParameter(expectedQ, ParameterDirection.OUT)
251 ),
252 List.of(
253 List.of(
254 friendView.call(expectedP, expectedP),
255 expectedQ.isEquivalent(expectedP),
256 childrenView.call(expectedP, expectedP)
257 )
258 )
259 ));
260 }
261
262 @Test
263 void parameterAndQuantifiedEqualsReverseBoth() {
264 var actual = Dnf.of(builder -> {
265 var p = builder.parameter("p");
266 var q = builder.parameter("q");
267 builder.clause((r) -> List.of(
268 friendView.call(p, r),
269 p.isEquivalent(r),
270 childrenView.call(q, r),
271 r.isEquivalent(q)
272 ));
273 });
274
275 var expectedP = Variable.of("p");
276 var expectedQ = Variable.of("q");
277 assertThat(actual, structurallyEqualTo(
278 List.of(
279 new SymbolicParameter(expectedP, ParameterDirection.OUT),
280 new SymbolicParameter(expectedQ, ParameterDirection.OUT)
281 ),
282 List.of(
283 List.of(
284 friendView.call(expectedP, expectedP),
285 expectedQ.isEquivalent(expectedP),
286 childrenView.call(expectedP, expectedP)
287 )
288 )
289 ));
290 }
291
292 @Test
293 void parameterAndTwoQuantifiedEqualsTest() {
294 var actual = Dnf.of(builder -> {
295 var p = builder.parameter("p");
296 var q = builder.parameter("q");
297 builder.clause((r, s) -> List.of(
298 r.isEquivalent(s),
299 friendView.call(p, r),
300 p.isEquivalent(r),
301 childrenView.call(q, s),
302 q.isEquivalent(s)
303 ));
304 });
305
306 var expectedP = Variable.of("p");
307 var expectedQ = Variable.of("q");
308 assertThat(actual, structurallyEqualTo(
309 List.of(
310 new SymbolicParameter(expectedP, ParameterDirection.OUT),
311 new SymbolicParameter(expectedQ, ParameterDirection.OUT)
312 ),
313 List.of(
314 List.of(
315 friendView.call(expectedP, expectedP),
316 expectedQ.isEquivalent(expectedP),
317 childrenView.call(expectedP, expectedP)
318 )
319 )
320 ));
321 }
322}
diff --git a/subprojects/logic/src/test/java/tools/refinery/logic/dnf/DnfToDefinitionStringTest.java b/subprojects/logic/src/test/java/tools/refinery/logic/dnf/DnfToDefinitionStringTest.java
new file mode 100644
index 00000000..dd624548
--- /dev/null
+++ b/subprojects/logic/src/test/java/tools/refinery/logic/dnf/DnfToDefinitionStringTest.java
@@ -0,0 +1,154 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2024 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.logic.dnf;
7
8import org.junit.jupiter.api.Test;
9import tools.refinery.logic.Constraint;
10import tools.refinery.logic.term.NodeVariable;
11import tools.refinery.logic.term.ParameterDirection;
12import tools.refinery.logic.term.Variable;
13import tools.refinery.logic.tests.FakeKeyOnlyView;
14
15import static org.hamcrest.MatcherAssert.assertThat;
16import static org.hamcrest.Matchers.is;
17import static tools.refinery.logic.literal.Literals.not;
18
19class DnfToDefinitionStringTest {
20 private static final Constraint personView = new FakeKeyOnlyView("person", 1);
21 private static final Constraint friendView = new FakeKeyOnlyView("friend", 2);
22 private static final NodeVariable p = Variable.of("p");
23 private static final NodeVariable q = Variable.of("q");
24
25 @Test
26 void noClausesTest() {
27 var dnf = Dnf.builder("Example").parameter(p).build();
28
29 assertThat(dnf.toDefinitionString(), is("""
30 pred Example(p) <->
31 <no clauses>.
32 """));
33 }
34
35 @Test
36 void noParametersTest() {
37 var dnf = Dnf.builder("Example").build();
38
39 assertThat(dnf.toDefinitionString(), is("""
40 pred Example() <->
41 <no clauses>.
42 """));
43 }
44
45 @Test
46 void emptyClauseTest() {
47 var dnf = Dnf.builder("Example").parameter(p, ParameterDirection.IN).clause().build();
48
49 assertThat(dnf.toDefinitionString(), is("""
50 pred Example(in p) <->
51 <empty>.
52 """));
53 }
54
55 @Test
56 void relationViewPositiveTest() {
57 var dnf = Dnf.builder("Example").parameter(p).clause(friendView.call(p, q)).build();
58
59 assertThat(dnf.toDefinitionString(), is("""
60 pred Example(p) <->
61 friend(p, q).
62 """));
63 }
64
65 @Test
66 void relationViewNegativeTest() {
67 var dnf = Dnf.builder("Example")
68 .parameter(p, ParameterDirection.IN)
69 .clause(not(friendView.call(p, q)))
70 .build();
71
72 assertThat(dnf.toDefinitionString(), is("""
73 pred Example(in p) <->
74 !(friend(p, q)).
75 """));
76 }
77
78 @Test
79 void relationViewTransitiveTest() {
80 var dnf = Dnf.builder("Example").parameter(p).clause(friendView.callTransitive(p, q)).build();
81
82 assertThat(dnf.toDefinitionString(), is("""
83 pred Example(p) <->
84 friend+(p, q).
85 """));
86 }
87
88 @Test
89 void multipleParametersTest() {
90 var dnf = Dnf.builder("Example").parameters(p, q).clause(friendView.call(p, q)).build();
91
92 assertThat(dnf.toDefinitionString(), is("""
93 pred Example(p, q) <->
94 friend(p, q).
95 """));
96 }
97
98 @Test
99 void multipleLiteralsTest() {
100 var dnf = Dnf.builder("Example")
101 .parameter(p)
102 .clause(
103 personView.call(p),
104 personView.call(q),
105 friendView.call(p, q)
106 )
107 .build();
108
109 assertThat(dnf.toDefinitionString(), is("""
110 pred Example(p) <->
111 person(p),
112 person(q),
113 friend(p, q).
114 """));
115 }
116
117 @Test
118 void multipleClausesTest() {
119 var dnf = Dnf.builder("Example")
120 .parameter(p)
121 .clause(friendView.call(p, q))
122 .clause(friendView.call(q, p))
123 .build();
124
125 assertThat(dnf.toDefinitionString(), is("""
126 pred Example(p) <->
127 friend(p, q)
128 ;
129 friend(q, p).
130 """));
131 }
132
133 @Test
134 void dnfTest() {
135 var r = Variable.of("r");
136 var s = Variable.of("s");
137 var called = Dnf.builder("Called").parameters(r, s).clause(friendView.call(r, s)).build();
138 var dnf = Dnf.builder("Example")
139 .parameter(p)
140 .clause(
141 personView.call(p),
142 personView.call(q),
143 not(called.call(p, q))
144 )
145 .build();
146
147 assertThat(dnf.toDefinitionString(), is("""
148 pred Example(p) <->
149 person(p),
150 person(q),
151 !(@Dnf Called(p, q)).
152 """));
153 }
154}
diff --git a/subprojects/logic/src/test/java/tools/refinery/logic/dnf/HashCodeTest.java b/subprojects/logic/src/test/java/tools/refinery/logic/dnf/HashCodeTest.java
new file mode 100644
index 00000000..e140be1e
--- /dev/null
+++ b/subprojects/logic/src/test/java/tools/refinery/logic/dnf/HashCodeTest.java
@@ -0,0 +1,64 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.logic.dnf;
7
8import org.junit.jupiter.api.Test;
9import tools.refinery.logic.Constraint;
10import tools.refinery.logic.term.NodeVariable;
11import tools.refinery.logic.term.Variable;
12import tools.refinery.logic.tests.FakeKeyOnlyView;
13
14import static org.hamcrest.MatcherAssert.assertThat;
15import static org.hamcrest.Matchers.is;
16import static org.hamcrest.Matchers.not;
17
18class HashCodeTest {
19 private static final Constraint personView = new FakeKeyOnlyView("Person", 1);
20 private static final Constraint friendView = new FakeKeyOnlyView("friend", 2);
21 private static final NodeVariable p = Variable.of("p");
22 private static final NodeVariable q = Variable.of("q");
23
24 @Test
25 void flatEqualsTest() {
26 var expected = Dnf.builder("Expected").parameters(q).clause(personView.call(q)).build();
27 var actual = Dnf.builder("Actual").parameters(p).clause(personView.call(p)).build();
28
29 assertThat(actual.hashCodeWithSubstitution(), is(expected.hashCodeWithSubstitution()));
30 }
31
32 @Test
33 void flatNotEqualsTest() {
34 var expected = Dnf.builder("Expected").parameters(q).clause(friendView.call(q, q)).build();
35 var actual = Dnf.builder("Actual").parameters(p).clause(friendView.call(p, q)).build();
36
37 assertThat(actual.hashCodeWithSubstitution(), not(expected.hashCodeWithSubstitution()));
38 }
39
40 @Test
41 void deepEqualsTest() {
42 var expected2 = Dnf.builder("Expected2").parameters(p).clause(personView.call(p)).build();
43 var expected = Dnf.builder("Expected").parameters(q).clause(
44 expected2.call(q)
45 ).build();
46 var actual = Dnf.builder("Actual").parameters(q).clause(
47 expected2.call(q)
48 ).build();
49
50 assertThat(actual.hashCodeWithSubstitution(), is(expected.hashCodeWithSubstitution()));
51 }
52
53 @Test
54 void deepNotEqualsTest() {
55 var expected = Dnf.builder("Expected").parameters(q).clause(
56 Dnf.builder("Expected2").parameters(p).clause(personView.call(p)).build().call(q)
57 ).build();
58 var actual = Dnf.builder("Actual").parameters(q).clause(
59 Dnf.builder("Actual2").parameters(p).clause(personView.call(p)).build().call(q)
60 ).build();
61
62 assertThat(actual.hashCodeWithSubstitution(), not(expected.hashCodeWithSubstitution()));
63 }
64}
diff --git a/subprojects/logic/src/test/java/tools/refinery/logic/dnf/TopologicalSortTest.java b/subprojects/logic/src/test/java/tools/refinery/logic/dnf/TopologicalSortTest.java
new file mode 100644
index 00000000..8ea27cc9
--- /dev/null
+++ b/subprojects/logic/src/test/java/tools/refinery/logic/dnf/TopologicalSortTest.java
@@ -0,0 +1,111 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.logic.dnf;
7
8import org.junit.jupiter.api.Test;
9import tools.refinery.logic.Constraint;
10import tools.refinery.logic.InvalidQueryException;
11import tools.refinery.logic.term.NodeVariable;
12import tools.refinery.logic.term.ParameterDirection;
13import tools.refinery.logic.term.Variable;
14import tools.refinery.logic.tests.FakeKeyOnlyView;
15
16import java.util.List;
17
18import static org.hamcrest.MatcherAssert.assertThat;
19import static org.junit.jupiter.api.Assertions.assertThrows;
20import static tools.refinery.logic.literal.Literals.not;
21import static tools.refinery.logic.tests.QueryMatchers.structurallyEqualTo;
22
23class TopologicalSortTest {
24 private static final Constraint friendView = new FakeKeyOnlyView("friend", 2);
25 private static final Dnf example = Dnf.of("example", builder -> {
26 var a = builder.parameter("a", ParameterDirection.IN);
27 var b = builder.parameter("b", ParameterDirection.IN);
28 var c = builder.parameter("c", ParameterDirection.OUT);
29 var d = builder.parameter("d", ParameterDirection.OUT);
30 builder.clause(
31 friendView.call(a, b),
32 friendView.call(b, c),
33 friendView.call(c, d)
34 );
35 });
36 private static final NodeVariable p = Variable.of("p");
37 private static final NodeVariable q = Variable.of("q");
38 private static final NodeVariable r = Variable.of("r");
39 private static final NodeVariable s = Variable.of("s");
40 private static final NodeVariable t = Variable.of("t");
41
42 @Test
43 void topologicalSortTest() {
44 var actual = Dnf.builder("Actual")
45 .parameter(p, ParameterDirection.IN)
46 .parameter(q, ParameterDirection.OUT)
47 .clause(
48 not(friendView.call(p, q)),
49 example.call(p, q, r, s),
50 example.call(r, t, q, s),
51 friendView.call(r, t)
52 )
53 .build();
54
55 assertThat(actual, structurallyEqualTo(
56 List.of(
57 new SymbolicParameter(p, ParameterDirection.IN),
58 new SymbolicParameter(q, ParameterDirection.OUT)
59 ),
60 List.of(
61 List.of(
62 friendView.call(r, t),
63 example.call(r, t, q, s),
64 not(friendView.call(p, q)),
65 example.call(p, q, r, s)
66 )
67 )
68 ));
69 }
70
71 @Test
72 void missingInputTest() {
73 var builder = Dnf.builder("Actual")
74 .parameter(p, ParameterDirection.OUT)
75 .parameter(q, ParameterDirection.OUT)
76 .clause(
77 not(friendView.call(p, q)),
78 example.call(p, q, r, s),
79 example.call(r, t, q, s),
80 friendView.call(r, t)
81 );
82 assertThrows(InvalidQueryException.class, builder::build);
83 }
84
85 @Test
86 void missingVariableTest() {
87 var builder = Dnf.builder("Actual")
88 .parameter(p, ParameterDirection.IN)
89 .parameter(q, ParameterDirection.OUT)
90 .clause(
91 not(friendView.call(p, q)),
92 example.call(p, q, r, s),
93 example.call(r, t, q, s)
94 );
95 assertThrows(InvalidQueryException.class, builder::build);
96 }
97
98 @Test
99 void circularDependencyTest() {
100 var builder = Dnf.builder("Actual")
101 .parameter(p, ParameterDirection.IN)
102 .parameter(q, ParameterDirection.OUT)
103 .clause(
104 not(friendView.call(p, q)),
105 example.call(p, q, r, s),
106 example.call(r, t, q, s),
107 example.call(p, q, r, t)
108 );
109 assertThrows(InvalidQueryException.class, builder::build);
110 }
111}
diff --git a/subprojects/logic/src/test/java/tools/refinery/logic/dnf/VariableDirectionTest.java b/subprojects/logic/src/test/java/tools/refinery/logic/dnf/VariableDirectionTest.java
new file mode 100644
index 00000000..f9f39b8a
--- /dev/null
+++ b/subprojects/logic/src/test/java/tools/refinery/logic/dnf/VariableDirectionTest.java
@@ -0,0 +1,247 @@
1/*
2 * SPDX-FileCopyrightText: 2023-2024 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.logic.dnf;
7
8import org.junit.jupiter.params.ParameterizedTest;
9import org.junit.jupiter.params.provider.Arguments;
10import org.junit.jupiter.params.provider.MethodSource;
11import tools.refinery.logic.Constraint;
12import tools.refinery.logic.literal.BooleanLiteral;
13import tools.refinery.logic.literal.Literal;
14import tools.refinery.logic.term.DataVariable;
15import tools.refinery.logic.term.NodeVariable;
16import tools.refinery.logic.term.ParameterDirection;
17import tools.refinery.logic.term.Variable;
18import tools.refinery.logic.tests.FakeFunctionView;
19import tools.refinery.logic.tests.FakeKeyOnlyView;
20
21import java.util.ArrayList;
22import java.util.List;
23import java.util.stream.Stream;
24
25import static org.hamcrest.MatcherAssert.assertThat;
26import static org.hamcrest.Matchers.hasItem;
27import static org.hamcrest.Matchers.not;
28import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
29import static org.junit.jupiter.api.Assertions.assertThrows;
30import static tools.refinery.logic.literal.Literals.not;
31import static tools.refinery.logic.term.int_.IntTerms.INT_SUM;
32
33class VariableDirectionTest {
34 private static final Constraint personView = new FakeKeyOnlyView("Person", 1);
35 private static final Constraint friendView = new FakeKeyOnlyView("friend", 2);
36 private static final FakeFunctionView<Integer> ageView = new FakeFunctionView<>("age", 1, Integer.class);
37 private static final NodeVariable p = Variable.of("p");
38 private static final NodeVariable q = Variable.of("q");
39 private static final DataVariable<Integer> x = Variable.of("x", Integer.class);
40 private static final DataVariable<Integer> y = Variable.of("y", Integer.class);
41 private static final DataVariable<Integer> z = Variable.of("z", Integer.class);
42
43 @ParameterizedTest
44 @MethodSource("clausesWithVariableInput")
45 void unboundOutVariableTest(List<? extends Literal> clause) {
46 var builder = Dnf.builder().parameter(p, ParameterDirection.OUT).clause(clause);
47 assertThrows(InvalidClauseException.class, builder::build);
48 }
49
50 @ParameterizedTest
51 @MethodSource("clausesWithVariableInput")
52 void unboundInVariableTest(List<? extends Literal> clause) {
53 var builder = Dnf.builder().parameter(p, ParameterDirection.IN).clause(clause);
54 var dnf = assertDoesNotThrow(builder::build);
55 var clauses = dnf.getClauses();
56 if (!clauses.isEmpty()) {
57 assertThat(clauses.getFirst().positiveVariables(), hasItem(p));
58 }
59 }
60
61 @ParameterizedTest
62 @MethodSource("clausesWithVariableInput")
63 void boundPrivateVariableTest(List<? extends Literal> clause) {
64 var clauseWithBinding = new ArrayList<Literal>(clause);
65 clauseWithBinding.add(personView.call(p));
66 var builder = Dnf.builder().clause(clauseWithBinding);
67 var dnf = assertDoesNotThrow(builder::build);
68 var clauses = dnf.getClauses();
69 if (!clauses.isEmpty()) {
70 assertThat(clauses.getFirst().positiveVariables(), hasItem(p));
71 }
72 }
73
74 static Stream<Arguments> clausesWithVariableInput() {
75 return Stream.concat(
76 clausesNotBindingVariable(),
77 literalToClauseArgumentStream(literalsWithRequiredVariableInput())
78 );
79 }
80
81 @ParameterizedTest
82 @MethodSource("clausesNotBindingVariable")
83 void unboundPrivateVariableTest(List<? extends Literal> clause) {
84 var builder = Dnf.builder().clause(clause);
85 var dnf = assertDoesNotThrow(builder::build);
86 var clauses = dnf.getClauses();
87 if (!clauses.isEmpty()) {
88 assertThat(clauses.getFirst().positiveVariables(), not(hasItem(p)));
89 }
90 }
91
92 @ParameterizedTest
93 @MethodSource("clausesNotBindingVariable")
94 void unboundByEquivalencePrivateVariableTest(List<? extends Literal> clause) {
95 var r = Variable.of("r");
96 var clauseWithEquivalence = new ArrayList<Literal>(clause);
97 clauseWithEquivalence.add(r.isEquivalent(p));
98 var builder = Dnf.builder().clause(clauseWithEquivalence);
99 assertThrows(InvalidClauseException.class, builder::build);
100 }
101
102 static Stream<Arguments> clausesNotBindingVariable() {
103 return Stream.concat(
104 Stream.of(
105 Arguments.of(List.of()),
106 Arguments.of(List.of(BooleanLiteral.TRUE)),
107 Arguments.of(List.of(BooleanLiteral.FALSE))
108 ),
109 literalToClauseArgumentStream(literalsWithPrivateVariable())
110 );
111 }
112
113 @ParameterizedTest
114 @MethodSource("literalsWithPrivateVariable")
115 void unboundTwicePrivateVariableTest(Literal literal) {
116 var builder = Dnf.builder().clause(not(personView.call(p)), literal);
117 assertThrows(InvalidClauseException.class, builder::build);
118 }
119
120 @ParameterizedTest
121 @MethodSource("literalsWithPrivateVariable")
122 void unboundTwiceByEquivalencePrivateVariableTest(Literal literal) {
123 var r = Variable.of("r");
124 var builder = Dnf.builder().clause(not(personView.call(r)), r.isEquivalent(p), literal);
125 assertThrows(InvalidClauseException.class, builder::build);
126 }
127
128 static Stream<Arguments> literalsWithPrivateVariable() {
129 var dnfWithOutput = Dnf.builder("WithOutput")
130 .parameter(p, ParameterDirection.OUT)
131 .parameter(q, ParameterDirection.OUT)
132 .clause(friendView.call(p, q))
133 .build();
134 var dnfWithOutputToAggregate = Dnf.builder("WithOutputToAggregate")
135 .parameter(p, ParameterDirection.OUT)
136 .parameter(q, ParameterDirection.OUT)
137 .parameter(x, ParameterDirection.OUT)
138 .clause(
139 friendView.call(p, q),
140 ageView.call(q, x)
141 )
142 .build();
143
144 return Stream.of(
145 Arguments.of(not(friendView.call(p, q))),
146 Arguments.of(y.assign(friendView.count(p, q))),
147 Arguments.of(y.assign(ageView.aggregate(INT_SUM, p))),
148 Arguments.of(not(dnfWithOutput.call(p, q))),
149 Arguments.of(y.assign(dnfWithOutput.count(p, q))),
150 Arguments.of(y.assign(dnfWithOutputToAggregate.aggregateBy(z, INT_SUM, p, q, z)))
151 );
152 }
153
154 @ParameterizedTest
155 @MethodSource("literalsWithRequiredVariableInput")
156 void unboundPrivateVariableTest(Literal literal) {
157 var builder = Dnf.builder().clause(literal);
158 assertThrows(InvalidClauseException.class, builder::build);
159 }
160
161 @ParameterizedTest
162 @MethodSource("literalsWithRequiredVariableInput")
163 void boundPrivateVariableInputTest(Literal literal) {
164 var builder = Dnf.builder().clause(personView.call(p), literal);
165 var dnf = assertDoesNotThrow(builder::build);
166 assertThat(dnf.getClauses().getFirst().positiveVariables(), hasItem(p));
167 }
168
169 static Stream<Arguments> literalsWithRequiredVariableInput() {
170 var dnfWithInput = Dnf.builder("WithInput")
171 .parameter(p, ParameterDirection.IN)
172 .parameter(q, ParameterDirection.OUT)
173 .clause(friendView.call(p, q)).build();
174 var dnfWithInputToAggregate = Dnf.builder("WithInputToAggregate")
175 .parameter(p, ParameterDirection.IN)
176 .parameter(q, ParameterDirection.OUT)
177 .parameter(x, ParameterDirection.OUT)
178 .clause(
179 friendView.call(p, q),
180 ageView.call(q, x)
181 ).build();
182
183 return Stream.of(
184 Arguments.of(dnfWithInput.call(p, q)),
185 Arguments.of(dnfWithInput.call(p, p)),
186 Arguments.of(not(dnfWithInput.call(p, q))),
187 Arguments.of(not(dnfWithInput.call(p, p))),
188 Arguments.of(y.assign(dnfWithInput.count(p, q))),
189 Arguments.of(y.assign(dnfWithInput.count(p, p))),
190 Arguments.of(y.assign(dnfWithInputToAggregate.aggregateBy(z, INT_SUM, p, q, z))),
191 Arguments.of(y.assign(dnfWithInputToAggregate.aggregateBy(z, INT_SUM, p, p, z)))
192 );
193 }
194
195 @ParameterizedTest
196 @MethodSource("literalsWithVariableOutput")
197 void boundParameterTest(Literal literal) {
198 var builder = Dnf.builder().parameter(p, ParameterDirection.OUT).clause(literal);
199 var dnf = assertDoesNotThrow(builder::build);
200 assertThat(dnf.getClauses().getFirst().positiveVariables(), hasItem(p));
201 }
202
203 @ParameterizedTest
204 @MethodSource("literalsWithVariableOutput")
205 void boundTwiceParameterTest(Literal literal) {
206 var builder = Dnf.builder().parameter(p, ParameterDirection.IN).clause(literal);
207 var dnf = assertDoesNotThrow(builder::build);
208 assertThat(dnf.getClauses().getFirst().positiveVariables(), hasItem(p));
209 }
210
211 @ParameterizedTest
212 @MethodSource("literalsWithVariableOutput")
213 void boundPrivateVariableOutputTest(Literal literal) {
214 var dnfWithInput = Dnf.builder("WithInput")
215 .parameter(p, ParameterDirection.IN)
216 .clause(personView.call(p))
217 .build();
218 var builder = Dnf.builder().clause(dnfWithInput.call(p), literal);
219 var dnf = assertDoesNotThrow(builder::build);
220 assertThat(dnf.getClauses().getFirst().positiveVariables(), hasItem(p));
221 }
222
223 @ParameterizedTest
224 @MethodSource("literalsWithVariableOutput")
225 void boundTwicePrivateVariableOutputTest(Literal literal) {
226 var builder = Dnf.builder().clause(personView.call(p), literal);
227 var dnf = assertDoesNotThrow(builder::build);
228 assertThat(dnf.getClauses().getFirst().positiveVariables(), hasItem(p));
229 }
230
231 static Stream<Arguments> literalsWithVariableOutput() {
232 var dnfWithOutput = Dnf.builder("WithOutput")
233 .parameter(p, ParameterDirection.OUT)
234 .parameter(q, ParameterDirection.OUT)
235 .clause(friendView.call(p, q))
236 .build();
237
238 return Stream.of(
239 Arguments.of(friendView.call(p, q)),
240 Arguments.of(dnfWithOutput.call(p, q))
241 );
242 }
243
244 private static Stream<Arguments> literalToClauseArgumentStream(Stream<Arguments> literalArgumentsStream) {
245 return literalArgumentsStream.map(arguments -> Arguments.of(List.of(arguments.get()[0])));
246 }
247}
diff --git a/subprojects/logic/src/test/java/tools/refinery/logic/literal/AggregationLiteralTest.java b/subprojects/logic/src/test/java/tools/refinery/logic/literal/AggregationLiteralTest.java
new file mode 100644
index 00000000..76639e18
--- /dev/null
+++ b/subprojects/logic/src/test/java/tools/refinery/logic/literal/AggregationLiteralTest.java
@@ -0,0 +1,89 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.logic.literal;
7
8import org.junit.jupiter.api.Test;
9import tools.refinery.logic.Constraint;
10import tools.refinery.logic.InvalidQueryException;
11import tools.refinery.logic.dnf.Dnf;
12import tools.refinery.logic.dnf.InvalidClauseException;
13import tools.refinery.logic.term.*;
14
15import java.util.List;
16import java.util.Set;
17
18import static org.hamcrest.MatcherAssert.assertThat;
19import static org.hamcrest.Matchers.*;
20import static org.junit.jupiter.api.Assertions.assertAll;
21import static org.junit.jupiter.api.Assertions.assertThrows;
22import static tools.refinery.logic.literal.Literals.not;
23import static tools.refinery.logic.term.int_.IntTerms.INT_SUM;
24import static tools.refinery.logic.term.int_.IntTerms.constant;
25
26class AggregationLiteralTest {
27 private static final NodeVariable p = Variable.of("p");
28 private static final DataVariable<Integer> x = Variable.of("x", Integer.class);
29 private static final DataVariable<Integer> y = Variable.of("y", Integer.class);
30 private static final DataVariable<Integer> z = Variable.of("z", Integer.class);
31 private static final Constraint fakeConstraint = new Constraint() {
32 @Override
33 public String name() {
34 return getClass().getName();
35 }
36
37 @Override
38 public List<Parameter> getParameters() {
39 return List.of(
40 new Parameter(null, ParameterDirection.OUT),
41 new Parameter(Integer.class, ParameterDirection.OUT)
42 );
43 }
44 };
45
46 @Test
47 void parameterDirectionTest() {
48 var literal = x.assign(fakeConstraint.aggregateBy(y, INT_SUM, p, y));
49 assertAll(
50 () -> assertThat(literal.getOutputVariables(), containsInAnyOrder(x)),
51 () -> assertThat(literal.getInputVariables(Set.of()), empty()),
52 () -> assertThat(literal.getInputVariables(Set.of(p)), containsInAnyOrder(p)),
53 () -> assertThat(literal.getPrivateVariables(Set.of()), containsInAnyOrder(p, y)),
54 () -> assertThat(literal.getPrivateVariables(Set.of(p)), containsInAnyOrder(y))
55 );
56 }
57
58 @Test
59 void missingAggregationVariableTest() {
60 var aggregation = fakeConstraint.aggregateBy(y, INT_SUM, p, z);
61 assertThrows(InvalidQueryException.class, () -> x.assign(aggregation));
62 }
63
64 @Test
65 void circularAggregationVariableTest() {
66 var aggregation = fakeConstraint.aggregateBy(x, INT_SUM, p, x);
67 assertThrows(InvalidQueryException.class, () -> x.assign(aggregation));
68 }
69
70 @Test
71 void unboundTwiceVariableTest() {
72 var builder = Dnf.builder()
73 .clause(
74 not(fakeConstraint.call(p, y)),
75 x.assign(fakeConstraint.aggregateBy(y, INT_SUM, p, y))
76 );
77 assertThrows(InvalidClauseException.class, builder::build);
78 }
79
80 @Test
81 void unboundBoundVariableTest() {
82 var builder = Dnf.builder()
83 .clause(
84 y.assign(constant(27)),
85 x.assign(fakeConstraint.aggregateBy(y, INT_SUM, p, y))
86 );
87 assertThrows(InvalidClauseException.class, builder::build);
88 }
89}
diff --git a/subprojects/logic/src/test/java/tools/refinery/logic/literal/CallLiteralTest.java b/subprojects/logic/src/test/java/tools/refinery/logic/literal/CallLiteralTest.java
new file mode 100644
index 00000000..0fb2e7c9
--- /dev/null
+++ b/subprojects/logic/src/test/java/tools/refinery/logic/literal/CallLiteralTest.java
@@ -0,0 +1,94 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.logic.literal;
7
8import org.junit.jupiter.api.Test;
9import tools.refinery.logic.Constraint;
10import tools.refinery.logic.term.NodeVariable;
11import tools.refinery.logic.term.Parameter;
12import tools.refinery.logic.term.ParameterDirection;
13import tools.refinery.logic.term.Variable;
14
15import java.util.List;
16import java.util.Set;
17
18import static org.hamcrest.MatcherAssert.assertThat;
19import static org.hamcrest.Matchers.containsInAnyOrder;
20import static org.hamcrest.Matchers.empty;
21import static org.junit.jupiter.api.Assertions.assertAll;
22import static tools.refinery.logic.literal.Literals.not;
23
24class CallLiteralTest {
25 private static final NodeVariable p = Variable.of("p");
26 private static final NodeVariable q = Variable.of("q");
27 private static final NodeVariable r = Variable.of("r");
28 private static final NodeVariable s = Variable.of("s");
29
30 private static final Constraint fakeConstraint = new Constraint() {
31 @Override
32 public String name() {
33 return getClass().getName();
34 }
35
36 @Override
37 public List<Parameter> getParameters() {
38 return List.of(
39 new Parameter(null, ParameterDirection.IN),
40 new Parameter(null, ParameterDirection.IN),
41 new Parameter(null, ParameterDirection.OUT),
42 new Parameter(null, ParameterDirection.OUT)
43 );
44 }
45 };
46
47 @Test
48 void notRepeatedPositiveDirectionTest() {
49 var literal = fakeConstraint.call(p, q, r, s);
50 assertAll(
51 () -> assertThat(literal.getOutputVariables(), containsInAnyOrder(r, s)),
52 () -> assertThat(literal.getInputVariables(Set.of()), containsInAnyOrder(p, q)),
53 () -> assertThat(literal.getInputVariables(Set.of(p, q, r)), containsInAnyOrder(p, q)),
54 () -> assertThat(literal.getPrivateVariables(Set.of()), empty()),
55 () -> assertThat(literal.getPrivateVariables(Set.of(p, q, r)), empty())
56 );
57 }
58
59 @Test
60 void notRepeatedNegativeDirectionTest() {
61 var literal = not(fakeConstraint.call(p, q, r, s));
62 assertAll(
63 () -> assertThat(literal.getOutputVariables(), empty()),
64 () -> assertThat(literal.getInputVariables(Set.of()), containsInAnyOrder(p, q)),
65 () -> assertThat(literal.getInputVariables(Set.of(p, q, r)), containsInAnyOrder(p, q, r)),
66 () -> assertThat(literal.getPrivateVariables(Set.of()), containsInAnyOrder(r, s)),
67 () -> assertThat(literal.getPrivateVariables(Set.of(p, q, r)), containsInAnyOrder(s))
68 );
69 }
70
71 @Test
72 void repeatedPositiveDirectionTest() {
73 var literal = fakeConstraint.call(p, p, q, q);
74 assertAll(
75 () -> assertThat(literal.getOutputVariables(), containsInAnyOrder(q)),
76 () -> assertThat(literal.getInputVariables(Set.of()), containsInAnyOrder(p)),
77 () -> assertThat(literal.getInputVariables(Set.of(p, q)), containsInAnyOrder(p)),
78 () -> assertThat(literal.getPrivateVariables(Set.of()), empty()),
79 () -> assertThat(literal.getPrivateVariables(Set.of(p, q)), empty())
80 );
81 }
82
83 @Test
84 void repeatedNegativeDirectionTest() {
85 var literal = not(fakeConstraint.call(p, p, q, q));
86 assertAll(
87 () -> assertThat(literal.getOutputVariables(), empty()),
88 () -> assertThat(literal.getInputVariables(Set.of()), containsInAnyOrder(p)),
89 () -> assertThat(literal.getInputVariables(Set.of(p, q)), containsInAnyOrder(p, q)),
90 () -> assertThat(literal.getPrivateVariables(Set.of()), containsInAnyOrder(q)),
91 () -> assertThat(literal.getPrivateVariables(Set.of(p, q)), empty())
92 );
93 }
94}
diff --git a/subprojects/logic/src/test/java/tools/refinery/logic/rewriter/DuplicateDnfRemoverTest.java b/subprojects/logic/src/test/java/tools/refinery/logic/rewriter/DuplicateDnfRemoverTest.java
new file mode 100644
index 00000000..7b2ce8b2
--- /dev/null
+++ b/subprojects/logic/src/test/java/tools/refinery/logic/rewriter/DuplicateDnfRemoverTest.java
@@ -0,0 +1,162 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.logic.rewriter;
7
8import org.junit.jupiter.api.BeforeEach;
9import org.junit.jupiter.api.Test;
10import tools.refinery.logic.Constraint;
11import tools.refinery.logic.dnf.Query;
12import tools.refinery.logic.literal.AbstractCallLiteral;
13import tools.refinery.logic.literal.Reduction;
14import tools.refinery.logic.term.Variable;
15import tools.refinery.logic.tests.FakeKeyOnlyView;
16
17import java.util.List;
18
19import static org.hamcrest.MatcherAssert.assertThat;
20import static org.hamcrest.Matchers.is;
21import static org.hamcrest.Matchers.not;
22import static tools.refinery.logic.literal.Literals.not;
23
24class DuplicateDnfRemoverTest {
25 private final static Constraint friendView = new FakeKeyOnlyView("friend", 2);
26
27 private DuplicateDnfRemover sut;
28
29 @BeforeEach
30 void beforeEach() {
31 sut = new DuplicateDnfRemover();
32 }
33
34 @Test
35 void removeDuplicateSimpleTest() {
36 var one = Query.of("One", (builder, x, y) -> builder.clause(
37 friendView.call(x, y),
38 friendView.call(y, x)
39 ));
40 var two = Query.of("Two", (builder, x, y) -> builder.clause(
41 friendView.call(x, y),
42 friendView.call(y, x)
43 ));
44
45 var oneResult = sut.rewrite(one);
46 var twoResult = sut.rewrite(two);
47
48 assertThat(oneResult, is(twoResult));
49 assertThat(one, is(oneResult));
50 }
51
52 @Test
53 void notDuplicateSimpleTest() {
54 var one = Query.of("One", (builder, x, y) -> builder.clause(
55 friendView.call(x, y),
56 friendView.call(y, x)
57 ));
58 var two = Query.of("Two", (builder, x, y) -> builder.clause((z) -> List.of(
59 friendView.call(x, y),
60 friendView.call(y, z)
61 )));
62
63 var oneResult = sut.rewrite(one);
64 var twoResult = sut.rewrite(two);
65
66 assertThat(one, is(oneResult));
67 assertThat(two, is(twoResult));
68 }
69
70 @Test
71 void removeDuplicateRecursiveTest() {
72 var oneSubQuery = Query.of("OneSubQuery", (builder, x, y) -> builder.clause(
73 friendView.call(x, y),
74 friendView.call(y, x)
75 ));
76 var one = Query.of("One", (builder, x) -> builder.clause(
77 oneSubQuery.call(x, Variable.of())
78 ));
79 var twoSubQuery = Query.of("TwoSubQuery", (builder, x, y) -> builder.clause(
80 friendView.call(x, y),
81 friendView.call(y, x)
82 ));
83 var two = Query.of("Two", (builder, x) -> builder.clause(
84 twoSubQuery.call(x, Variable.of())
85 ));
86
87 var oneResult = sut.rewrite(one);
88 var twoResult = sut.rewrite(two);
89
90 assertThat(oneResult, is(twoResult));
91 assertThat(one, is(oneResult));
92 }
93
94 @Test
95 void notDuplicateRecursiveTest() {
96 var oneSubQuery = Query.of("OneSubQuery", (builder, x, y) -> builder.clause(
97 friendView.call(x, y),
98 friendView.call(y, x)
99 ));
100 var one = Query.of("One", (builder, x) -> builder.clause(
101 oneSubQuery.call(x, Variable.of())
102 ));
103 var twoSubQuery = Query.of("TwoSubQuery", (builder, x, y) -> builder.clause(
104 friendView.call(x, y),
105 friendView.call(y, x)
106 ));
107 var two = Query.of("Two", (builder, x) -> builder.clause(
108 twoSubQuery.call(Variable.of(), x)
109 ));
110
111 var oneResult = sut.rewrite(one);
112 var twoResult = sut.rewrite(two);
113
114 assertThat(one, is(oneResult));
115 assertThat(oneResult, is(not(twoResult)));
116
117 var oneCall = (AbstractCallLiteral) oneResult.getDnf().getClauses().getFirst().literals().getFirst();
118 var twoCall = (AbstractCallLiteral) twoResult.getDnf().getClauses().getFirst().literals().getFirst();
119
120 assertThat(oneCall.getTarget(), is(twoCall.getTarget()));
121 }
122
123 @Test
124 void removeContradictionTest() {
125 var oneSubQuery = Query.of("OneSubQuery", (builder, x, y) -> builder.clause(
126 friendView.call(x, y),
127 friendView.call(y, x)
128 ));
129 var twoSubQuery = Query.of("TwoSubQuery", (builder, x, y) -> builder.clause(
130 friendView.call(x, y),
131 friendView.call(y, x)
132 ));
133 var query = Query.of("Contradiction", (builder, x, y) -> builder.clause(
134 oneSubQuery.call(x, y),
135 not(twoSubQuery.call(x, y))
136 ));
137
138 var result = sut.rewrite(query);
139
140 assertThat(result.getDnf().getReduction(), is(Reduction.ALWAYS_FALSE));
141 }
142
143 @Test
144 void removeQuantifiedContradictionTest() {
145 var oneSubQuery = Query.of("OneSubQuery", (builder, x, y) -> builder.clause(
146 friendView.call(x, y),
147 friendView.call(y, x)
148 ));
149 var twoSubQuery = Query.of("TwoSubQuery", (builder, x, y) -> builder.clause(
150 friendView.call(x, y),
151 friendView.call(y, x)
152 ));
153 var query = Query.of("Contradiction", (builder, x) -> builder.clause(
154 oneSubQuery.call(x, Variable.of()),
155 not(twoSubQuery.call(x, Variable.of()))
156 ));
157
158 var result = sut.rewrite(query);
159
160 assertThat(result.getDnf().getReduction(), is(Reduction.ALWAYS_FALSE));
161 }
162}
diff --git a/subprojects/logic/src/test/java/tools/refinery/logic/rewriter/InputParameterResolverTest.java b/subprojects/logic/src/test/java/tools/refinery/logic/rewriter/InputParameterResolverTest.java
new file mode 100644
index 00000000..5e5fdb64
--- /dev/null
+++ b/subprojects/logic/src/test/java/tools/refinery/logic/rewriter/InputParameterResolverTest.java
@@ -0,0 +1,225 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.logic.rewriter;
7
8import org.junit.jupiter.api.BeforeEach;
9import org.junit.jupiter.api.Test;
10import tools.refinery.logic.Constraint;
11import tools.refinery.logic.dnf.Dnf;
12import tools.refinery.logic.dnf.Query;
13import tools.refinery.logic.term.ParameterDirection;
14import tools.refinery.logic.term.Variable;
15import tools.refinery.logic.tests.FakeKeyOnlyView;
16
17import java.util.List;
18
19import static org.hamcrest.MatcherAssert.assertThat;
20import static org.hamcrest.Matchers.is;
21import static tools.refinery.logic.literal.Literals.not;
22import static tools.refinery.logic.tests.QueryMatchers.structurallyEqualTo;
23
24class InputParameterResolverTest {
25 private final static Constraint personView = new FakeKeyOnlyView("Person", 1);
26 private final static Constraint friendView = new FakeKeyOnlyView("friend", 2);
27
28 private InputParameterResolver sut;
29
30 @BeforeEach
31 void beforeEach() {
32 sut = new InputParameterResolver();
33 }
34
35 @Test
36 void inlineSingleClauseTest() {
37 var dnf = Dnf.of("SubQuery", builder -> {
38 var x = builder.parameter("x", ParameterDirection.OUT);
39 builder.clause(friendView.call(x, Variable.of()));
40 });
41 var query = Query.of("Actual", (builder, x) -> builder.clause(
42 dnf.call(x),
43 personView.call(x)
44 ));
45
46 var actual = sut.rewrite(query);
47
48 var expected = Query.of("Expected", (builder, x) -> builder.clause(
49 friendView.call(x, Variable.of()),
50 personView.call(x)
51 ));
52
53 assertThat(actual.getDnf(), structurallyEqualTo(expected.getDnf()));
54 }
55
56 @Test
57 void inlineSingleClauseWIthInputTest() {
58 var dnf = Dnf.of("SubQuery", builder -> {
59 var x = builder.parameter("x", ParameterDirection.IN);
60 builder.clause(not(friendView.call(x, Variable.of())));
61 });
62 var query = Query.of("Actual", (builder, x) -> builder.clause(
63 dnf.call(x),
64 personView.call(x)
65 ));
66
67 var actual = sut.rewrite(query);
68
69 var expected = Query.of("Expected", (builder, x) -> builder.clause(
70 personView.call(x),
71 not(friendView.call(x, Variable.of()))
72 ));
73
74 assertThat(actual.getDnf(), structurallyEqualTo(expected.getDnf()));
75 }
76
77 @Test
78 void singleLiteralDemandSetTest() {
79 var dnf = Dnf.of("SubQuery", builder -> {
80 var x = builder.parameter("x", ParameterDirection.IN);
81 builder.clause(not(friendView.call(x, Variable.of())));
82 builder.clause(not(friendView.call(Variable.of(), x)));
83 });
84 var query = Query.of("Actual", (builder, x) -> builder.clause(
85 dnf.call(x),
86 personView.call(x)
87 ));
88
89 var actual = sut.rewrite(query);
90
91 var expectedSubQuery = Dnf.of("ExpectedSubQuery", builder -> {
92 var x = builder.parameter("x", ParameterDirection.OUT);
93 builder.clause(
94 personView.call(x),
95 not(friendView.call(x, Variable.of()))
96 );
97 builder.clause(
98 personView.call(x),
99 not(friendView.call(Variable.of(), x))
100 );
101 });
102 var expected = Query.of("Expected", (builder, x) -> builder.clause(
103 personView.call(x),
104 expectedSubQuery.call(x)
105 ));
106
107 assertThat(actual.getDnf(), structurallyEqualTo(expected.getDnf()));
108 }
109
110 @Test
111 void multipleLiteralDemandSetTest() {
112 var dnf = Dnf.of("SubQuery", builder -> {
113 var x = builder.parameter("x", ParameterDirection.IN);
114 var y = builder.parameter("y", ParameterDirection.IN);
115 builder.clause(not(friendView.call(x, y)));
116 builder.clause(not(friendView.call(y, x)));
117 });
118 var query = Query.of("Actual", (builder, p1) -> builder.clause(p2 -> List.of(
119 not(dnf.call(p1, p2)),
120 personView.call(p1),
121 personView.call(p2)
122 )));
123
124 var actual = sut.rewrite(query);
125
126 var context = Dnf.of("Context", builder -> {
127 var x = builder.parameter("x", ParameterDirection.OUT);
128 var y = builder.parameter("y", ParameterDirection.OUT);
129 builder.clause(
130 personView.call(x),
131 personView.call(y)
132 );
133 });
134 var expectedSubQuery = Dnf.of("ExpectedSubQuery", builder -> {
135 var x = builder.parameter("x", ParameterDirection.OUT);
136 var y = builder.parameter("x", ParameterDirection.OUT);
137 builder.clause(
138 context.call(x, y),
139 not(friendView.call(x, y))
140 );
141 builder.clause(
142 context.call(x, y),
143 not(friendView.call(y, x))
144 );
145 });
146 var expected = Query.of("Expected", (builder, p1) -> builder.clause(p2 -> List.of(
147 context.call(p1, p2),
148 not(expectedSubQuery.call(p1, p2))
149 )));
150
151 assertThat(actual.getDnf(), structurallyEqualTo(expected.getDnf()));
152 }
153
154 @Test
155 void multipleParameterDemandSetTest() {
156 var dnf = Dnf.of("SubQuery", builder -> {
157 var x = builder.parameter("x", ParameterDirection.IN);
158 var y = builder.parameter("y", ParameterDirection.IN);
159 builder.clause(not(friendView.call(x, y)));
160 builder.clause(not(friendView.call(y, x)));
161 });
162 var query = Query.of("Actual", (builder, p1) -> builder.clause(
163 not(dnf.call(p1, p1)),
164 personView.call(p1)
165 ));
166
167 var actual = sut.rewrite(query);
168
169 var expectedSubQuery = Dnf.of("ExpectedSubQuery", builder -> {
170 var x = builder.parameter("x", ParameterDirection.OUT);
171 var y = builder.parameter("y", ParameterDirection.OUT);
172 builder.clause(
173 y.isEquivalent(x),
174 personView.call(x),
175 not(friendView.call(x, x))
176 );
177 });
178 var expected = Query.of("Expected", (builder, p1) -> builder.clause(
179 personView.call(p1),
180 not(expectedSubQuery.call(p1, p1))
181 ));
182
183 assertThat(actual.getDnf(), structurallyEqualTo(expected.getDnf()));
184 }
185
186 @Test
187 void eliminateDoubleNegationTest() {
188 var dnf = Dnf.of("SubQuery", builder -> {
189 var x = builder.parameter("x", ParameterDirection.IN);
190 builder.clause(not(friendView.call(x, Variable.of())));
191 });
192 var query = Query.of("Actual", (builder, p1) -> builder.clause(
193 personView.call(p1),
194 not(dnf.call(p1))
195 ));
196
197 var actual = sut.rewrite(query);
198
199 var expected = Query.of("Actual", (builder, p1) -> builder.clause(
200 personView.call(p1),
201 friendView.call(p1, Variable.of())
202 ));
203
204 assertThat(actual.getDnf(), structurallyEqualTo(expected.getDnf()));
205 }
206
207 @Test
208 void identityWhenNoWorkToDoTest() {
209 var dnf = Dnf.of("SubQuery", builder -> {
210 var x = builder.parameter("x", ParameterDirection.OUT);
211 builder.clause(
212 personView.call(x),
213 not(friendView.call(x, Variable.of()))
214 );
215 });
216 var query = Query.of("Actual", (builder, p1) -> builder.clause(
217 personView.call(p1),
218 not(dnf.call(p1))
219 ));
220
221 var actual = sut.rewrite(query);
222
223 assertThat(actual, is(query));
224 }
225}
diff --git a/subprojects/logic/src/test/java/tools/refinery/logic/term/TermSubstitutionTest.java b/subprojects/logic/src/test/java/tools/refinery/logic/term/TermSubstitutionTest.java
new file mode 100644
index 00000000..52b21692
--- /dev/null
+++ b/subprojects/logic/src/test/java/tools/refinery/logic/term/TermSubstitutionTest.java
@@ -0,0 +1,97 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.logic.term;
7
8import org.junit.jupiter.api.Assertions;
9import org.junit.jupiter.params.ParameterizedTest;
10import org.junit.jupiter.params.provider.Arguments;
11import org.junit.jupiter.params.provider.MethodSource;
12import tools.refinery.logic.equality.DnfEqualityChecker;
13import tools.refinery.logic.equality.SubstitutingLiteralEqualityHelper;
14import tools.refinery.logic.substitution.Substitution;
15import tools.refinery.logic.term.bool.BoolTerms;
16import tools.refinery.logic.term.int_.IntTerms;
17import tools.refinery.logic.term.real.RealTerms;
18import tools.refinery.logic.term.uppercardinality.UpperCardinality;
19import tools.refinery.logic.term.uppercardinality.UpperCardinalityTerms;
20
21import java.util.List;
22import java.util.stream.Stream;
23
24class TermSubstitutionTest {
25 private final static DataVariable<Integer> intA = Variable.of("intA", Integer.class);
26 private final static DataVariable<Integer> intB = Variable.of("intB", Integer.class);
27 private final static DataVariable<Double> realA = Variable.of("realA", Double.class);
28 private final static DataVariable<Double> realB = Variable.of("realB", Double.class);
29 private final static DataVariable<Boolean> boolA = Variable.of("boolA", Boolean.class);
30 private final static DataVariable<Boolean> boolB = Variable.of("boolB", Boolean.class);
31 private final static DataVariable<UpperCardinality> upperCardinalityA = Variable.of("upperCardinalityA",
32 UpperCardinality.class);
33 private final static DataVariable<UpperCardinality> upperCardinalityB = Variable.of("upperCardinalityB",
34 UpperCardinality.class);
35 private final static Substitution substitution = Substitution.builder()
36 .put(intA, intB)
37 .put(intB, intA)
38 .put(realA, realB)
39 .put(realB, realA)
40 .put(boolA, boolB)
41 .put(boolB, boolA)
42 .put(upperCardinalityA, upperCardinalityB)
43 .put(upperCardinalityB, upperCardinalityA)
44 .build();
45
46 @ParameterizedTest
47 @MethodSource
48 void substitutionTest(AnyTerm term) {
49 var substitutedTerm1 = term.substitute(substitution);
50 Assertions.assertNotEquals(term, substitutedTerm1, "Original term is not equal to substituted term");
51 var helper = new SubstitutingLiteralEqualityHelper(DnfEqualityChecker.DEFAULT, List.of(), List.of());
52 Assertions.assertTrue(term.equalsWithSubstitution(helper, substitutedTerm1), "Terms are equal by helper");
53 // The {@link #substitution} is its own inverse.
54 var substitutedTerm2 = substitutedTerm1.substitute(substitution);
55 Assertions.assertEquals(term, substitutedTerm2, "Original term is not equal to back-substituted term");
56 }
57
58 static Stream<Arguments> substitutionTest() {
59 return Stream.of(
60 Arguments.of(IntTerms.plus(intA)),
61 Arguments.of(IntTerms.minus(intA)),
62 Arguments.of(IntTerms.add(intA, intB)),
63 Arguments.of(IntTerms.sub(intA, intB)),
64 Arguments.of(IntTerms.mul(intA, intB)),
65 Arguments.of(IntTerms.div(intA, intB)),
66 Arguments.of(IntTerms.pow(intA, intB)),
67 Arguments.of(IntTerms.min(intA, intB)),
68 Arguments.of(IntTerms.max(intA, intB)),
69 Arguments.of(IntTerms.eq(intA, intB)),
70 Arguments.of(IntTerms.notEq(intA, intB)),
71 Arguments.of(IntTerms.less(intA, intB)),
72 Arguments.of(IntTerms.lessEq(intA, intB)),
73 Arguments.of(IntTerms.greater(intA, intB)),
74 Arguments.of(IntTerms.greaterEq(intA, intB)),
75 Arguments.of(IntTerms.asInt(realA)),
76 Arguments.of(RealTerms.plus(realA)),
77 Arguments.of(RealTerms.minus(realA)),
78 Arguments.of(RealTerms.add(realA, realB)),
79 Arguments.of(RealTerms.sub(realA, realB)),
80 Arguments.of(RealTerms.mul(realA, realB)),
81 Arguments.of(RealTerms.div(realA, realB)),
82 Arguments.of(RealTerms.pow(realA, realB)),
83 Arguments.of(RealTerms.min(realA, realB)),
84 Arguments.of(RealTerms.max(realA, realB)),
85 Arguments.of(RealTerms.asReal(intA)),
86 Arguments.of(BoolTerms.not(boolA)),
87 Arguments.of(BoolTerms.and(boolA, boolB)),
88 Arguments.of(BoolTerms.or(boolA, boolB)),
89 Arguments.of(BoolTerms.xor(boolA, boolB)),
90 Arguments.of(RealTerms.eq(realA, realB)),
91 Arguments.of(UpperCardinalityTerms.add(upperCardinalityA, upperCardinalityB)),
92 Arguments.of(UpperCardinalityTerms.mul(upperCardinalityA, upperCardinalityB)),
93 Arguments.of(UpperCardinalityTerms.min(upperCardinalityA, upperCardinalityB)),
94 Arguments.of(UpperCardinalityTerms.max(upperCardinalityA, upperCardinalityB))
95 );
96 }
97}
diff --git a/subprojects/logic/src/test/java/tools/refinery/logic/term/bool/BoolTermsEvaluateTest.java b/subprojects/logic/src/test/java/tools/refinery/logic/term/bool/BoolTermsEvaluateTest.java
new file mode 100644
index 00000000..7f65591f
--- /dev/null
+++ b/subprojects/logic/src/test/java/tools/refinery/logic/term/bool/BoolTermsEvaluateTest.java
@@ -0,0 +1,76 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.logic.term.bool;
7
8import org.junit.jupiter.params.ParameterizedTest;
9import org.junit.jupiter.params.provider.CsvSource;
10import tools.refinery.logic.term.bool.BoolTerms;
11import tools.refinery.logic.valuation.Valuation;
12
13import static org.hamcrest.MatcherAssert.assertThat;
14import static org.hamcrest.Matchers.is;
15
16class BoolTermsEvaluateTest {
17 @ParameterizedTest(name = "!{0} == {1}")
18 @CsvSource(value = {
19 "false, true",
20 "true, false",
21 "null, null"
22 }, nullValues = "null")
23 void notTest(Boolean a, Boolean result) {
24 var term = BoolTerms.not(BoolTerms.constant(a));
25 assertThat(term.getType(), is(Boolean.class));
26 assertThat(term.evaluate(Valuation.empty()), is(result));
27 }
28
29 @ParameterizedTest(name = "{0} && {1} == {2}")
30 @CsvSource(value = {
31 "false, false, false",
32 "false, true, false",
33 "true, false, false",
34 "true, true, true",
35 "false, null, null",
36 "null, false, null",
37 "null, null, null"
38 }, nullValues = "null")
39 void andTest(Boolean a, Boolean b, Boolean result) {
40 var term = BoolTerms.and(BoolTerms.constant(a), BoolTerms.constant(b));
41 assertThat(term.getType(), is(Boolean.class));
42 assertThat(term.evaluate(Valuation.empty()), is(result));
43 }
44
45 @ParameterizedTest(name = "{0} || {1} == {2}")
46 @CsvSource(value = {
47 "false, false, false",
48 "false, true, true",
49 "true, false, true",
50 "true, true, true",
51 "true, null, null",
52 "null, true, null",
53 "null, null, null"
54 }, nullValues = "null")
55 void orTest(Boolean a, Boolean b, Boolean result) {
56 var term = BoolTerms.or(BoolTerms.constant(a), BoolTerms.constant(b));
57 assertThat(term.getType(), is(Boolean.class));
58 assertThat(term.evaluate(Valuation.empty()), is(result));
59 }
60
61 @ParameterizedTest(name = "{0} ^^ {1} == {2}")
62 @CsvSource(value = {
63 "false, false, false",
64 "false, true, true",
65 "true, false, true",
66 "true, true, false",
67 "false, null, null",
68 "null, false, null",
69 "null, null, null"
70 }, nullValues = "null")
71 void xorTest(Boolean a, Boolean b, Boolean result) {
72 var term = BoolTerms.xor(BoolTerms.constant(a), BoolTerms.constant(b));
73 assertThat(term.getType(), is(Boolean.class));
74 assertThat(term.evaluate(Valuation.empty()), is(result));
75 }
76}
diff --git a/subprojects/logic/src/test/java/tools/refinery/logic/term/cardinalityinterval/CardinalityIntervalTest.java b/subprojects/logic/src/test/java/tools/refinery/logic/term/cardinalityinterval/CardinalityIntervalTest.java
new file mode 100644
index 00000000..ee2dd61c
--- /dev/null
+++ b/subprojects/logic/src/test/java/tools/refinery/logic/term/cardinalityinterval/CardinalityIntervalTest.java
@@ -0,0 +1,127 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.logic.term.cardinalityinterval;
7
8import org.junit.jupiter.params.ParameterizedTest;
9import org.junit.jupiter.params.provider.Arguments;
10import org.junit.jupiter.params.provider.MethodSource;
11
12import java.util.stream.Stream;
13
14import static org.hamcrest.MatcherAssert.assertThat;
15import static org.hamcrest.Matchers.equalTo;
16import static tools.refinery.logic.term.cardinalityinterval.CardinalityIntervals.*;
17
18class CardinalityIntervalTest {
19 @ParameterizedTest(name = "min({0}, {1}) == {2}")
20 @MethodSource
21 void minTest(CardinalityInterval a, CardinalityInterval b, CardinalityInterval expected) {
22 assertThat(a.min(b), equalTo(expected));
23 }
24
25 static Stream<Arguments> minTest() {
26 return Stream.of(
27 Arguments.of(atMost(1), atMost(1), atMost(1)),
28 Arguments.of(atMost(1), between(2, 3), atMost(1)),
29 Arguments.of(atMost(1), atLeast(2), atMost(1)),
30 Arguments.of(atMost(1), ERROR, ERROR),
31 Arguments.of(atLeast(1), atLeast(2), atLeast(1)),
32 Arguments.of(atLeast(1), ERROR, ERROR),
33 Arguments.of(ERROR, atLeast(2), ERROR),
34 Arguments.of(ERROR, ERROR, ERROR)
35 );
36 }
37
38 @ParameterizedTest(name = "max({0}, {1}) == {2}")
39 @MethodSource
40 void maxTest(CardinalityInterval a, CardinalityInterval b, CardinalityInterval expected) {
41 assertThat(a.max(b), equalTo(expected));
42 }
43
44 static Stream<Arguments> maxTest() {
45 return Stream.of(
46 Arguments.of(atMost(1), atMost(1), atMost(1)),
47 Arguments.of(atMost(1), between(2, 3), between(2, 3)),
48 Arguments.of(atMost(1), atLeast(2), atLeast(2)),
49 Arguments.of(atMost(1), ERROR, ERROR),
50 Arguments.of(atLeast(1), atLeast(2), atLeast(2)),
51 Arguments.of(atLeast(1), ERROR, ERROR),
52 Arguments.of(ERROR, atLeast(2), ERROR),
53 Arguments.of(ERROR, ERROR, ERROR)
54 );
55 }
56
57 @ParameterizedTest(name = "{0} + {1} == {2}")
58 @MethodSource
59 void addTest(CardinalityInterval a, CardinalityInterval b, CardinalityInterval expected) {
60 assertThat(a.add(b), equalTo(expected));
61 }
62
63 static Stream<Arguments> addTest() {
64 return Stream.of(
65 Arguments.of(atMost(1), atMost(1), atMost(2)),
66 Arguments.of(atMost(1), between(2, 3), between(2, 4)),
67 Arguments.of(atMost(1), atLeast(2), atLeast(2)),
68 Arguments.of(atMost(1), ERROR, ERROR),
69 Arguments.of(atLeast(1), atLeast(2), atLeast(3)),
70 Arguments.of(atLeast(1), ERROR, ERROR),
71 Arguments.of(ERROR, atLeast(2), ERROR),
72 Arguments.of(ERROR, ERROR, ERROR)
73 );
74 }
75
76 @ParameterizedTest(name = "{0} * {1} == {2}")
77 @MethodSource
78 void multiplyTest(CardinalityInterval a, CardinalityInterval b, CardinalityInterval expected) {
79 assertThat(a.multiply(b), equalTo(expected));
80 }
81
82 static Stream<Arguments> multiplyTest() {
83 return Stream.of(
84 Arguments.of(between(2, 3), between(4, 5), between(8, 15)),
85 Arguments.of(atLeast(2), between(4, 5), atLeast(8)),
86 Arguments.of(between(2, 3), atLeast(4), atLeast(8)),
87 Arguments.of(between(2, 3), ERROR, ERROR),
88 Arguments.of(ERROR, between(4, 5), ERROR),
89 Arguments.of(ERROR, ERROR, ERROR)
90 );
91 }
92
93 @ParameterizedTest(name = "{0} /\\ {1} == {2}")
94 @MethodSource
95 void meetTest(CardinalityInterval a, CardinalityInterval b, CardinalityInterval expected) {
96 assertThat(a.meet(b), equalTo(expected));
97 }
98
99 static Stream<Arguments> meetTest() {
100 return Stream.of(
101 Arguments.of(atMost(1), atMost(2), atMost(1)),
102 Arguments.of(atMost(2), between(1, 3), between(1, 2)),
103 Arguments.of(atMost(1), between(1, 3), exactly(1)),
104 Arguments.of(atMost(1), between(2, 3), ERROR),
105 Arguments.of(atMost(1), ERROR, ERROR),
106 Arguments.of(ERROR, atMost(1), ERROR),
107 Arguments.of(ERROR, ERROR, ERROR)
108 );
109 }
110
111 @ParameterizedTest(name = "{0} \\/ {1} == {2}")
112 @MethodSource
113 void joinTest(CardinalityInterval a, CardinalityInterval b, CardinalityInterval expected) {
114 assertThat(a.join(b), equalTo(expected));
115 }
116
117 static Stream<Arguments> joinTest() {
118 return Stream.of(
119 Arguments.of(atMost(1), atMost(2), atMost(2)),
120 Arguments.of(atMost(2), between(1, 3), atMost(3)),
121 Arguments.of(atMost(1), between(2, 3), atMost(3)),
122 Arguments.of(atMost(1), ERROR, atMost(1)),
123 Arguments.of(ERROR, atMost(1), atMost(1)),
124 Arguments.of(ERROR, ERROR, ERROR)
125 );
126 }
127}
diff --git a/subprojects/logic/src/test/java/tools/refinery/logic/term/cardinalityinterval/CardinalityIntervalsTest.java b/subprojects/logic/src/test/java/tools/refinery/logic/term/cardinalityinterval/CardinalityIntervalsTest.java
new file mode 100644
index 00000000..5441c837
--- /dev/null
+++ b/subprojects/logic/src/test/java/tools/refinery/logic/term/cardinalityinterval/CardinalityIntervalsTest.java
@@ -0,0 +1,27 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.logic.term.cardinalityinterval;
7
8import org.junit.jupiter.api.Test;
9import tools.refinery.logic.term.uppercardinality.UpperCardinalities;
10
11import static org.hamcrest.MatcherAssert.assertThat;
12import static org.hamcrest.Matchers.equalTo;
13
14class CardinalityIntervalsTest {
15 @Test
16 void betweenEmptyTest() {
17 var interval = CardinalityIntervals.between(2, 1);
18 assertThat(interval.isEmpty(), equalTo(true));
19 }
20
21 @Test
22 void betweenNegativeUpperBoundTest() {
23 var interval = CardinalityIntervals.between(0, -1);
24 assertThat(interval.upperBound(), equalTo(UpperCardinalities.UNBOUNDED));
25 assertThat(interval.isEmpty(), equalTo(false));
26 }
27}
diff --git a/subprojects/logic/src/test/java/tools/refinery/logic/term/cardinalityinterval/EmptyCardinalityIntervalTest.java b/subprojects/logic/src/test/java/tools/refinery/logic/term/cardinalityinterval/EmptyCardinalityIntervalTest.java
new file mode 100644
index 00000000..0dbc7f61
--- /dev/null
+++ b/subprojects/logic/src/test/java/tools/refinery/logic/term/cardinalityinterval/EmptyCardinalityIntervalTest.java
@@ -0,0 +1,19 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.logic.term.cardinalityinterval;
7
8import org.junit.jupiter.api.Test;
9
10import static org.hamcrest.MatcherAssert.assertThat;
11import static org.hamcrest.Matchers.lessThan;
12
13class EmptyCardinalityIntervalTest {
14 @Test
15 void inconsistentBoundsTest() {
16 assertThat(CardinalityIntervals.ERROR.upperBound().compareToInt(CardinalityIntervals.ERROR.lowerBound()),
17 lessThan(0));
18 }
19}
diff --git a/subprojects/logic/src/test/java/tools/refinery/logic/term/cardinalityinterval/FiniteCardinalityIntervalTest.java b/subprojects/logic/src/test/java/tools/refinery/logic/term/cardinalityinterval/FiniteCardinalityIntervalTest.java
new file mode 100644
index 00000000..588b25ab
--- /dev/null
+++ b/subprojects/logic/src/test/java/tools/refinery/logic/term/cardinalityinterval/FiniteCardinalityIntervalTest.java
@@ -0,0 +1,27 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.logic.term.cardinalityinterval;
7
8import org.junit.jupiter.api.Test;
9import tools.refinery.logic.term.uppercardinality.UpperCardinality;
10import tools.refinery.logic.term.uppercardinality.UpperCardinalities;
11
12import static org.junit.jupiter.api.Assertions.assertThrows;
13
14class FiniteCardinalityIntervalTest {
15 @Test
16 void invalidLowerBoundConstructorTest() {
17 assertThrows(IllegalArgumentException.class, () -> new NonEmptyCardinalityInterval(-1,
18 UpperCardinalities.UNBOUNDED));
19 }
20
21 @Test
22 void invalidUpperBoundConstructorTest() {
23 var upperCardinality = UpperCardinality.of(1);
24 assertThrows(IllegalArgumentException.class, () -> new NonEmptyCardinalityInterval(2,
25 upperCardinality));
26 }
27}
diff --git a/subprojects/logic/src/test/java/tools/refinery/logic/term/int_/IntTermsEvaluateTest.java b/subprojects/logic/src/test/java/tools/refinery/logic/term/int_/IntTermsEvaluateTest.java
new file mode 100644
index 00000000..55d9b740
--- /dev/null
+++ b/subprojects/logic/src/test/java/tools/refinery/logic/term/int_/IntTermsEvaluateTest.java
@@ -0,0 +1,260 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.logic.term.int_;
7
8import org.junit.jupiter.params.ParameterizedTest;
9import org.junit.jupiter.params.provider.Arguments;
10import org.junit.jupiter.params.provider.CsvSource;
11import org.junit.jupiter.params.provider.MethodSource;
12import tools.refinery.logic.term.int_.IntTerms;
13import tools.refinery.logic.term.real.RealTerms;
14import tools.refinery.logic.valuation.Valuation;
15
16import java.util.stream.Stream;
17
18import static org.hamcrest.Matchers.is;
19import static org.hamcrest.MatcherAssert.assertThat;
20
21class IntTermsEvaluateTest {
22 @ParameterizedTest(name = "+{0} == {1}")
23 @CsvSource(value = {
24 "2, 2",
25 "null, null"
26 }, nullValues = "null")
27 void plusTest(Integer a, Integer result) {
28 var term = IntTerms.plus(IntTerms.constant(a));
29 assertThat(term.getType(), is(Integer.class));
30 assertThat(term.evaluate(Valuation.empty()), is(result));
31 }
32
33 @ParameterizedTest(name = "-{0} == {1}")
34 @CsvSource(value = {
35 "2, -2",
36 "null, null"
37 }, nullValues = "null")
38 void minusTest(Integer a, Integer result) {
39 var term = IntTerms.minus(IntTerms.constant(a));
40 assertThat(term.getType(), is(Integer.class));
41 assertThat(term.evaluate(Valuation.empty()), is(result));
42 }
43
44 @ParameterizedTest(name = "{0} + {1} == {2}")
45 @CsvSource(value = {
46 "1, 2, 3",
47 "null, 2, null",
48 "1, null, null",
49 "null, null, null"
50 }, nullValues = "null")
51 void addTest(Integer a, Integer b, Integer result) {
52 var term = IntTerms.add(IntTerms.constant(a), IntTerms.constant(b));
53 assertThat(term.getType(), is(Integer.class));
54 assertThat(term.evaluate(Valuation.empty()), is(result));
55 }
56
57 @ParameterizedTest(name = "{0} - {1} == {2}")
58 @CsvSource(value = {
59 "1, 3, -2",
60 "null, 3, null",
61 "1, null, null",
62 "null, null, null"
63 }, nullValues = "null")
64 void subTest(Integer a, Integer b, Integer result) {
65 var term = IntTerms.sub(IntTerms.constant(a), IntTerms.constant(b));
66 assertThat(term.getType(), is(Integer.class));
67 assertThat(term.evaluate(Valuation.empty()), is(result));
68 }
69
70 @ParameterizedTest(name = "{0} * {1} == {2}")
71 @CsvSource(value = {
72 "2, 3, 6",
73 "null, 3, null",
74 "2, null, null",
75 "null, null, null"
76 }, nullValues = "null")
77 void mulTest(Integer a, Integer b, Integer result) {
78 var term = IntTerms.mul(IntTerms.constant(a), IntTerms.constant(b));
79 assertThat(term.getType(), is(Integer.class));
80 assertThat(term.evaluate(Valuation.empty()), is(result));
81 }
82
83 @ParameterizedTest(name = "{0} * {1} == {2}")
84 @CsvSource(value = {
85 "6, 3, 2",
86 "7, 3, 2",
87 "6, 0, null",
88 "null, 3, null",
89 "6, null, null",
90 "null, null, null"
91 }, nullValues = "null")
92 void divTest(Integer a, Integer b, Integer result) {
93 var term = IntTerms.div(IntTerms.constant(a), IntTerms.constant(b));
94 assertThat(term.getType(), is(Integer.class));
95 assertThat(term.evaluate(Valuation.empty()), is(result));
96 }
97
98 @ParameterizedTest(name = "{0} ** {1} == {2}")
99 @CsvSource(value = {
100 "1, 0, 1",
101 "1, 3, 1",
102 "1, -3, null",
103 "2, 0, 1",
104 "2, 2, 4",
105 "2, 3, 8",
106 "2, 4, 16",
107 "2, 5, 32",
108 "2, 6, 64",
109 "2, -3, null",
110 "null, 3, null",
111 "2, null, null",
112 "null, null, null"
113 }, nullValues = "null")
114 void powTest(Integer a, Integer b, Integer result) {
115 var term = IntTerms.pow(IntTerms.constant(a), IntTerms.constant(b));
116 assertThat(term.getType(), is(Integer.class));
117 assertThat(term.evaluate(Valuation.empty()), is(result));
118 }
119
120 @ParameterizedTest(name = "min({0}, {1}) == {2}")
121 @CsvSource(value = {
122 "1, 2, 1",
123 "2, 1, 1",
124 "null, 2, null",
125 "1, null, null",
126 "null, null, null"
127 }, nullValues = "null")
128 void minTest(Integer a, Integer b, Integer result) {
129 var term = IntTerms.min(IntTerms.constant(a), IntTerms.constant(b));
130 assertThat(term.getType(), is(Integer.class));
131 assertThat(term.evaluate(Valuation.empty()), is(result));
132 }
133
134 @ParameterizedTest(name = "max({0}, {1}) == {2}")
135 @CsvSource(value = {
136 "1, 2, 2",
137 "2, 1, 2",
138 "null, 2, null",
139 "1, null, null",
140 "null, null, null"
141 }, nullValues = "null")
142 void maxTest(Integer a, Integer b, Integer result) {
143 var term = IntTerms.max(IntTerms.constant(a), IntTerms.constant(b));
144 assertThat(term.getType(), is(Integer.class));
145 assertThat(term.evaluate(Valuation.empty()), is(result));
146 }
147
148 @ParameterizedTest(name = "({0} == {1}) == {2}")
149 @CsvSource(value = {
150 "1, 1, true",
151 "1, 2, false",
152 "null, 1, null",
153 "1, null, null",
154 "null, null, null"
155 }, nullValues = "null")
156 void eqTest(Integer a, Integer b, Boolean result) {
157 var term = IntTerms.eq(IntTerms.constant(a), IntTerms.constant(b));
158 assertThat(term.getType(), is(Boolean.class));
159 assertThat(term.evaluate(Valuation.empty()), is(result));
160 }
161
162 @ParameterizedTest(name = "({0} != {1}) == {2}")
163 @CsvSource(value = {
164 "1, 1, false",
165 "1, 2, true",
166 "null, 1, null",
167 "1, null, null",
168 "null, null, null"
169 }, nullValues = "null")
170 void notEqTest(Integer a, Integer b, Boolean result) {
171 var term = IntTerms.notEq(IntTerms.constant(a), IntTerms.constant(b));
172 assertThat(term.getType(), is(Boolean.class));
173 assertThat(term.evaluate(Valuation.empty()), is(result));
174 }
175
176 @ParameterizedTest(name = "({0} < {1}) == {2}")
177 @CsvSource(value = {
178 "1, -2, false",
179 "1, 1, false",
180 "1, 2, true",
181 "null, 1, null",
182 "1, null, null",
183 "null, null, null"
184 }, nullValues = "null")
185 void lessTest(Integer a, Integer b, Boolean result) {
186 var term = IntTerms.less(IntTerms.constant(a), IntTerms.constant(b));
187 assertThat(term.getType(), is(Boolean.class));
188 assertThat(term.evaluate(Valuation.empty()), is(result));
189 }
190
191 @ParameterizedTest(name = "({0} <= {1}) == {2}")
192 @CsvSource(value = {
193 "1, -2, false",
194 "1, 1, true",
195 "1, 2, true",
196 "null, 1, null",
197 "1, null, null",
198 "null, null, null"
199 }, nullValues = "null")
200 void lessEqTest(Integer a, Integer b, Boolean result) {
201 var term = IntTerms.lessEq(IntTerms.constant(a), IntTerms.constant(b));
202 assertThat(term.getType(), is(Boolean.class));
203 assertThat(term.evaluate(Valuation.empty()), is(result));
204 }
205
206 @ParameterizedTest(name = "({0} > {1}) == {2}")
207 @CsvSource(value = {
208 "1, -2, true",
209 "1, 1, false",
210 "1, 2, false",
211 "null, 1, null",
212 "1, null, null",
213 "null, null, null"
214 }, nullValues = "null")
215 void greaterTest(Integer a, Integer b, Boolean result) {
216 var term = IntTerms.greater(IntTerms.constant(a), IntTerms.constant(b));
217 assertThat(term.getType(), is(Boolean.class));
218 assertThat(term.evaluate(Valuation.empty()), is(result));
219 }
220
221 @ParameterizedTest(name = "({0} >= {1}) == {2}")
222 @CsvSource(value = {
223 "1, -2, true",
224 "1, 1, true",
225 "1, 2, false",
226 "null, 1, null",
227 "1, null, null",
228 "null, null, null"
229 }, nullValues = "null")
230 void greaterEqTest(Integer a, Integer b, Boolean result) {
231 var term = IntTerms.greaterEq(IntTerms.constant(a), IntTerms.constant(b));
232 assertThat(term.getType(), is(Boolean.class));
233 assertThat(term.evaluate(Valuation.empty()), is(result));
234 }
235
236 @ParameterizedTest(name = "{0} as int == {1}")
237 @MethodSource
238 void asIntTest(Double a, Integer result) {
239 var term = IntTerms.asInt(RealTerms.constant(a));
240 assertThat(term.getType(), is(Integer.class));
241 assertThat(term.evaluate(Valuation.empty()), is(result));
242 }
243
244 static Stream<Arguments> asIntTest() {
245 return Stream.of(
246 Arguments.of(2.0, 2),
247 Arguments.of(2.1, 2),
248 Arguments.of(2.9, 2),
249 Arguments.of(-2.0, -2),
250 Arguments.of(-2.1, -2),
251 Arguments.of(-2.9, -2),
252 Arguments.of(0.0, 0),
253 Arguments.of(-0.0, 0),
254 Arguments.of(Double.POSITIVE_INFINITY, Integer.MAX_VALUE),
255 Arguments.of(Double.NEGATIVE_INFINITY, Integer.MIN_VALUE),
256 Arguments.of(Double.NaN, null),
257 Arguments.of(null, null)
258 );
259 }
260}
diff --git a/subprojects/logic/src/test/java/tools/refinery/logic/term/real/RealTermEvaluateTest.java b/subprojects/logic/src/test/java/tools/refinery/logic/term/real/RealTermEvaluateTest.java
new file mode 100644
index 00000000..042d1807
--- /dev/null
+++ b/subprojects/logic/src/test/java/tools/refinery/logic/term/real/RealTermEvaluateTest.java
@@ -0,0 +1,239 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.logic.term.real;
7
8import org.hamcrest.Matcher;
9import org.junit.jupiter.params.ParameterizedTest;
10import org.junit.jupiter.params.provider.CsvSource;
11import tools.refinery.logic.term.int_.IntTerms;
12import tools.refinery.logic.term.real.RealTerms;
13import tools.refinery.logic.valuation.Valuation;
14
15import static org.hamcrest.MatcherAssert.assertThat;
16import static org.hamcrest.Matchers.*;
17
18class RealTermEvaluateTest {
19 public static final double TOLERANCE = 1e-6;
20
21 private static Matcher<Double> closeToOrNull(Double expected) {
22 return expected == null ? nullValue(Double.class) : closeTo(expected, TOLERANCE);
23 }
24
25 @ParameterizedTest(name = "+{0} == {1}")
26 @CsvSource(value = {
27 "2.5, 2.5",
28 "null, null"
29 }, nullValues = "null")
30 void plusTest(Double a, Double result) {
31 var term = RealTerms.plus(RealTerms.constant(a));
32 assertThat(term.getType(), is(Double.class));
33 assertThat(term.evaluate(Valuation.empty()), closeToOrNull(result));
34 }
35
36 @ParameterizedTest(name = "-{0} == {1}")
37 @CsvSource(value = {
38 "2.5, -2.5",
39 "null, null"
40 }, nullValues = "null")
41 void minusTest(Double a, Double result) {
42 var term = RealTerms.minus(RealTerms.constant(a));
43 assertThat(term.getType(), is(Double.class));
44 assertThat(term.evaluate(Valuation.empty()), closeToOrNull(result));
45 }
46
47 @ParameterizedTest(name = "{0} + {1} == {2}")
48 @CsvSource(value = {
49 "1.2, 2.3, 3.5",
50 "null, 2.3, null",
51 "1.2, null, null",
52 "null, null, null"
53 }, nullValues = "null")
54 void addTest(Double a, Double b, Double result) {
55 var term = RealTerms.add(RealTerms.constant(a), RealTerms.constant(b));
56 assertThat(term.getType(), is(Double.class));
57 assertThat(term.evaluate(Valuation.empty()), closeToOrNull(result));
58 }
59
60 @ParameterizedTest(name = "{0} - {1} == {2}")
61 @CsvSource(value = {
62 "1.2, 3.4, -2.2",
63 "null, 3.4, null",
64 "1.2, null, null",
65 "null, null, null"
66 }, nullValues = "null")
67 void subTest(Double a, Double b, Double result) {
68 var term = RealTerms.sub(RealTerms.constant(a), RealTerms.constant(b));
69 assertThat(term.getType(), is(Double.class));
70 assertThat(term.evaluate(Valuation.empty()), closeToOrNull(result));
71 }
72
73 @ParameterizedTest(name = "{0} * {1} == {2}")
74 @CsvSource(value = {
75 "2.3, 3.4, 7.82",
76 "null, 3.4, null",
77 "2.3, null, null",
78 "null, null, null"
79 }, nullValues = "null")
80 void mulTest(Double a, Double b, Double result) {
81 var term = RealTerms.mul(RealTerms.constant(a), RealTerms.constant(b));
82 assertThat(term.getType(), is(Double.class));
83 assertThat(term.evaluate(Valuation.empty()), closeToOrNull(result));
84 }
85
86 @ParameterizedTest(name = "{0} * {1} == {2}")
87 @CsvSource(value = {
88 "7.82, 3.4, 2.3",
89 "null, 3.4, null",
90 "7.82, null, null",
91 "null, null, null"
92 }, nullValues = "null")
93 void divTest(Double a, Double b, Double result) {
94 var term = RealTerms.div(RealTerms.constant(a), RealTerms.constant(b));
95 assertThat(term.getType(), is(Double.class));
96 assertThat(term.evaluate(Valuation.empty()), closeToOrNull(result));
97 }
98
99 @ParameterizedTest(name = "{0} ** {1} == {2}")
100 @CsvSource(value = {
101 "2.0, 6.0, 64.0",
102 "null, 6.0, null",
103 "2.0, null, null",
104 "null, null, null"
105 }, nullValues = "null")
106 void powTest(Double a, Double b, Double result) {
107 var term = RealTerms.pow(RealTerms.constant(a), RealTerms.constant(b));
108 assertThat(term.getType(), is(Double.class));
109 assertThat(term.evaluate(Valuation.empty()), closeToOrNull(result));
110 }
111
112 @ParameterizedTest(name = "min({0}, {1}) == {2}")
113 @CsvSource(value = {
114 "1.5, 2.7, 1.5",
115 "2.7, 1.5, 1.5",
116 "null, 2.7, null",
117 "1.5, null, null",
118 "null, null, null"
119 }, nullValues = "null")
120 void minTest(Double a, Double b, Double result) {
121 var term = RealTerms.min(RealTerms.constant(a), RealTerms.constant(b));
122 assertThat(term.getType(), is(Double.class));
123 assertThat(term.evaluate(Valuation.empty()), closeToOrNull(result));
124 }
125
126 @ParameterizedTest(name = "max({0}, {1}) == {2}")
127 @CsvSource(value = {
128 "1.5, 2.7, 2.7",
129 "2.7, 1.7, 2.7",
130 "null, 2.7, null",
131 "1.5, null, null",
132 "null, null, null"
133 }, nullValues = "null")
134 void maxTest(Double a, Double b, Double result) {
135 var term = RealTerms.max(RealTerms.constant(a), RealTerms.constant(b));
136 assertThat(term.getType(), is(Double.class));
137 assertThat(term.evaluate(Valuation.empty()), closeToOrNull(result));
138 }
139
140 @ParameterizedTest(name = "({0} == {1}) == {2}")
141 @CsvSource(value = {
142 "1.5, 1.5, true",
143 "1.5, 2.7, false",
144 "null, 1.5, null",
145 "1.5, null, null",
146 "null, null, null"
147 }, nullValues = "null")
148 void eqTest(Double a, Double b, Boolean result) {
149 var term = RealTerms.eq(RealTerms.constant(a), RealTerms.constant(b));
150 assertThat(term.getType(), is(Boolean.class));
151 assertThat(term.evaluate(Valuation.empty()), is(result));
152 }
153
154 @ParameterizedTest(name = "({0} != {1}) == {2}")
155 @CsvSource(value = {
156 "1.5, 1.5, false",
157 "1.5, 2.7, true",
158 "null, 1.5, null",
159 "1.5, null, null",
160 "null, null, null"
161 }, nullValues = "null")
162 void notEqTest(Double a, Double b, Boolean result) {
163 var term = RealTerms.notEq(RealTerms.constant(a), RealTerms.constant(b));
164 assertThat(term.getType(), is(Boolean.class));
165 assertThat(term.evaluate(Valuation.empty()), is(result));
166 }
167
168 @ParameterizedTest(name = "({0} < {1}) == {2}")
169 @CsvSource(value = {
170 "1.5, -2.7, false",
171 "1.5, 1.5, false",
172 "1.5, 2.7, true",
173 "null, 1.5, null",
174 "1.5, null, null",
175 "null, null, null"
176 }, nullValues = "null")
177 void lessTest(Double a, Double b, Boolean result) {
178 var term = RealTerms.less(RealTerms.constant(a), RealTerms.constant(b));
179 assertThat(term.getType(), is(Boolean.class));
180 assertThat(term.evaluate(Valuation.empty()), is(result));
181 }
182
183 @ParameterizedTest(name = "({0} <= {1}) == {2}")
184 @CsvSource(value = {
185 "1.5, -2.7, false",
186 "1.5, 1.5, true",
187 "1.5, 2.7, true",
188 "null, 1.5, null",
189 "1.5, null, null",
190 "null, null, null"
191 }, nullValues = "null")
192 void lessEqTest(Double a, Double b, Boolean result) {
193 var term = RealTerms.lessEq(RealTerms.constant(a), RealTerms.constant(b));
194 assertThat(term.getType(), is(Boolean.class));
195 assertThat(term.evaluate(Valuation.empty()), is(result));
196 }
197
198 @ParameterizedTest(name = "({0} > {1}) == {2}")
199 @CsvSource(value = {
200 "1.5, -2.7, true",
201 "1.5, 1.5, false",
202 "1.5, 2.7, false",
203 "null, 1.5, null",
204 "1.5, null, null",
205 "null, null, null"
206 }, nullValues = "null")
207 void greaterTest(Double a, Double b, Boolean result) {
208 var term = RealTerms.greater(RealTerms.constant(a), RealTerms.constant(b));
209 assertThat(term.getType(), is(Boolean.class));
210 assertThat(term.evaluate(Valuation.empty()), is(result));
211 }
212
213 @ParameterizedTest(name = "({0} >= {1}) == {2}")
214 @CsvSource(value = {
215 "1.5, -2.7, true",
216 "1.5, 1.5, true",
217 "1.5, 2.7, false",
218 "null, 1.5, null",
219 "1.5, null, null",
220 "null, null, null"
221 }, nullValues = "null")
222 void greaterEqTest(Double a, Double b, Boolean result) {
223 var term = RealTerms.greaterEq(RealTerms.constant(a), RealTerms.constant(b));
224 assertThat(term.getType(), is(Boolean.class));
225 assertThat(term.evaluate(Valuation.empty()), is(result));
226 }
227
228 @ParameterizedTest(name = "{0} as real == {1}")
229 @CsvSource(value = {
230 "0, 0.0",
231 "5, 5.0",
232 "null, null"
233 }, nullValues = "null")
234 void asRealTest(Integer a, Double result) {
235 var term = RealTerms.asReal(IntTerms.constant(a));
236 assertThat(term.getType(), is(Double.class));
237 assertThat(term.evaluate(Valuation.empty()), closeToOrNull(result));
238 }
239}
diff --git a/subprojects/logic/src/test/java/tools/refinery/logic/term/uppercardinality/FiniteUpperCardinalityTest.java b/subprojects/logic/src/test/java/tools/refinery/logic/term/uppercardinality/FiniteUpperCardinalityTest.java
new file mode 100644
index 00000000..8a57f029
--- /dev/null
+++ b/subprojects/logic/src/test/java/tools/refinery/logic/term/uppercardinality/FiniteUpperCardinalityTest.java
@@ -0,0 +1,17 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.logic.term.uppercardinality;
7
8import org.junit.jupiter.api.Test;
9
10import static org.junit.jupiter.api.Assertions.assertThrows;
11
12class FiniteUpperCardinalityTest {
13 @Test
14 void invalidConstructorTest() {
15 assertThrows(IllegalArgumentException.class, () -> new FiniteUpperCardinality(-1));
16 }
17}
diff --git a/subprojects/logic/src/test/java/tools/refinery/logic/term/uppercardinality/UpperCardinalitiesTest.java b/subprojects/logic/src/test/java/tools/refinery/logic/term/uppercardinality/UpperCardinalitiesTest.java
new file mode 100644
index 00000000..bdb6a833
--- /dev/null
+++ b/subprojects/logic/src/test/java/tools/refinery/logic/term/uppercardinality/UpperCardinalitiesTest.java
@@ -0,0 +1,30 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.logic.term.uppercardinality;
7
8import org.junit.jupiter.api.Test;
9import org.junit.jupiter.params.ParameterizedTest;
10import org.junit.jupiter.params.provider.ValueSource;
11
12import static org.hamcrest.MatcherAssert.assertThat;
13import static org.hamcrest.Matchers.equalTo;
14import static org.hamcrest.Matchers.instanceOf;
15
16class UpperCardinalitiesTest {
17 @ParameterizedTest
18 @ValueSource(ints = {0, 1, 255, 256, 1000, Integer.MAX_VALUE})
19 void valueOfBoundedTest(int value) {
20 var upperCardinality = UpperCardinalities.atMost(value);
21 assertThat(upperCardinality, instanceOf(FiniteUpperCardinality.class));
22 assertThat(((FiniteUpperCardinality) upperCardinality).finiteUpperBound(), equalTo(value));
23 }
24
25 @Test
26 void valueOfUnboundedTest() {
27 var upperCardinality = UpperCardinalities.atMost(-1);
28 assertThat(upperCardinality, instanceOf(UnboundedUpperCardinality.class));
29 }
30}
diff --git a/subprojects/logic/src/test/java/tools/refinery/logic/term/uppercardinality/UpperCardinalitySumAggregatorStreamTest.java b/subprojects/logic/src/test/java/tools/refinery/logic/term/uppercardinality/UpperCardinalitySumAggregatorStreamTest.java
new file mode 100644
index 00000000..fc8522d4
--- /dev/null
+++ b/subprojects/logic/src/test/java/tools/refinery/logic/term/uppercardinality/UpperCardinalitySumAggregatorStreamTest.java
@@ -0,0 +1,54 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.logic.term.uppercardinality;
7
8import org.hamcrest.Matchers;
9import org.junit.jupiter.params.ParameterizedTest;
10import org.junit.jupiter.params.provider.Arguments;
11import org.junit.jupiter.params.provider.MethodSource;
12
13import java.util.List;
14import java.util.stream.Stream;
15
16import static org.hamcrest.MatcherAssert.assertThat;
17
18class UpperCardinalitySumAggregatorStreamTest {
19 @ParameterizedTest
20 @MethodSource
21 void testStream(List<UpperCardinality> list, UpperCardinality expected) {
22 var result = UpperCardinalitySumAggregator.INSTANCE.aggregateStream(list.stream());
23 assertThat(result, Matchers.is(expected));
24 }
25
26 static Stream<Arguments> testStream() {
27 return Stream.of(
28 Arguments.of(List.of(), UpperCardinalities.ZERO),
29 Arguments.of(List.of(UpperCardinality.of(3)), UpperCardinality.of(3)),
30 Arguments.of(
31 List.of(
32 UpperCardinality.of(2),
33 UpperCardinality.of(3)
34 ),
35 UpperCardinality.of(5)
36 ),
37 Arguments.of(List.of(UpperCardinalities.UNBOUNDED), UpperCardinalities.UNBOUNDED),
38 Arguments.of(
39 List.of(
40 UpperCardinalities.UNBOUNDED,
41 UpperCardinalities.UNBOUNDED
42 ),
43 UpperCardinalities.UNBOUNDED
44 ),
45 Arguments.of(
46 List.of(
47 UpperCardinalities.UNBOUNDED,
48 UpperCardinality.of(3)
49 ),
50 UpperCardinalities.UNBOUNDED
51 )
52 );
53 }
54}
diff --git a/subprojects/logic/src/test/java/tools/refinery/logic/term/uppercardinality/UpperCardinalitySumAggregatorTest.java b/subprojects/logic/src/test/java/tools/refinery/logic/term/uppercardinality/UpperCardinalitySumAggregatorTest.java
new file mode 100644
index 00000000..e252b097
--- /dev/null
+++ b/subprojects/logic/src/test/java/tools/refinery/logic/term/uppercardinality/UpperCardinalitySumAggregatorTest.java
@@ -0,0 +1,79 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.logic.term.uppercardinality;
7
8import org.hamcrest.MatcherAssert;
9import org.hamcrest.Matchers;
10import org.junit.jupiter.api.BeforeEach;
11import org.junit.jupiter.api.Test;
12import tools.refinery.logic.term.StatefulAggregate;
13
14import static org.hamcrest.MatcherAssert.assertThat;
15
16class UpperCardinalitySumAggregatorTest {
17 private StatefulAggregate<UpperCardinality, UpperCardinality> accumulator;
18
19 @BeforeEach
20 void beforeEach() {
21 accumulator = UpperCardinalitySumAggregator.INSTANCE.createEmptyAggregate();
22 }
23
24 @Test
25 void emptyAggregationTest() {
26 MatcherAssert.assertThat(accumulator.getResult(), Matchers.is(UpperCardinality.of(0)));
27 }
28
29 @Test
30 void singleBoundedTest() {
31 accumulator.add(UpperCardinality.of(3));
32 MatcherAssert.assertThat(accumulator.getResult(), Matchers.is(UpperCardinality.of(3)));
33 }
34
35 @Test
36 void multipleBoundedTest() {
37 accumulator.add(UpperCardinality.of(2));
38 accumulator.add(UpperCardinality.of(3));
39 MatcherAssert.assertThat(accumulator.getResult(), Matchers.is(UpperCardinality.of(5)));
40 }
41
42 @Test
43 void singleUnboundedTest() {
44 accumulator.add(UpperCardinalities.UNBOUNDED);
45 assertThat(accumulator.getResult(), Matchers.is(UpperCardinalities.UNBOUNDED));
46 }
47
48 @Test
49 void multipleUnboundedTest() {
50 accumulator.add(UpperCardinalities.UNBOUNDED);
51 accumulator.add(UpperCardinalities.UNBOUNDED);
52 assertThat(accumulator.getResult(), Matchers.is(UpperCardinalities.UNBOUNDED));
53 }
54
55 @Test
56 void removeBoundedTest() {
57 accumulator.add(UpperCardinality.of(2));
58 accumulator.add(UpperCardinality.of(3));
59 accumulator.remove(UpperCardinality.of(2));
60 MatcherAssert.assertThat(accumulator.getResult(), Matchers.is(UpperCardinality.of(3)));
61 }
62
63 @Test
64 void removeAllUnboundedTest() {
65 accumulator.add(UpperCardinalities.UNBOUNDED);
66 accumulator.add(UpperCardinality.of(3));
67 accumulator.remove(UpperCardinalities.UNBOUNDED);
68 MatcherAssert.assertThat(accumulator.getResult(), Matchers.is(UpperCardinality.of(3)));
69 }
70
71 @Test
72 void removeSomeUnboundedTest() {
73 accumulator.add(UpperCardinalities.UNBOUNDED);
74 accumulator.add(UpperCardinalities.UNBOUNDED);
75 accumulator.add(UpperCardinality.of(3));
76 accumulator.remove(UpperCardinalities.UNBOUNDED);
77 assertThat(accumulator.getResult(), Matchers.is(UpperCardinalities.UNBOUNDED));
78 }
79}
diff --git a/subprojects/logic/src/test/java/tools/refinery/logic/term/uppercardinality/UpperCardinalityTermsEvaluateTest.java b/subprojects/logic/src/test/java/tools/refinery/logic/term/uppercardinality/UpperCardinalityTermsEvaluateTest.java
new file mode 100644
index 00000000..ab71b716
--- /dev/null
+++ b/subprojects/logic/src/test/java/tools/refinery/logic/term/uppercardinality/UpperCardinalityTermsEvaluateTest.java
@@ -0,0 +1,103 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.logic.term.uppercardinality;
7
8import org.hamcrest.Matchers;
9import org.junit.jupiter.params.ParameterizedTest;
10import org.junit.jupiter.params.provider.Arguments;
11import org.junit.jupiter.params.provider.MethodSource;
12import tools.refinery.logic.valuation.Valuation;
13
14import java.util.stream.Stream;
15
16import static org.hamcrest.MatcherAssert.assertThat;
17import static org.hamcrest.Matchers.is;
18
19class UpperCardinalityTermsEvaluateTest {
20 @ParameterizedTest(name = "min({0}, {1}) == {2}")
21 @MethodSource
22 void minTest(UpperCardinality a, UpperCardinality b, UpperCardinality expected) {
23 var term = UpperCardinalityTerms.min(UpperCardinalityTerms.constant(a), UpperCardinalityTerms.constant(b));
24 assertThat(term.getType(), is(UpperCardinality.class));
25 assertThat(term.evaluate(Valuation.empty()), Matchers.is(expected));
26 }
27
28 static Stream<Arguments> minTest() {
29 return Stream.of(
30 Arguments.of(UpperCardinality.of(0), UpperCardinality.of(0), UpperCardinality.of(0)),
31 Arguments.of(UpperCardinality.of(0), UpperCardinality.of(1), UpperCardinality.of(0)),
32 Arguments.of(UpperCardinality.of(1), UpperCardinality.of(0), UpperCardinality.of(0)),
33 Arguments.of(UpperCardinality.of(0), UpperCardinalities.UNBOUNDED, UpperCardinality.of(0)),
34 Arguments.of(UpperCardinalities.UNBOUNDED, UpperCardinality.of(0), UpperCardinality.of(0)),
35 Arguments.of(UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED),
36 Arguments.of(UpperCardinality.of(1), null, null),
37 Arguments.of(null, UpperCardinality.of(1), null),
38 Arguments.of(null, null, null)
39 );
40 }
41
42 @ParameterizedTest(name = "max({0}, {1}) == {2}")
43 @MethodSource
44 void maxTest(UpperCardinality a, UpperCardinality b, UpperCardinality expected) {
45 var term = UpperCardinalityTerms.max(UpperCardinalityTerms.constant(a), UpperCardinalityTerms.constant(b));
46 assertThat(term.getType(), is(UpperCardinality.class));
47 assertThat(term.evaluate(Valuation.empty()), Matchers.is(expected));
48 }
49
50 static Stream<Arguments> maxTest() {
51 return Stream.of(
52 Arguments.of(UpperCardinality.of(0), UpperCardinality.of(0), UpperCardinality.of(0)),
53 Arguments.of(UpperCardinality.of(0), UpperCardinality.of(1), UpperCardinality.of(1)),
54 Arguments.of(UpperCardinality.of(1), UpperCardinality.of(0), UpperCardinality.of(1)),
55 Arguments.of(UpperCardinality.of(0), UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED),
56 Arguments.of(UpperCardinalities.UNBOUNDED, UpperCardinality.of(0), UpperCardinalities.UNBOUNDED),
57 Arguments.of(UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED),
58 Arguments.of(UpperCardinality.of(1), null, null),
59 Arguments.of(null, UpperCardinality.of(1), null),
60 Arguments.of(null, null, null)
61 );
62 }
63
64 @ParameterizedTest(name = "{0} + {1} == {2}")
65 @MethodSource
66 void addTest(UpperCardinality a, UpperCardinality b, UpperCardinality expected) {
67 var term = UpperCardinalityTerms.add(UpperCardinalityTerms.constant(a), UpperCardinalityTerms.constant(b));
68 assertThat(term.getType(), is(UpperCardinality.class));
69 assertThat(term.evaluate(Valuation.empty()), Matchers.is(expected));
70 }
71
72 static Stream<Arguments> addTest() {
73 return Stream.of(
74 Arguments.of(UpperCardinality.of(2), UpperCardinality.of(3), UpperCardinality.of(5)),
75 Arguments.of(UpperCardinality.of(2), UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED),
76 Arguments.of(UpperCardinalities.UNBOUNDED, UpperCardinality.of(2), UpperCardinalities.UNBOUNDED),
77 Arguments.of(UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED),
78 Arguments.of(UpperCardinality.of(1), null, null),
79 Arguments.of(null, UpperCardinality.of(1), null),
80 Arguments.of(null, null, null)
81 );
82 }
83
84 @ParameterizedTest(name = "{0} * {1} == {2}")
85 @MethodSource
86 void mulTest(UpperCardinality a, UpperCardinality b, UpperCardinality expected) {
87 var term = UpperCardinalityTerms.mul(UpperCardinalityTerms.constant(a), UpperCardinalityTerms.constant(b));
88 assertThat(term.getType(), is(UpperCardinality.class));
89 assertThat(term.evaluate(Valuation.empty()), Matchers.is(expected));
90 }
91
92 static Stream<Arguments> mulTest() {
93 return Stream.of(
94 Arguments.of(UpperCardinality.of(2), UpperCardinality.of(3), UpperCardinality.of(6)),
95 Arguments.of(UpperCardinality.of(2), UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED),
96 Arguments.of(UpperCardinalities.UNBOUNDED, UpperCardinality.of(2), UpperCardinalities.UNBOUNDED),
97 Arguments.of(UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED),
98 Arguments.of(UpperCardinality.of(1), null, null),
99 Arguments.of(null, UpperCardinality.of(1), null),
100 Arguments.of(null, null, null)
101 );
102 }
103}
diff --git a/subprojects/logic/src/test/java/tools/refinery/logic/term/uppercardinality/UpperCardinalityTest.java b/subprojects/logic/src/test/java/tools/refinery/logic/term/uppercardinality/UpperCardinalityTest.java
new file mode 100644
index 00000000..70cb6695
--- /dev/null
+++ b/subprojects/logic/src/test/java/tools/refinery/logic/term/uppercardinality/UpperCardinalityTest.java
@@ -0,0 +1,115 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.logic.term.uppercardinality;
7
8import org.junit.jupiter.params.ParameterizedTest;
9import org.junit.jupiter.params.provider.Arguments;
10import org.junit.jupiter.params.provider.MethodSource;
11
12import java.util.stream.Stream;
13
14import static org.hamcrest.MatcherAssert.assertThat;
15import static org.hamcrest.Matchers.equalTo;
16
17class UpperCardinalityTest {
18 @ParameterizedTest(name = "min({0}, {1}) == {2}")
19 @MethodSource
20 void minTest(UpperCardinality a, UpperCardinality b, UpperCardinality expected) {
21 assertThat(a.min(b), equalTo(expected));
22 }
23
24 static Stream<Arguments> minTest() {
25 return Stream.of(
26 Arguments.of(UpperCardinality.of(0), UpperCardinality.of(0), UpperCardinality.of(0)),
27 Arguments.of(UpperCardinality.of(0), UpperCardinality.of(1), UpperCardinality.of(0)),
28 Arguments.of(UpperCardinality.of(1), UpperCardinality.of(0), UpperCardinality.of(0)),
29 Arguments.of(UpperCardinality.of(0), UpperCardinalities.UNBOUNDED, UpperCardinality.of(0)),
30 Arguments.of(UpperCardinalities.UNBOUNDED, UpperCardinality.of(0), UpperCardinality.of(0)),
31 Arguments.of(UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED)
32 );
33 }
34
35 @ParameterizedTest(name = "max({0}, {1}) == {2}")
36 @MethodSource
37 void maxTest(UpperCardinality a, UpperCardinality b, UpperCardinality expected) {
38 assertThat(a.max(b), equalTo(expected));
39 }
40
41 static Stream<Arguments> maxTest() {
42 return Stream.of(
43 Arguments.of(UpperCardinality.of(0), UpperCardinality.of(0), UpperCardinality.of(0)),
44 Arguments.of(UpperCardinality.of(0), UpperCardinality.of(1), UpperCardinality.of(1)),
45 Arguments.of(UpperCardinality.of(1), UpperCardinality.of(0), UpperCardinality.of(1)),
46 Arguments.of(UpperCardinality.of(0), UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED),
47 Arguments.of(UpperCardinalities.UNBOUNDED, UpperCardinality.of(0), UpperCardinalities.UNBOUNDED),
48 Arguments.of(UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED)
49 );
50 }
51
52 @ParameterizedTest(name = "{0} + {1} == {2}")
53 @MethodSource
54 void addTest(UpperCardinality a, UpperCardinality b, UpperCardinality expected) {
55 assertThat(a.add(b), equalTo(expected));
56 }
57
58 static Stream<Arguments> addTest() {
59 return Stream.of(
60 Arguments.of(UpperCardinality.of(2), UpperCardinality.of(3), UpperCardinality.of(5)),
61 Arguments.of(UpperCardinality.of(2), UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED),
62 Arguments.of(UpperCardinalities.UNBOUNDED, UpperCardinality.of(2), UpperCardinalities.UNBOUNDED),
63 Arguments.of(UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED)
64 );
65 }
66
67 @ParameterizedTest(name = "{0} * {1} == {2}")
68 @MethodSource
69 void multiplyTest(UpperCardinality a, UpperCardinality b, UpperCardinality expected) {
70 assertThat(a.multiply(b), equalTo(expected));
71 }
72
73 static Stream<Arguments> multiplyTest() {
74 return Stream.of(
75 Arguments.of(UpperCardinality.of(2), UpperCardinality.of(3), UpperCardinality.of(6)),
76 Arguments.of(UpperCardinality.of(2), UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED),
77 Arguments.of(UpperCardinalities.UNBOUNDED, UpperCardinality.of(2), UpperCardinalities.UNBOUNDED),
78 Arguments.of(UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED)
79 );
80 }
81
82 @ParameterizedTest(name = "{0}.compareTo({1}) == {2}")
83 @MethodSource
84 void compareToTest(UpperCardinality a, UpperCardinality b, int expected) {
85 assertThat(a.compareTo(b), equalTo(expected));
86 }
87
88 static Stream<Arguments> compareToTest() {
89 return Stream.of(
90 Arguments.of(UpperCardinality.of(0), UpperCardinality.of(0), 0),
91 Arguments.of(UpperCardinality.of(0), UpperCardinality.of(1), -1),
92 Arguments.of(UpperCardinality.of(1), UpperCardinality.of(0), 1),
93 Arguments.of(UpperCardinality.of(0), UpperCardinalities.UNBOUNDED, -1),
94 Arguments.of(UpperCardinalities.UNBOUNDED, UpperCardinality.of(0), 1),
95 Arguments.of(UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED, 0)
96 );
97 }
98
99 @ParameterizedTest(name = "{0}.compareToInt({1}) == {2}")
100 @MethodSource
101 void compareToIntTest(UpperCardinality a, int b, int expected) {
102 assertThat(a.compareToInt(b), equalTo(expected));
103 }
104
105 static Stream<Arguments> compareToIntTest() {
106 return Stream.of(
107 Arguments.of(UpperCardinality.of(3), -1, 1),
108 Arguments.of(UpperCardinality.of(3), 2, 1),
109 Arguments.of(UpperCardinality.of(3), 3, 0),
110 Arguments.of(UpperCardinality.of(3), 4, -1),
111 Arguments.of(UpperCardinalities.UNBOUNDED, -1, 1),
112 Arguments.of(UpperCardinalities.UNBOUNDED, 3, 1)
113 );
114 }
115}
diff --git a/subprojects/logic/src/test/java/tools/refinery/logic/tests/FakeFunctionView.java b/subprojects/logic/src/test/java/tools/refinery/logic/tests/FakeFunctionView.java
new file mode 100644
index 00000000..4a55f561
--- /dev/null
+++ b/subprojects/logic/src/test/java/tools/refinery/logic/tests/FakeFunctionView.java
@@ -0,0 +1,57 @@
1/*
2 * SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.logic.tests;
7
8import tools.refinery.logic.Constraint;
9import tools.refinery.logic.term.*;
10
11import java.util.ArrayList;
12import java.util.Arrays;
13import java.util.List;
14
15public record FakeFunctionView<T>(String name, int keyArity, Class<T> valueType) implements Constraint {
16 @Override
17 public int arity() {
18 return keyArity + 1;
19 }
20
21 @Override
22 public List<Parameter> getParameters() {
23 var parameters = new Parameter[keyArity + 1];
24 Arrays.fill(parameters, Parameter.NODE_OUT);
25 parameters[keyArity] = new Parameter(valueType, ParameterDirection.OUT);
26 return List.of(parameters);
27 }
28
29 public <R> AssignedValue<R> aggregate(Aggregator<R, T> aggregator, List<NodeVariable> arguments) {
30 return targetVariable -> {
31 var placeholderVariable = Variable.of(valueType);
32 var argumentsWithPlaceholder = new ArrayList<Variable>(arguments.size() + 1);
33 argumentsWithPlaceholder.addAll(arguments);
34 argumentsWithPlaceholder.add(placeholderVariable);
35 return aggregateBy(placeholderVariable, aggregator, argumentsWithPlaceholder).toLiteral(targetVariable);
36 };
37 }
38
39 public <R> AssignedValue<R> aggregate(Aggregator<R, T> aggregator, NodeVariable... arguments) {
40 return aggregate(aggregator, List.of(arguments));
41 }
42
43 public AssignedValue<T> leftJoin(T defaultValue, List<NodeVariable> arguments) {
44 return targetVariable -> {
45 var placeholderVariable = Variable.of(valueType);
46 var argumentsWithPlaceholder = new ArrayList<Variable>(arguments.size() + 1);
47 argumentsWithPlaceholder.addAll(arguments);
48 argumentsWithPlaceholder.add(placeholderVariable);
49 return leftJoinBy(placeholderVariable, defaultValue, argumentsWithPlaceholder).toLiteral(targetVariable);
50 };
51 }
52
53 public AssignedValue<T> leftJoin(T defaultValue, NodeVariable... arguments) {
54 return leftJoin(defaultValue, List.of(arguments));
55
56 }
57}
diff --git a/subprojects/logic/src/test/java/tools/refinery/logic/tests/FakeKeyOnlyView.java b/subprojects/logic/src/test/java/tools/refinery/logic/tests/FakeKeyOnlyView.java
new file mode 100644
index 00000000..7e09ddab
--- /dev/null
+++ b/subprojects/logic/src/test/java/tools/refinery/logic/tests/FakeKeyOnlyView.java
@@ -0,0 +1,21 @@
1/*
2 * SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.logic.tests;
7
8import tools.refinery.logic.Constraint;
9import tools.refinery.logic.term.Parameter;
10
11import java.util.Arrays;
12import java.util.List;
13
14public record FakeKeyOnlyView(String name, int arity) implements Constraint {
15 @Override
16 public List<Parameter> getParameters() {
17 var parameters = new Parameter[arity];
18 Arrays.fill(parameters, Parameter.NODE_OUT);
19 return List.of(parameters);
20 }
21}
diff --git a/subprojects/logic/src/test/java/tools/refinery/logic/tests/StructurallyEqualToRawTest.java b/subprojects/logic/src/test/java/tools/refinery/logic/tests/StructurallyEqualToRawTest.java
new file mode 100644
index 00000000..52a22ce1
--- /dev/null
+++ b/subprojects/logic/src/test/java/tools/refinery/logic/tests/StructurallyEqualToRawTest.java
@@ -0,0 +1,155 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.logic.tests;
7
8import org.junit.jupiter.api.Test;
9import tools.refinery.logic.Constraint;
10import tools.refinery.logic.dnf.Dnf;
11import tools.refinery.logic.dnf.SymbolicParameter;
12import tools.refinery.logic.term.NodeVariable;
13import tools.refinery.logic.term.ParameterDirection;
14import tools.refinery.logic.term.Variable;
15
16import java.util.List;
17
18import static org.hamcrest.CoreMatchers.containsString;
19import static org.hamcrest.MatcherAssert.assertThat;
20import static org.hamcrest.Matchers.allOf;
21import static org.junit.jupiter.api.Assertions.assertThrows;
22import static tools.refinery.logic.tests.QueryMatchers.structurallyEqualTo;
23
24class StructurallyEqualToRawTest {
25 private static final Constraint personView = new FakeKeyOnlyView("Person", 1);
26 private static final Constraint friendView = new FakeKeyOnlyView("friend", 2);
27 private static final NodeVariable p = Variable.of("p");
28 private static final NodeVariable q = Variable.of("q");
29
30 @Test
31 void flatEqualsTest() {
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 actual = Dnf.builder("Actual").parameters(p).clause(friendView.call(p, q)).build();
43
44 var assertion = structurallyEqualTo(
45 List.of(new SymbolicParameter(q, ParameterDirection.OUT)),
46 List.of(List.of(friendView.call(q, q)))
47 );
48 assertThrows(AssertionError.class, () -> assertThat(actual, assertion));
49 }
50
51 @Test
52 void deepEqualsTest() {
53 var actual = Dnf.builder("Actual").parameters(q).clause(
54 Dnf.builder("Actual2").parameters(p).clause(personView.call(p)).build().call(q)
55 ).build();
56
57 assertThat(actual, structurallyEqualTo(
58 List.of(new SymbolicParameter(q, ParameterDirection.OUT)),
59 List.of(
60 List.of(
61 Dnf.builder("Expected2").parameters(p).clause(personView.call(p)).build().call(q)
62 )
63 )
64 ));
65 }
66
67 @Test
68 void deepNotEqualsTest() {
69 var actual = Dnf.builder("Actual").parameter(q).clause(
70 Dnf.builder("Actual2").parameters(p).clause(friendView.call(p, q)).build().call(q)
71 ).build();
72
73 var assertion = structurallyEqualTo(
74 List.of(new SymbolicParameter(q, ParameterDirection.OUT)),
75 List.of(
76 List.of(
77 Dnf.builder("Expected2")
78 .parameters(p)
79 .clause(friendView.call(p, p))
80 .build()
81 .call(q)
82 )
83 )
84 );
85 var error = assertThrows(AssertionError.class, () -> assertThat(actual, assertion));
86 assertThat(error.getMessage(), allOf(containsString("Expected2"), containsString("Actual2")));
87 }
88
89 @Test
90 void parameterListLengthMismatchTest() {
91 var actual = Dnf.builder("Actual").parameters(p, q).clause(
92 friendView.call(p, q)
93 ).build();
94
95 var assertion = structurallyEqualTo(
96 List.of(new SymbolicParameter(p, ParameterDirection.OUT)),
97 List.of(List.of(friendView.call(p, p)))
98 );
99
100 assertThrows(AssertionError.class, () -> assertThat(actual, assertion));
101 }
102
103 @Test
104 void parameterDirectionMismatchTest() {
105 var actual = Dnf.builder("Actual").parameter(p, ParameterDirection.IN).clause(
106 personView.call(p)
107 ).build();
108
109 var assertion = structurallyEqualTo(
110 List.of(new SymbolicParameter(p, ParameterDirection.OUT)),
111 List.of(List.of(personView.call(p)))
112 );
113
114 assertThrows(AssertionError.class, () -> assertThat(actual, assertion));
115 }
116
117 @Test
118 void clauseCountMismatchTest() {
119 var actual = Dnf.builder("Actual").parameters(p, q).clause(
120 friendView.call(p, q)
121 ).build();
122
123 var assertion = structurallyEqualTo(
124 List.of(
125 new SymbolicParameter(p, ParameterDirection.OUT),
126 new SymbolicParameter(q, ParameterDirection.OUT)
127 ),
128 List.of(
129 List.of(friendView.call(p, q)),
130 List.of(friendView.call(q, p))
131 )
132 );
133
134 assertThrows(AssertionError.class, () -> assertThat(actual, assertion));
135 }
136
137 @Test
138 void literalCountMismatchTest() {
139 var actual = Dnf.builder("Actual").parameters(p, q).clause(
140 friendView.call(p, q)
141 ).build();
142
143 var assertion = structurallyEqualTo(
144 List.of(
145 new SymbolicParameter(p, ParameterDirection.OUT),
146 new SymbolicParameter(q, ParameterDirection.OUT)
147 ),
148 List.of(
149 List.of(friendView.call(p, q), friendView.call(q, p))
150 )
151 );
152
153 assertThrows(AssertionError.class, () -> assertThat(actual, assertion));
154 }
155}
diff --git a/subprojects/logic/src/test/java/tools/refinery/logic/tests/StructurallyEqualToTest.java b/subprojects/logic/src/test/java/tools/refinery/logic/tests/StructurallyEqualToTest.java
new file mode 100644
index 00000000..663b115a
--- /dev/null
+++ b/subprojects/logic/src/test/java/tools/refinery/logic/tests/StructurallyEqualToTest.java
@@ -0,0 +1,123 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.logic.tests;
7
8import org.junit.jupiter.api.Test;
9import tools.refinery.logic.Constraint;
10import tools.refinery.logic.dnf.Dnf;
11import tools.refinery.logic.term.NodeVariable;
12import tools.refinery.logic.term.ParameterDirection;
13import tools.refinery.logic.term.Variable;
14
15import static org.hamcrest.CoreMatchers.containsString;
16import static org.hamcrest.MatcherAssert.assertThat;
17import static org.junit.jupiter.api.Assertions.assertThrows;
18import static tools.refinery.logic.tests.QueryMatchers.structurallyEqualTo;
19
20class StructurallyEqualToTest {
21 private static final Constraint personView = new FakeKeyOnlyView("Person", 1);
22 private static final Constraint friendView = new FakeKeyOnlyView("friend", 2);
23 private static final NodeVariable p = Variable.of("p");
24 private static final NodeVariable q = Variable.of("q");
25
26 @Test
27 void flatEqualsTest() {
28 var expected = Dnf.builder("Expected").parameters(q).clause(personView.call(q)).build();
29 var actual = Dnf.builder("Actual").parameters(p).clause(personView.call(p)).build();
30
31 assertThat(actual, structurallyEqualTo(expected));
32 }
33
34 @Test
35 void flatNotEqualsTest() {
36 var expected = Dnf.builder("Expected").parameters(q).clause(friendView.call(q, q)).build();
37 var actual = Dnf.builder("Actual").parameters(p).clause(friendView.call(p, q)).build();
38
39 var assertion = structurallyEqualTo(expected);
40 assertThrows(AssertionError.class, () -> assertThat(actual, assertion));
41 }
42
43 @Test
44 void deepEqualsTest() {
45 var expected = Dnf.builder("Expected").parameters(q).clause(
46 Dnf.builder("Expected2").parameters(p).clause(personView.call(p)).build().call(q)
47 ).build();
48 var actual = Dnf.builder("Actual").parameters(q).clause(
49 Dnf.builder("Actual2").parameters(p).clause(personView.call(p)).build().call(q)
50 ).build();
51
52 assertThat(actual, structurallyEqualTo(expected));
53 }
54
55 @Test
56 void deepNotEqualsTest() {
57 var expected = Dnf.builder("Expected").parameters(q).clause(
58 Dnf.builder("Expected2").parameters(p).clause(friendView.call(p, p)).build().call(q)
59 ).build();
60 var actual = Dnf.builder("Actual").parameter(q).clause(
61 Dnf.builder("Actual2").parameters(p).clause(friendView.call(p, q)).build().call(q)
62 ).build();
63
64 var assertion = structurallyEqualTo(expected);
65 var error = assertThrows(AssertionError.class, () -> assertThat(actual, assertion));
66 assertThat(error.getMessage(), containsString(" called from Expected/1 "));
67 }
68
69 @Test
70 void parameterListLengthMismatchTest() {
71 var expected = Dnf.builder("Expected").parameter(p).clause(
72 friendView.call(p, p)
73 ).build();
74 var actual = Dnf.builder("Actual").parameters(p, q).clause(
75 friendView.call(p, q)
76 ).build();
77
78 var assertion = structurallyEqualTo(expected);
79 assertThrows(AssertionError.class, () -> assertThat(actual, assertion));
80 }
81
82 @Test
83 void parameterDirectionMismatchTest() {
84 var expected = Dnf.builder("Expected").parameter(p, ParameterDirection.OUT).clause(
85 personView.call(p)
86 ).build();
87 var actual = Dnf.builder("Actual").parameter(p, ParameterDirection.IN).clause(
88 personView.call(p)
89 ).build();
90
91 var assertion = structurallyEqualTo(expected);
92 assertThrows(AssertionError.class, () -> assertThat(actual, assertion));
93 }
94
95 @Test
96 void clauseCountMismatchTest() {
97 var expected = Dnf.builder("Expected")
98 .parameters(p, q)
99 .clause(friendView.call(p, q))
100 .clause(friendView.call(q, p))
101 .build();
102 var actual = Dnf.builder("Actual").parameters(p, q).clause(
103 friendView.call(p, q)
104 ).build();
105
106 var assertion = structurallyEqualTo(expected);
107 assertThrows(AssertionError.class, () -> assertThat(actual, assertion));
108 }
109
110 @Test
111 void literalCountMismatchTest() {
112 var expected = Dnf.builder("Expected").parameters(p, q).clause(
113 friendView.call(p, q),
114 friendView.call(q, p)
115 ).build();
116 var actual = Dnf.builder("Actual").parameters(p, q).clause(
117 friendView.call(p, q)
118 ).build();
119
120 var assertion = structurallyEqualTo(expected);
121 assertThrows(AssertionError.class, () -> assertThat(actual, assertion));
122 }
123}