diff options
Diffstat (limited to 'subprojects/store-query-viatra/src/test/java/tools')
12 files changed, 2120 insertions, 565 deletions
diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/DiagonalQueryTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/DiagonalQueryTest.java new file mode 100644 index 00000000..6aae2ebe --- /dev/null +++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/DiagonalQueryTest.java | |||
@@ -0,0 +1,390 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.viatra; | ||
7 | |||
8 | import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint; | ||
9 | import tools.refinery.store.model.ModelStore; | ||
10 | import tools.refinery.store.query.ModelQueryAdapter; | ||
11 | import tools.refinery.store.query.dnf.Dnf; | ||
12 | import tools.refinery.store.query.dnf.Query; | ||
13 | import tools.refinery.store.query.viatra.tests.QueryEngineTest; | ||
14 | import tools.refinery.store.query.view.AnySymbolView; | ||
15 | import tools.refinery.store.query.view.FunctionView; | ||
16 | import tools.refinery.store.query.view.KeyOnlyView; | ||
17 | import tools.refinery.store.representation.Symbol; | ||
18 | import tools.refinery.store.tuple.Tuple; | ||
19 | |||
20 | import java.util.List; | ||
21 | import java.util.Map; | ||
22 | import java.util.Optional; | ||
23 | |||
24 | import static tools.refinery.store.query.literal.Literals.not; | ||
25 | import static tools.refinery.store.query.term.int_.IntTerms.INT_SUM; | ||
26 | import static tools.refinery.store.query.viatra.tests.QueryAssertions.assertNullableResults; | ||
27 | import static tools.refinery.store.query.viatra.tests.QueryAssertions.assertResults; | ||
28 | |||
29 | class DiagonalQueryTest { | ||
30 | private static final Symbol<Boolean> person = Symbol.of("Person", 1); | ||
31 | private static final Symbol<Boolean> friend = Symbol.of("friend", 2); | ||
32 | private static final Symbol<Boolean> symbol = Symbol.of("symbol", 4); | ||
33 | private static final Symbol<Integer> intSymbol = Symbol.of("intSymbol", 4, Integer.class); | ||
34 | private static final AnySymbolView personView = new KeyOnlyView<>(person); | ||
35 | private static final AnySymbolView friendView = new KeyOnlyView<>(friend); | ||
36 | private static final AnySymbolView symbolView = new KeyOnlyView<>(symbol); | ||
37 | private static final FunctionView<Integer> intSymbolView = new FunctionView<>(intSymbol); | ||
38 | |||
39 | @QueryEngineTest | ||
40 | void inputKeyNegationTest(QueryEvaluationHint hint) { | ||
41 | var query = Query.of("Diagonal", (builder, p1) -> builder.clause(p2 -> List.of( | ||
42 | personView.call(p1), | ||
43 | not(symbolView.call(p1, p1, p2, p2)) | ||
44 | ))); | ||
45 | |||
46 | var store = ModelStore.builder() | ||
47 | .symbols(person, symbol) | ||
48 | .with(ViatraModelQueryAdapter.builder() | ||
49 | .defaultHint(hint) | ||
50 | .queries(query)) | ||
51 | .build(); | ||
52 | |||
53 | var model = store.createEmptyModel(); | ||
54 | var personInterpretation = model.getInterpretation(person); | ||
55 | var symbolInterpretation = model.getInterpretation(symbol); | ||
56 | var queryEngine = model.getAdapter(ModelQueryAdapter.class); | ||
57 | var queryResultSet = queryEngine.getResultSet(query); | ||
58 | |||
59 | personInterpretation.put(Tuple.of(0), true); | ||
60 | personInterpretation.put(Tuple.of(1), true); | ||
61 | personInterpretation.put(Tuple.of(2), true); | ||
62 | |||
63 | symbolInterpretation.put(Tuple.of(0, 0, 1, 1), true); | ||
64 | symbolInterpretation.put(Tuple.of(0, 0, 1, 2), true); | ||
65 | symbolInterpretation.put(Tuple.of(1, 1, 0, 1), true); | ||
66 | symbolInterpretation.put(Tuple.of(1, 2, 1, 1), true); | ||
67 | |||
68 | queryEngine.flushChanges(); | ||
69 | assertResults(Map.of( | ||
70 | Tuple.of(0), false, | ||
71 | Tuple.of(1), true, | ||
72 | Tuple.of(2), true, | ||
73 | Tuple.of(3), false | ||
74 | ), queryResultSet); | ||
75 | } | ||
76 | |||
77 | @QueryEngineTest | ||
78 | void subQueryNegationTest(QueryEvaluationHint hint) { | ||
79 | var subQuery = Query.of("SubQuery", (builder, p1, p2, p3, p4) -> builder | ||
80 | .clause( | ||
81 | personView.call(p1), | ||
82 | symbolView.call(p1, p2, p3, p4) | ||
83 | ) | ||
84 | .clause( | ||
85 | personView.call(p2), | ||
86 | symbolView.call(p1, p2, p3, p4) | ||
87 | )); | ||
88 | var query = Query.of("Diagonal", (builder, p1) -> builder.clause(p2 -> List.of( | ||
89 | personView.call(p1), | ||
90 | not(subQuery.call(p1, p1, p2, p2)) | ||
91 | ))); | ||
92 | |||
93 | var store = ModelStore.builder() | ||
94 | .symbols(person, symbol) | ||
95 | .with(ViatraModelQueryAdapter.builder() | ||
96 | .defaultHint(hint) | ||
97 | .queries(query)) | ||
98 | .build(); | ||
99 | |||
100 | var model = store.createEmptyModel(); | ||
101 | var personInterpretation = model.getInterpretation(person); | ||
102 | var symbolInterpretation = model.getInterpretation(symbol); | ||
103 | var queryEngine = model.getAdapter(ModelQueryAdapter.class); | ||
104 | var queryResultSet = queryEngine.getResultSet(query); | ||
105 | |||
106 | personInterpretation.put(Tuple.of(0), true); | ||
107 | personInterpretation.put(Tuple.of(1), true); | ||
108 | personInterpretation.put(Tuple.of(2), true); | ||
109 | |||
110 | symbolInterpretation.put(Tuple.of(0, 0, 1, 1), true); | ||
111 | symbolInterpretation.put(Tuple.of(0, 0, 1, 2), true); | ||
112 | symbolInterpretation.put(Tuple.of(1, 1, 0, 1), true); | ||
113 | symbolInterpretation.put(Tuple.of(1, 2, 1, 1), true); | ||
114 | |||
115 | queryEngine.flushChanges(); | ||
116 | assertResults(Map.of( | ||
117 | Tuple.of(0), false, | ||
118 | Tuple.of(1), true, | ||
119 | Tuple.of(2), true, | ||
120 | Tuple.of(3), false | ||
121 | ), queryResultSet); | ||
122 | } | ||
123 | |||
124 | @QueryEngineTest | ||
125 | void inputKeyCountTest(QueryEvaluationHint hint) { | ||
126 | var query = Query.of("Diagonal", Integer.class, (builder, p1, output) -> builder.clause(p2 -> List.of( | ||
127 | personView.call(p1), | ||
128 | output.assign(symbolView.count(p1, p1, p2, p2)) | ||
129 | ))); | ||
130 | |||
131 | var store = ModelStore.builder() | ||
132 | .symbols(person, symbol) | ||
133 | .with(ViatraModelQueryAdapter.builder() | ||
134 | .defaultHint(hint) | ||
135 | .queries(query)) | ||
136 | .build(); | ||
137 | |||
138 | var model = store.createEmptyModel(); | ||
139 | var personInterpretation = model.getInterpretation(person); | ||
140 | var symbolInterpretation = model.getInterpretation(symbol); | ||
141 | var queryEngine = model.getAdapter(ModelQueryAdapter.class); | ||
142 | var queryResultSet = queryEngine.getResultSet(query); | ||
143 | |||
144 | personInterpretation.put(Tuple.of(0), true); | ||
145 | personInterpretation.put(Tuple.of(1), true); | ||
146 | personInterpretation.put(Tuple.of(2), true); | ||
147 | |||
148 | symbolInterpretation.put(Tuple.of(0, 0, 1, 1), true); | ||
149 | symbolInterpretation.put(Tuple.of(0, 0, 2, 2), true); | ||
150 | symbolInterpretation.put(Tuple.of(0, 0, 1, 2), true); | ||
151 | symbolInterpretation.put(Tuple.of(1, 1, 0, 1), true); | ||
152 | symbolInterpretation.put(Tuple.of(1, 2, 1, 1), true); | ||
153 | |||
154 | queryEngine.flushChanges(); | ||
155 | assertNullableResults(Map.of( | ||
156 | Tuple.of(0), Optional.of(2), | ||
157 | Tuple.of(1), Optional.of(0), | ||
158 | Tuple.of(2), Optional.of(0), | ||
159 | Tuple.of(3), Optional.empty() | ||
160 | ), queryResultSet); | ||
161 | } | ||
162 | |||
163 | @QueryEngineTest | ||
164 | void subQueryCountTest(QueryEvaluationHint hint) { | ||
165 | var subQuery = Query.of("SubQuery", (builder, p1, p2, p3, p4) -> builder.clause( | ||
166 | personView.call(p1), | ||
167 | symbolView.call(p1, p2, p3, p4) | ||
168 | ) | ||
169 | .clause( | ||
170 | personView.call(p2), | ||
171 | symbolView.call(p1, p2, p3, p4) | ||
172 | )); | ||
173 | var query = Query.of("Diagonal", Integer.class, (builder, p1, output) -> builder.clause(p2 -> List.of( | ||
174 | personView.call(p1), | ||
175 | output.assign(subQuery.count(p1, p1, p2, p2)) | ||
176 | ))); | ||
177 | |||
178 | var store = ModelStore.builder() | ||
179 | .symbols(person, symbol) | ||
180 | .with(ViatraModelQueryAdapter.builder() | ||
181 | .defaultHint(hint) | ||
182 | .queries(query)) | ||
183 | .build(); | ||
184 | |||
185 | var model = store.createEmptyModel(); | ||
186 | var personInterpretation = model.getInterpretation(person); | ||
187 | var symbolInterpretation = model.getInterpretation(symbol); | ||
188 | var queryEngine = model.getAdapter(ModelQueryAdapter.class); | ||
189 | var queryResultSet = queryEngine.getResultSet(query); | ||
190 | |||
191 | personInterpretation.put(Tuple.of(0), true); | ||
192 | personInterpretation.put(Tuple.of(1), true); | ||
193 | personInterpretation.put(Tuple.of(2), true); | ||
194 | |||
195 | symbolInterpretation.put(Tuple.of(0, 0, 1, 1), true); | ||
196 | symbolInterpretation.put(Tuple.of(0, 0, 2, 2), true); | ||
197 | symbolInterpretation.put(Tuple.of(0, 0, 1, 2), true); | ||
198 | symbolInterpretation.put(Tuple.of(1, 1, 0, 1), true); | ||
199 | symbolInterpretation.put(Tuple.of(1, 2, 1, 1), true); | ||
200 | |||
201 | queryEngine.flushChanges(); | ||
202 | assertNullableResults(Map.of( | ||
203 | Tuple.of(0), Optional.of(2), | ||
204 | Tuple.of(1), Optional.of(0), | ||
205 | Tuple.of(2), Optional.of(0), | ||
206 | Tuple.of(3), Optional.empty() | ||
207 | ), queryResultSet); | ||
208 | } | ||
209 | |||
210 | @QueryEngineTest | ||
211 | void inputKeyAggregationTest(QueryEvaluationHint hint) { | ||
212 | var query = Query.of("Diagonal", Integer.class, (builder, p1, output) -> builder | ||
213 | .clause((p2) -> List.of( | ||
214 | personView.call(p1), | ||
215 | output.assign(intSymbolView.aggregate(INT_SUM, p1, p1, p2, p2)) | ||
216 | ))); | ||
217 | |||
218 | var store = ModelStore.builder() | ||
219 | .symbols(person, intSymbol) | ||
220 | .with(ViatraModelQueryAdapter.builder() | ||
221 | .defaultHint(hint) | ||
222 | .queries(query)) | ||
223 | .build(); | ||
224 | |||
225 | var model = store.createEmptyModel(); | ||
226 | var personInterpretation = model.getInterpretation(person); | ||
227 | var intSymbolInterpretation = model.getInterpretation(intSymbol); | ||
228 | var queryEngine = model.getAdapter(ModelQueryAdapter.class); | ||
229 | var queryResultSet = queryEngine.getResultSet(query); | ||
230 | |||
231 | personInterpretation.put(Tuple.of(0), true); | ||
232 | personInterpretation.put(Tuple.of(1), true); | ||
233 | personInterpretation.put(Tuple.of(2), true); | ||
234 | |||
235 | intSymbolInterpretation.put(Tuple.of(0, 0, 1, 1), 1); | ||
236 | intSymbolInterpretation.put(Tuple.of(0, 0, 2, 2), 2); | ||
237 | intSymbolInterpretation.put(Tuple.of(0, 0, 1, 2), 10); | ||
238 | intSymbolInterpretation.put(Tuple.of(1, 1, 0, 1), 11); | ||
239 | intSymbolInterpretation.put(Tuple.of(1, 2, 1, 1), 12); | ||
240 | |||
241 | queryEngine.flushChanges(); | ||
242 | assertNullableResults(Map.of( | ||
243 | Tuple.of(0), Optional.of(3), | ||
244 | Tuple.of(1), Optional.of(0), | ||
245 | Tuple.of(2), Optional.of(0), | ||
246 | Tuple.of(3), Optional.empty() | ||
247 | ), queryResultSet); | ||
248 | } | ||
249 | |||
250 | @QueryEngineTest | ||
251 | void subQueryAggregationTest(QueryEvaluationHint hint) { | ||
252 | var subQuery = Dnf.of("SubQuery", builder -> { | ||
253 | var p1 = builder.parameter("p1"); | ||
254 | var p2 = builder.parameter("p2"); | ||
255 | var p3 = builder.parameter("p3"); | ||
256 | var p4 = builder.parameter("p4"); | ||
257 | var x = builder.parameter("x", Integer.class); | ||
258 | var y = builder.parameter("y", Integer.class); | ||
259 | builder.clause( | ||
260 | personView.call(p1), | ||
261 | intSymbolView.call(p1, p2, p3, p4, x), | ||
262 | y.assign(x) | ||
263 | ); | ||
264 | builder.clause( | ||
265 | personView.call(p2), | ||
266 | intSymbolView.call(p1, p2, p3, p4, x), | ||
267 | y.assign(x) | ||
268 | ); | ||
269 | }); | ||
270 | var query = Query.of("Diagonal", Integer.class, (builder, p1, output) -> builder | ||
271 | .clause(Integer.class, Integer.class, (p2, y, z) -> List.of( | ||
272 | personView.call(p1), | ||
273 | output.assign(subQuery.aggregateBy(y, INT_SUM, p1, p1, p2, p2, y, z)) | ||
274 | ))); | ||
275 | |||
276 | var store = ModelStore.builder() | ||
277 | .symbols(person, intSymbol) | ||
278 | .with(ViatraModelQueryAdapter.builder() | ||
279 | .defaultHint(hint) | ||
280 | .queries(query)) | ||
281 | .build(); | ||
282 | |||
283 | var model = store.createEmptyModel(); | ||
284 | var personInterpretation = model.getInterpretation(person); | ||
285 | var intSymbolInterpretation = model.getInterpretation(intSymbol); | ||
286 | var queryEngine = model.getAdapter(ModelQueryAdapter.class); | ||
287 | var queryResultSet = queryEngine.getResultSet(query); | ||
288 | |||
289 | personInterpretation.put(Tuple.of(0), true); | ||
290 | personInterpretation.put(Tuple.of(1), true); | ||
291 | personInterpretation.put(Tuple.of(2), true); | ||
292 | |||
293 | intSymbolInterpretation.put(Tuple.of(0, 0, 1, 1), 1); | ||
294 | intSymbolInterpretation.put(Tuple.of(0, 0, 2, 2), 2); | ||
295 | intSymbolInterpretation.put(Tuple.of(0, 0, 1, 2), 10); | ||
296 | intSymbolInterpretation.put(Tuple.of(1, 1, 0, 1), 11); | ||
297 | intSymbolInterpretation.put(Tuple.of(1, 2, 1, 1), 12); | ||
298 | |||
299 | queryEngine.flushChanges(); | ||
300 | assertNullableResults(Map.of( | ||
301 | Tuple.of(0), Optional.of(3), | ||
302 | Tuple.of(1), Optional.of(0), | ||
303 | Tuple.of(2), Optional.of(0), | ||
304 | Tuple.of(3), Optional.empty() | ||
305 | ), queryResultSet); | ||
306 | } | ||
307 | |||
308 | @QueryEngineTest | ||
309 | void inputKeyTransitiveTest(QueryEvaluationHint hint) { | ||
310 | var query = Query.of("Diagonal", (builder, p1) -> builder.clause( | ||
311 | personView.call(p1), | ||
312 | friendView.callTransitive(p1, p1) | ||
313 | )); | ||
314 | |||
315 | var store = ModelStore.builder() | ||
316 | .symbols(person, friend) | ||
317 | .with(ViatraModelQueryAdapter.builder() | ||
318 | .defaultHint(hint) | ||
319 | .queries(query)) | ||
320 | .build(); | ||
321 | |||
322 | var model = store.createEmptyModel(); | ||
323 | var personInterpretation = model.getInterpretation(person); | ||
324 | var friendInterpretation = model.getInterpretation(friend); | ||
325 | var queryEngine = model.getAdapter(ModelQueryAdapter.class); | ||
326 | var queryResultSet = queryEngine.getResultSet(query); | ||
327 | |||
328 | personInterpretation.put(Tuple.of(0), true); | ||
329 | personInterpretation.put(Tuple.of(1), true); | ||
330 | personInterpretation.put(Tuple.of(2), true); | ||
331 | |||
332 | friendInterpretation.put(Tuple.of(0, 0), true); | ||
333 | friendInterpretation.put(Tuple.of(0, 1), true); | ||
334 | friendInterpretation.put(Tuple.of(1, 2), true); | ||
335 | |||
336 | queryEngine.flushChanges(); | ||
337 | assertResults(Map.of( | ||
338 | Tuple.of(0), true, | ||
339 | Tuple.of(1), false, | ||
340 | Tuple.of(2), false, | ||
341 | Tuple.of(3), false | ||
342 | ), queryResultSet); | ||
343 | } | ||
344 | |||
345 | @QueryEngineTest | ||
346 | void subQueryTransitiveTest(QueryEvaluationHint hint) { | ||
347 | var subQuery = Query.of("SubQuery", (builder, p1, p2) -> builder | ||
348 | .clause( | ||
349 | personView.call(p1), | ||
350 | friendView.call(p1, p2) | ||
351 | ) | ||
352 | .clause( | ||
353 | personView.call(p2), | ||
354 | friendView.call(p1, p2) | ||
355 | )); | ||
356 | var query = Query.of("Diagonal", (builder, p1) -> builder.clause( | ||
357 | personView.call(p1), | ||
358 | subQuery.callTransitive(p1, p1) | ||
359 | )); | ||
360 | |||
361 | var store = ModelStore.builder() | ||
362 | .symbols(person, friend) | ||
363 | .with(ViatraModelQueryAdapter.builder() | ||
364 | .defaultHint(hint) | ||
365 | .queries(query)) | ||
366 | .build(); | ||
367 | |||
368 | var model = store.createEmptyModel(); | ||
369 | var personInterpretation = model.getInterpretation(person); | ||
370 | var friendInterpretation = model.getInterpretation(friend); | ||
371 | var queryEngine = model.getAdapter(ModelQueryAdapter.class); | ||
372 | var queryResultSet = queryEngine.getResultSet(query); | ||
373 | |||
374 | personInterpretation.put(Tuple.of(0), true); | ||
375 | personInterpretation.put(Tuple.of(1), true); | ||
376 | personInterpretation.put(Tuple.of(2), true); | ||
377 | |||
378 | friendInterpretation.put(Tuple.of(0, 0), true); | ||
379 | friendInterpretation.put(Tuple.of(0, 1), true); | ||
380 | friendInterpretation.put(Tuple.of(1, 2), true); | ||
381 | |||
382 | queryEngine.flushChanges(); | ||
383 | assertResults(Map.of( | ||
384 | Tuple.of(0), true, | ||
385 | Tuple.of(1), false, | ||
386 | Tuple.of(2), false, | ||
387 | Tuple.of(3), false | ||
388 | ), queryResultSet); | ||
389 | } | ||
390 | } | ||
diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/FunctionalQueryTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/FunctionalQueryTest.java new file mode 100644 index 00000000..258127e7 --- /dev/null +++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/FunctionalQueryTest.java | |||
@@ -0,0 +1,483 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.viatra; | ||
7 | |||
8 | import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint; | ||
9 | import tools.refinery.store.map.Cursor; | ||
10 | import tools.refinery.store.model.ModelStore; | ||
11 | import tools.refinery.store.query.ModelQueryAdapter; | ||
12 | import tools.refinery.store.query.dnf.Query; | ||
13 | import tools.refinery.store.query.term.Variable; | ||
14 | import tools.refinery.store.query.viatra.tests.QueryEngineTest; | ||
15 | import tools.refinery.store.query.view.AnySymbolView; | ||
16 | import tools.refinery.store.query.view.FilteredView; | ||
17 | import tools.refinery.store.query.view.FunctionView; | ||
18 | import tools.refinery.store.query.view.KeyOnlyView; | ||
19 | import tools.refinery.store.representation.Symbol; | ||
20 | import tools.refinery.store.representation.TruthValue; | ||
21 | import tools.refinery.store.tuple.Tuple; | ||
22 | |||
23 | import java.util.List; | ||
24 | import java.util.Map; | ||
25 | import java.util.Optional; | ||
26 | |||
27 | import static org.hamcrest.MatcherAssert.assertThat; | ||
28 | import static org.hamcrest.Matchers.is; | ||
29 | import static org.hamcrest.Matchers.nullValue; | ||
30 | import static org.junit.jupiter.api.Assertions.assertAll; | ||
31 | import static org.junit.jupiter.api.Assertions.assertThrows; | ||
32 | import static tools.refinery.store.query.literal.Literals.assume; | ||
33 | import static tools.refinery.store.query.term.int_.IntTerms.*; | ||
34 | import static tools.refinery.store.query.viatra.tests.QueryAssertions.assertNullableResults; | ||
35 | import static tools.refinery.store.query.viatra.tests.QueryAssertions.assertResults; | ||
36 | |||
37 | class FunctionalQueryTest { | ||
38 | private static final Symbol<Boolean> person = Symbol.of("Person", 1); | ||
39 | private static final Symbol<Integer> age = Symbol.of("age", 1, Integer.class); | ||
40 | private static final Symbol<TruthValue> friend = Symbol.of("friend", 2, TruthValue.class, TruthValue.FALSE); | ||
41 | private static final AnySymbolView personView = new KeyOnlyView<>(person); | ||
42 | private static final FunctionView<Integer> ageView = new FunctionView<>(age); | ||
43 | private static final AnySymbolView friendMustView = new FilteredView<>(friend, "must", TruthValue::must); | ||
44 | |||
45 | @QueryEngineTest | ||
46 | void inputKeyTest(QueryEvaluationHint hint) { | ||
47 | var query = Query.of("InputKey", Integer.class, (builder, p1, output) -> builder.clause( | ||
48 | personView.call(p1), | ||
49 | ageView.call(p1, output) | ||
50 | )); | ||
51 | |||
52 | var store = ModelStore.builder() | ||
53 | .symbols(person, age) | ||
54 | .with(ViatraModelQueryAdapter.builder() | ||
55 | .defaultHint(hint) | ||
56 | .queries(query)) | ||
57 | .build(); | ||
58 | |||
59 | var model = store.createEmptyModel(); | ||
60 | var personInterpretation = model.getInterpretation(person); | ||
61 | var ageInterpretation = model.getInterpretation(age); | ||
62 | var queryEngine = model.getAdapter(ModelQueryAdapter.class); | ||
63 | var queryResultSet = queryEngine.getResultSet(query); | ||
64 | |||
65 | personInterpretation.put(Tuple.of(0), true); | ||
66 | personInterpretation.put(Tuple.of(1), true); | ||
67 | |||
68 | ageInterpretation.put(Tuple.of(0), 12); | ||
69 | ageInterpretation.put(Tuple.of(1), 24); | ||
70 | ageInterpretation.put(Tuple.of(2), 36); | ||
71 | |||
72 | queryEngine.flushChanges(); | ||
73 | assertNullableResults(Map.of( | ||
74 | Tuple.of(0), Optional.of(12), | ||
75 | Tuple.of(1), Optional.of(24), | ||
76 | Tuple.of(2), Optional.empty() | ||
77 | ), queryResultSet); | ||
78 | } | ||
79 | |||
80 | @QueryEngineTest | ||
81 | void predicateTest(QueryEvaluationHint hint) { | ||
82 | var subQuery = Query.of("SubQuery", Integer.class, (builder, p1, x) -> builder.clause( | ||
83 | personView.call(p1), | ||
84 | ageView.call(p1, x) | ||
85 | )); | ||
86 | var query = Query.of("Predicate", Integer.class, (builder, p1, output) -> builder.clause( | ||
87 | personView.call(p1), | ||
88 | output.assign(subQuery.call(p1)) | ||
89 | )); | ||
90 | |||
91 | var store = ModelStore.builder() | ||
92 | .symbols(person, age) | ||
93 | .with(ViatraModelQueryAdapter.builder() | ||
94 | .defaultHint(hint) | ||
95 | .queries(query)) | ||
96 | .build(); | ||
97 | |||
98 | var model = store.createEmptyModel(); | ||
99 | var personInterpretation = model.getInterpretation(person); | ||
100 | var ageInterpretation = model.getInterpretation(age); | ||
101 | var queryEngine = model.getAdapter(ModelQueryAdapter.class); | ||
102 | var queryResultSet = queryEngine.getResultSet(query); | ||
103 | |||
104 | personInterpretation.put(Tuple.of(0), true); | ||
105 | personInterpretation.put(Tuple.of(1), true); | ||
106 | |||
107 | ageInterpretation.put(Tuple.of(0), 12); | ||
108 | ageInterpretation.put(Tuple.of(1), 24); | ||
109 | ageInterpretation.put(Tuple.of(2), 36); | ||
110 | |||
111 | queryEngine.flushChanges(); | ||
112 | assertNullableResults(Map.of( | ||
113 | Tuple.of(0), Optional.of(12), | ||
114 | Tuple.of(1), Optional.of(24), | ||
115 | Tuple.of(2), Optional.empty() | ||
116 | ), queryResultSet); | ||
117 | } | ||
118 | |||
119 | @QueryEngineTest | ||
120 | void computationTest(QueryEvaluationHint hint) { | ||
121 | var query = Query.of("Computation", Integer.class, (builder, p1, output) -> builder.clause(() -> { | ||
122 | var x = Variable.of("x", Integer.class); | ||
123 | return List.of( | ||
124 | personView.call(p1), | ||
125 | ageView.call(p1, x), | ||
126 | output.assign(mul(x, constant(7))) | ||
127 | ); | ||
128 | })); | ||
129 | |||
130 | var store = ModelStore.builder() | ||
131 | .symbols(person, age) | ||
132 | .with(ViatraModelQueryAdapter.builder() | ||
133 | .defaultHint(hint) | ||
134 | .queries(query)) | ||
135 | .build(); | ||
136 | |||
137 | var model = store.createEmptyModel(); | ||
138 | var personInterpretation = model.getInterpretation(person); | ||
139 | var ageInterpretation = model.getInterpretation(age); | ||
140 | var queryEngine = model.getAdapter(ModelQueryAdapter.class); | ||
141 | var queryResultSet = queryEngine.getResultSet(query); | ||
142 | |||
143 | personInterpretation.put(Tuple.of(0), true); | ||
144 | personInterpretation.put(Tuple.of(1), true); | ||
145 | |||
146 | ageInterpretation.put(Tuple.of(0), 12); | ||
147 | ageInterpretation.put(Tuple.of(1), 24); | ||
148 | |||
149 | queryEngine.flushChanges(); | ||
150 | assertNullableResults(Map.of( | ||
151 | Tuple.of(0), Optional.of(84), | ||
152 | Tuple.of(1), Optional.of(168), | ||
153 | Tuple.of(2), Optional.empty() | ||
154 | ), queryResultSet); | ||
155 | } | ||
156 | |||
157 | @QueryEngineTest | ||
158 | void inputKeyCountTest(QueryEvaluationHint hint) { | ||
159 | var query = Query.of("Count", Integer.class, (builder, p1, output) -> builder.clause( | ||
160 | personView.call(p1), | ||
161 | output.assign(friendMustView.count(p1, Variable.of())) | ||
162 | )); | ||
163 | |||
164 | var store = ModelStore.builder() | ||
165 | .symbols(person, friend) | ||
166 | .with(ViatraModelQueryAdapter.builder() | ||
167 | .defaultHint(hint) | ||
168 | .queries(query)) | ||
169 | .build(); | ||
170 | |||
171 | var model = store.createEmptyModel(); | ||
172 | var personInterpretation = model.getInterpretation(person); | ||
173 | var friendInterpretation = model.getInterpretation(friend); | ||
174 | var queryEngine = model.getAdapter(ModelQueryAdapter.class); | ||
175 | var queryResultSet = queryEngine.getResultSet(query); | ||
176 | |||
177 | personInterpretation.put(Tuple.of(0), true); | ||
178 | personInterpretation.put(Tuple.of(1), true); | ||
179 | personInterpretation.put(Tuple.of(2), true); | ||
180 | |||
181 | friendInterpretation.put(Tuple.of(0, 1), TruthValue.TRUE); | ||
182 | friendInterpretation.put(Tuple.of(1, 0), TruthValue.TRUE); | ||
183 | friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE); | ||
184 | |||
185 | queryEngine.flushChanges(); | ||
186 | assertNullableResults(Map.of( | ||
187 | Tuple.of(0), Optional.of(1), | ||
188 | Tuple.of(1), Optional.of(2), | ||
189 | Tuple.of(2), Optional.of(0), | ||
190 | Tuple.of(3), Optional.empty() | ||
191 | ), queryResultSet); | ||
192 | } | ||
193 | |||
194 | @QueryEngineTest | ||
195 | void predicateCountTest(QueryEvaluationHint hint) { | ||
196 | var subQuery = Query.of("SubQuery", (builder, p1, p2) -> builder.clause( | ||
197 | personView.call(p1), | ||
198 | personView.call(p2), | ||
199 | friendMustView.call(p1, p2) | ||
200 | )); | ||
201 | var query = Query.of("Count", Integer.class, (builder, p1, output) -> builder.clause( | ||
202 | personView.call(p1), | ||
203 | output.assign(subQuery.count(p1, Variable.of())) | ||
204 | )); | ||
205 | |||
206 | var store = ModelStore.builder() | ||
207 | .symbols(person, friend) | ||
208 | .with(ViatraModelQueryAdapter.builder() | ||
209 | .defaultHint(hint) | ||
210 | .queries(query)) | ||
211 | .build(); | ||
212 | |||
213 | var model = store.createEmptyModel(); | ||
214 | var personInterpretation = model.getInterpretation(person); | ||
215 | var friendInterpretation = model.getInterpretation(friend); | ||
216 | var queryEngine = model.getAdapter(ModelQueryAdapter.class); | ||
217 | var queryResultSet = queryEngine.getResultSet(query); | ||
218 | |||
219 | personInterpretation.put(Tuple.of(0), true); | ||
220 | personInterpretation.put(Tuple.of(1), true); | ||
221 | personInterpretation.put(Tuple.of(2), true); | ||
222 | |||
223 | friendInterpretation.put(Tuple.of(0, 1), TruthValue.TRUE); | ||
224 | friendInterpretation.put(Tuple.of(1, 0), TruthValue.TRUE); | ||
225 | friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE); | ||
226 | |||
227 | queryEngine.flushChanges(); | ||
228 | assertNullableResults(Map.of( | ||
229 | Tuple.of(0), Optional.of(1), | ||
230 | Tuple.of(1), Optional.of(2), | ||
231 | Tuple.of(2), Optional.of(0), | ||
232 | Tuple.of(3), Optional.empty() | ||
233 | ), queryResultSet); | ||
234 | } | ||
235 | |||
236 | @QueryEngineTest | ||
237 | void inputKeyAggregationTest(QueryEvaluationHint hint) { | ||
238 | var query = Query.of("Aggregate", Integer.class, (builder, output) -> builder.clause( | ||
239 | output.assign(ageView.aggregate(INT_SUM, Variable.of())) | ||
240 | )); | ||
241 | |||
242 | var store = ModelStore.builder() | ||
243 | .symbols(age) | ||
244 | .with(ViatraModelQueryAdapter.builder() | ||
245 | .defaultHint(hint) | ||
246 | .queries(query)) | ||
247 | .build(); | ||
248 | |||
249 | var model = store.createEmptyModel(); | ||
250 | var ageInterpretation = model.getInterpretation(age); | ||
251 | var queryEngine = model.getAdapter(ModelQueryAdapter.class); | ||
252 | var queryResultSet = queryEngine.getResultSet(query); | ||
253 | |||
254 | ageInterpretation.put(Tuple.of(0), 12); | ||
255 | ageInterpretation.put(Tuple.of(1), 24); | ||
256 | |||
257 | queryEngine.flushChanges(); | ||
258 | assertResults(Map.of(Tuple.of(), 36), queryResultSet); | ||
259 | } | ||
260 | |||
261 | @QueryEngineTest | ||
262 | void predicateAggregationTest(QueryEvaluationHint hint) { | ||
263 | var subQuery = Query.of("SubQuery", Integer.class, (builder, p1, x) -> builder.clause( | ||
264 | personView.call(p1), | ||
265 | ageView.call(p1, x) | ||
266 | )); | ||
267 | var query = Query.of("Aggregate", Integer.class, (builder, output) -> builder.clause( | ||
268 | output.assign(subQuery.aggregate(INT_SUM, Variable.of())) | ||
269 | )); | ||
270 | |||
271 | var store = ModelStore.builder() | ||
272 | .symbols(person, age) | ||
273 | .with(ViatraModelQueryAdapter.builder() | ||
274 | .defaultHint(hint) | ||
275 | .queries(query)) | ||
276 | .build(); | ||
277 | |||
278 | var model = store.createEmptyModel(); | ||
279 | var personInterpretation = model.getInterpretation(person); | ||
280 | var ageInterpretation = model.getInterpretation(age); | ||
281 | var queryEngine = model.getAdapter(ModelQueryAdapter.class); | ||
282 | var queryResultSet = queryEngine.getResultSet(query); | ||
283 | |||
284 | personInterpretation.put(Tuple.of(0), true); | ||
285 | personInterpretation.put(Tuple.of(1), true); | ||
286 | |||
287 | ageInterpretation.put(Tuple.of(0), 12); | ||
288 | ageInterpretation.put(Tuple.of(1), 24); | ||
289 | |||
290 | queryEngine.flushChanges(); | ||
291 | assertResults(Map.of(Tuple.of(), 36), queryResultSet); | ||
292 | } | ||
293 | |||
294 | @QueryEngineTest | ||
295 | void extremeValueTest(QueryEvaluationHint hint) { | ||
296 | var subQuery = Query.of("SubQuery", Integer.class, (builder, p1, x) -> builder.clause( | ||
297 | personView.call(p1), | ||
298 | x.assign(friendMustView.count(p1, Variable.of())) | ||
299 | )); | ||
300 | var minQuery = Query.of("Min", Integer.class, (builder, output) -> builder.clause( | ||
301 | output.assign(subQuery.aggregate(INT_MIN, Variable.of())) | ||
302 | )); | ||
303 | var maxQuery = Query.of("Max", Integer.class, (builder, output) -> builder.clause( | ||
304 | output.assign(subQuery.aggregate(INT_MAX, Variable.of())) | ||
305 | )); | ||
306 | |||
307 | var store = ModelStore.builder() | ||
308 | .symbols(person, friend) | ||
309 | .with(ViatraModelQueryAdapter.builder() | ||
310 | .defaultHint(hint) | ||
311 | .queries(minQuery, maxQuery)) | ||
312 | .build(); | ||
313 | |||
314 | var model = store.createEmptyModel(); | ||
315 | var personInterpretation = model.getInterpretation(person); | ||
316 | var friendInterpretation = model.getInterpretation(friend); | ||
317 | var queryEngine = model.getAdapter(ModelQueryAdapter.class); | ||
318 | var minResultSet = queryEngine.getResultSet(minQuery); | ||
319 | var maxResultSet = queryEngine.getResultSet(maxQuery); | ||
320 | |||
321 | assertResults(Map.of(Tuple.of(), Integer.MAX_VALUE), minResultSet); | ||
322 | assertResults(Map.of(Tuple.of(), Integer.MIN_VALUE), maxResultSet); | ||
323 | |||
324 | personInterpretation.put(Tuple.of(0), true); | ||
325 | personInterpretation.put(Tuple.of(1), true); | ||
326 | personInterpretation.put(Tuple.of(2), true); | ||
327 | |||
328 | friendInterpretation.put(Tuple.of(0, 1), TruthValue.TRUE); | ||
329 | friendInterpretation.put(Tuple.of(1, 0), TruthValue.TRUE); | ||
330 | friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE); | ||
331 | |||
332 | queryEngine.flushChanges(); | ||
333 | assertResults(Map.of(Tuple.of(), 0), minResultSet); | ||
334 | assertResults(Map.of(Tuple.of(), 2), maxResultSet); | ||
335 | |||
336 | friendInterpretation.put(Tuple.of(2, 0), TruthValue.TRUE); | ||
337 | friendInterpretation.put(Tuple.of(2, 1), TruthValue.TRUE); | ||
338 | |||
339 | queryEngine.flushChanges(); | ||
340 | assertResults(Map.of(Tuple.of(), 1), minResultSet); | ||
341 | assertResults(Map.of(Tuple.of(), 2), maxResultSet); | ||
342 | |||
343 | friendInterpretation.put(Tuple.of(0, 1), TruthValue.FALSE); | ||
344 | friendInterpretation.put(Tuple.of(1, 0), TruthValue.FALSE); | ||
345 | friendInterpretation.put(Tuple.of(2, 0), TruthValue.FALSE); | ||
346 | |||
347 | queryEngine.flushChanges(); | ||
348 | assertResults(Map.of(Tuple.of(), 0), minResultSet); | ||
349 | assertResults(Map.of(Tuple.of(), 1), maxResultSet); | ||
350 | } | ||
351 | |||
352 | @QueryEngineTest | ||
353 | void invalidComputationTest(QueryEvaluationHint hint) { | ||
354 | var query = Query.of("InvalidComputation", Integer.class, | ||
355 | (builder, p1, output) -> builder.clause(Integer.class, (x) -> List.of( | ||
356 | personView.call(p1), | ||
357 | ageView.call(p1, x), | ||
358 | output.assign(div(constant(120), x)) | ||
359 | ))); | ||
360 | |||
361 | var store = ModelStore.builder() | ||
362 | .symbols(person, age) | ||
363 | .with(ViatraModelQueryAdapter.builder() | ||
364 | .defaultHint(hint) | ||
365 | .queries(query)) | ||
366 | .build(); | ||
367 | |||
368 | var model = store.createEmptyModel(); | ||
369 | var personInterpretation = model.getInterpretation(person); | ||
370 | var ageInterpretation = model.getInterpretation(age); | ||
371 | var queryEngine = model.getAdapter(ModelQueryAdapter.class); | ||
372 | var queryResultSet = queryEngine.getResultSet(query); | ||
373 | |||
374 | personInterpretation.put(Tuple.of(0), true); | ||
375 | personInterpretation.put(Tuple.of(1), true); | ||
376 | |||
377 | ageInterpretation.put(Tuple.of(0), 0); | ||
378 | ageInterpretation.put(Tuple.of(1), 30); | ||
379 | |||
380 | queryEngine.flushChanges(); | ||
381 | assertNullableResults(Map.of( | ||
382 | Tuple.of(0), Optional.empty(), | ||
383 | Tuple.of(1), Optional.of(4), | ||
384 | Tuple.of(2), Optional.empty() | ||
385 | ), queryResultSet); | ||
386 | } | ||
387 | |||
388 | @QueryEngineTest | ||
389 | void invalidAssumeTest(QueryEvaluationHint hint) { | ||
390 | var query = Query.of("InvalidAssume", (builder, p1) -> builder.clause(Integer.class, (x) -> List.of( | ||
391 | personView.call(p1), | ||
392 | ageView.call(p1, x), | ||
393 | assume(lessEq(div(constant(120), x), constant(5))) | ||
394 | ))); | ||
395 | |||
396 | var store = ModelStore.builder() | ||
397 | .symbols(person, age) | ||
398 | .with(ViatraModelQueryAdapter.builder() | ||
399 | .defaultHint(hint) | ||
400 | .queries(query)) | ||
401 | .build(); | ||
402 | |||
403 | var model = store.createEmptyModel(); | ||
404 | var personInterpretation = model.getInterpretation(person); | ||
405 | var ageInterpretation = model.getInterpretation(age); | ||
406 | var queryEngine = model.getAdapter(ModelQueryAdapter.class); | ||
407 | var queryResultSet = queryEngine.getResultSet(query); | ||
408 | |||
409 | personInterpretation.put(Tuple.of(0), true); | ||
410 | personInterpretation.put(Tuple.of(1), true); | ||
411 | personInterpretation.put(Tuple.of(2), true); | ||
412 | |||
413 | ageInterpretation.put(Tuple.of(0), 0); | ||
414 | ageInterpretation.put(Tuple.of(1), 30); | ||
415 | ageInterpretation.put(Tuple.of(2), 20); | ||
416 | |||
417 | queryEngine.flushChanges(); | ||
418 | assertResults(Map.of( | ||
419 | Tuple.of(0), false, | ||
420 | Tuple.of(1), true, | ||
421 | Tuple.of(2), false, | ||
422 | Tuple.of(3), false | ||
423 | ), queryResultSet); | ||
424 | } | ||
425 | |||
426 | @QueryEngineTest | ||
427 | void notFunctionalTest(QueryEvaluationHint hint) { | ||
428 | var query = Query.of("NotFunctional", Integer.class, (builder, p1, output) -> builder.clause((p2) -> List.of( | ||
429 | personView.call(p1), | ||
430 | friendMustView.call(p1, p2), | ||
431 | ageView.call(p2, output) | ||
432 | ))); | ||
433 | |||
434 | var store = ModelStore.builder() | ||
435 | .symbols(person, age, friend) | ||
436 | .with(ViatraModelQueryAdapter.builder() | ||
437 | .defaultHint(hint) | ||
438 | .queries(query)) | ||
439 | .build(); | ||
440 | |||
441 | var model = store.createEmptyModel(); | ||
442 | var personInterpretation = model.getInterpretation(person); | ||
443 | var ageInterpretation = model.getInterpretation(age); | ||
444 | var friendInterpretation = model.getInterpretation(friend); | ||
445 | var queryEngine = model.getAdapter(ModelQueryAdapter.class); | ||
446 | var queryResultSet = queryEngine.getResultSet(query); | ||
447 | |||
448 | personInterpretation.put(Tuple.of(0), true); | ||
449 | personInterpretation.put(Tuple.of(1), true); | ||
450 | personInterpretation.put(Tuple.of(2), true); | ||
451 | |||
452 | ageInterpretation.put(Tuple.of(0), 24); | ||
453 | ageInterpretation.put(Tuple.of(1), 30); | ||
454 | ageInterpretation.put(Tuple.of(2), 36); | ||
455 | |||
456 | friendInterpretation.put(Tuple.of(0, 1), TruthValue.TRUE); | ||
457 | friendInterpretation.put(Tuple.of(1, 0), TruthValue.TRUE); | ||
458 | friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE); | ||
459 | |||
460 | queryEngine.flushChanges(); | ||
461 | var invalidTuple = Tuple.of(1); | ||
462 | var cursor = queryResultSet.getAll(); | ||
463 | assertAll( | ||
464 | () -> assertThat("value for key 0", queryResultSet.get(Tuple.of(0)), is(30)), | ||
465 | () -> assertThrows(IllegalStateException.class, () -> queryResultSet.get(invalidTuple), | ||
466 | "multiple values for key 1"), | ||
467 | () -> assertThat("value for key 2", queryResultSet.get(Tuple.of(2)), is(nullValue())), | ||
468 | () -> assertThat("value for key 3", queryResultSet.get(Tuple.of(3)), is(nullValue())) | ||
469 | ); | ||
470 | if (hint.getQueryBackendRequirementType() != QueryEvaluationHint.BackendRequirement.DEFAULT_SEARCH) { | ||
471 | // Local search doesn't support throwing an error on multiple function return values. | ||
472 | assertThat("results size", queryResultSet.size(), is(2)); | ||
473 | assertThrows(IllegalStateException.class, () -> enumerateValues(cursor), "move cursor"); | ||
474 | } | ||
475 | } | ||
476 | |||
477 | private static void enumerateValues(Cursor<?, ?> cursor) { | ||
478 | //noinspection StatementWithEmptyBody | ||
479 | while (cursor.move()) { | ||
480 | // Nothing do, just let the cursor move through the result set. | ||
481 | } | ||
482 | } | ||
483 | } | ||
diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/OrderedResultSetTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/OrderedResultSetTest.java new file mode 100644 index 00000000..8ede6c80 --- /dev/null +++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/OrderedResultSetTest.java | |||
@@ -0,0 +1,117 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.viatra; | ||
7 | |||
8 | import org.junit.jupiter.api.Test; | ||
9 | import tools.refinery.store.model.ModelStore; | ||
10 | import tools.refinery.store.query.ModelQueryAdapter; | ||
11 | import tools.refinery.store.query.dnf.Query; | ||
12 | import tools.refinery.store.query.resultset.OrderedResultSet; | ||
13 | import tools.refinery.store.query.term.Variable; | ||
14 | import tools.refinery.store.query.view.AnySymbolView; | ||
15 | import tools.refinery.store.query.view.KeyOnlyView; | ||
16 | import tools.refinery.store.representation.Symbol; | ||
17 | import tools.refinery.store.tuple.Tuple; | ||
18 | |||
19 | import static org.hamcrest.MatcherAssert.assertThat; | ||
20 | import static org.hamcrest.Matchers.is; | ||
21 | |||
22 | class OrderedResultSetTest { | ||
23 | private static final Symbol<Boolean> friend = Symbol.of("friend", 2); | ||
24 | private static final AnySymbolView friendView = new KeyOnlyView<>(friend); | ||
25 | |||
26 | @Test | ||
27 | void relationalFlushTest() { | ||
28 | var query = Query.of("Relation", (builder, p1, p2) -> builder.clause( | ||
29 | friendView.call(p1, p2) | ||
30 | )); | ||
31 | |||
32 | var store = ModelStore.builder() | ||
33 | .symbols(friend) | ||
34 | .with(ViatraModelQueryAdapter.builder() | ||
35 | .queries(query)) | ||
36 | .build(); | ||
37 | |||
38 | var model = store.createEmptyModel(); | ||
39 | var friendInterpretation = model.getInterpretation(friend); | ||
40 | var queryEngine = model.getAdapter(ModelQueryAdapter.class); | ||
41 | var resultSet = queryEngine.getResultSet(query); | ||
42 | |||
43 | friendInterpretation.put(Tuple.of(0, 1), true); | ||
44 | friendInterpretation.put(Tuple.of(1, 2), true); | ||
45 | friendInterpretation.put(Tuple.of(1, 1), true); | ||
46 | queryEngine.flushChanges(); | ||
47 | |||
48 | try (var orderedResultSet = new OrderedResultSet<>(resultSet)) { | ||
49 | assertThat(orderedResultSet.size(), is(3)); | ||
50 | assertThat(orderedResultSet.getKey(0), is(Tuple.of(0, 1))); | ||
51 | assertThat(orderedResultSet.getKey(1), is(Tuple.of(1, 1))); | ||
52 | assertThat(orderedResultSet.getKey(2), is(Tuple.of(1, 2))); | ||
53 | |||
54 | friendInterpretation.put(Tuple.of(1, 2), false); | ||
55 | friendInterpretation.put(Tuple.of(0, 2), true); | ||
56 | queryEngine.flushChanges(); | ||
57 | |||
58 | assertThat(orderedResultSet.size(), is(3)); | ||
59 | assertThat(orderedResultSet.getKey(0), is(Tuple.of(0, 1))); | ||
60 | assertThat(orderedResultSet.getKey(1), is(Tuple.of(0, 2))); | ||
61 | assertThat(orderedResultSet.getKey(2), is(Tuple.of(1, 1))); | ||
62 | } | ||
63 | } | ||
64 | |||
65 | @Test | ||
66 | void functionalFlushTest() { | ||
67 | var query = Query.of("Function", Integer.class, (builder, p1, output) -> builder.clause( | ||
68 | friendView.call(p1, Variable.of()), | ||
69 | output.assign(friendView.count(p1, Variable.of())) | ||
70 | )); | ||
71 | |||
72 | var store = ModelStore.builder() | ||
73 | .symbols(friend) | ||
74 | .with(ViatraModelQueryAdapter.builder() | ||
75 | .queries(query)) | ||
76 | .build(); | ||
77 | |||
78 | var model = store.createEmptyModel(); | ||
79 | var friendInterpretation = model.getInterpretation(friend); | ||
80 | var queryEngine = model.getAdapter(ModelQueryAdapter.class); | ||
81 | var resultSet = queryEngine.getResultSet(query); | ||
82 | |||
83 | friendInterpretation.put(Tuple.of(0, 1), true); | ||
84 | friendInterpretation.put(Tuple.of(1, 2), true); | ||
85 | friendInterpretation.put(Tuple.of(1, 1), true); | ||
86 | queryEngine.flushChanges(); | ||
87 | |||
88 | try (var orderedResultSet = new OrderedResultSet<>(resultSet)) { | ||
89 | assertThat(orderedResultSet.size(), is(2)); | ||
90 | assertThat(orderedResultSet.getKey(0), is(Tuple.of(0))); | ||
91 | assertThat(orderedResultSet.getKey(1), is(Tuple.of(1))); | ||
92 | |||
93 | friendInterpretation.put(Tuple.of(0, 1), false); | ||
94 | friendInterpretation.put(Tuple.of(2, 1), true); | ||
95 | queryEngine.flushChanges(); | ||
96 | |||
97 | assertThat(orderedResultSet.size(), is(2)); | ||
98 | assertThat(orderedResultSet.getKey(0), is(Tuple.of(1))); | ||
99 | assertThat(orderedResultSet.getKey(1), is(Tuple.of(2))); | ||
100 | |||
101 | friendInterpretation.put(Tuple.of(1, 1), false); | ||
102 | queryEngine.flushChanges(); | ||
103 | |||
104 | assertThat(orderedResultSet.size(), is(2)); | ||
105 | assertThat(orderedResultSet.getKey(0), is(Tuple.of(1))); | ||
106 | assertThat(orderedResultSet.getKey(1), is(Tuple.of(2))); | ||
107 | |||
108 | friendInterpretation.put(Tuple.of(1, 2), false); | ||
109 | friendInterpretation.put(Tuple.of(1, 0), true); | ||
110 | queryEngine.flushChanges(); | ||
111 | |||
112 | assertThat(orderedResultSet.size(), is(2)); | ||
113 | assertThat(orderedResultSet.getKey(0), is(Tuple.of(1))); | ||
114 | assertThat(orderedResultSet.getKey(1), is(Tuple.of(2))); | ||
115 | } | ||
116 | } | ||
117 | } | ||
diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTest.java index 6a37b54a..25bcb0dc 100644 --- a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTest.java +++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTest.java | |||
@@ -1,47 +1,57 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
1 | package tools.refinery.store.query.viatra; | 6 | package tools.refinery.store.query.viatra; |
2 | 7 | ||
8 | import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint; | ||
3 | import org.junit.jupiter.api.Test; | 9 | import org.junit.jupiter.api.Test; |
4 | import tools.refinery.store.model.ModelStore; | 10 | import tools.refinery.store.model.ModelStore; |
5 | import tools.refinery.store.query.DNF; | 11 | import tools.refinery.store.query.ModelQueryAdapter; |
6 | import tools.refinery.store.query.ModelQuery; | 12 | import tools.refinery.store.query.dnf.Query; |
7 | import tools.refinery.store.query.Variable; | 13 | import tools.refinery.store.query.term.Variable; |
8 | import tools.refinery.store.query.atom.*; | 14 | import tools.refinery.store.query.viatra.tests.QueryEngineTest; |
9 | import tools.refinery.store.query.view.FilteredRelationView; | 15 | import tools.refinery.store.query.view.AnySymbolView; |
10 | import tools.refinery.store.query.view.KeyOnlyRelationView; | 16 | import tools.refinery.store.query.view.FilteredView; |
17 | import tools.refinery.store.query.view.FunctionView; | ||
18 | import tools.refinery.store.query.view.KeyOnlyView; | ||
11 | import tools.refinery.store.representation.Symbol; | 19 | import tools.refinery.store.representation.Symbol; |
12 | import tools.refinery.store.representation.TruthValue; | 20 | import tools.refinery.store.representation.TruthValue; |
13 | import tools.refinery.store.tuple.Tuple; | 21 | import tools.refinery.store.tuple.Tuple; |
14 | import tools.refinery.store.tuple.TupleLike; | ||
15 | 22 | ||
16 | import java.util.HashSet; | 23 | import java.util.List; |
17 | import java.util.Set; | 24 | import java.util.Map; |
18 | import java.util.stream.Stream; | ||
19 | 25 | ||
20 | import static org.junit.jupiter.api.Assertions.assertEquals; | 26 | import static tools.refinery.store.query.literal.Literals.assume; |
27 | import static tools.refinery.store.query.literal.Literals.not; | ||
28 | import static tools.refinery.store.query.term.int_.IntTerms.constant; | ||
29 | import static tools.refinery.store.query.term.int_.IntTerms.greaterEq; | ||
30 | import static tools.refinery.store.query.viatra.tests.QueryAssertions.assertResults; | ||
21 | 31 | ||
22 | class QueryTest { | 32 | class QueryTest { |
23 | @Test | 33 | private static final Symbol<Boolean> person = Symbol.of("Person", 1); |
24 | void typeConstraintTest() { | 34 | private static final Symbol<TruthValue> friend = Symbol.of("friend", 2, TruthValue.class, TruthValue.FALSE); |
25 | var person = new Symbol<>("Person", 1, Boolean.class, false); | 35 | private static final AnySymbolView personView = new KeyOnlyView<>(person); |
26 | var asset = new Symbol<>("Asset", 1, Boolean.class, false); | 36 | private static final AnySymbolView friendMustView = new FilteredView<>(friend, "must", TruthValue::must); |
27 | var personView = new KeyOnlyRelationView<>(person); | 37 | |
28 | 38 | @QueryEngineTest | |
29 | var p1 = new Variable("p1"); | 39 | void typeConstraintTest(QueryEvaluationHint hint) { |
30 | var predicate = DNF.builder("TypeConstraint") | 40 | var asset = Symbol.of("Asset", 1); |
31 | .parameters(p1) | 41 | |
32 | .clause(new RelationViewAtom(personView, p1)) | 42 | var predicate = Query.of("TypeConstraint", (builder, p1) -> builder.clause(personView.call(p1))); |
33 | .build(); | ||
34 | 43 | ||
35 | var store = ModelStore.builder() | 44 | var store = ModelStore.builder() |
36 | .symbols(person, asset) | 45 | .symbols(person, asset) |
37 | .with(ViatraModelQuery.ADAPTER) | 46 | .with(ViatraModelQueryAdapter.builder() |
38 | .queries(predicate) | 47 | .defaultHint(hint) |
48 | .queries(predicate)) | ||
39 | .build(); | 49 | .build(); |
40 | 50 | ||
41 | var model = store.createEmptyModel(); | 51 | var model = store.createEmptyModel(); |
42 | var personInterpretation = model.getInterpretation(person); | 52 | var personInterpretation = model.getInterpretation(person); |
43 | var assetInterpretation = model.getInterpretation(asset); | 53 | var assetInterpretation = model.getInterpretation(asset); |
44 | var queryEngine = model.getAdapter(ModelQuery.ADAPTER); | 54 | var queryEngine = model.getAdapter(ModelQueryAdapter.class); |
45 | var predicateResultSet = queryEngine.getResultSet(predicate); | 55 | var predicateResultSet = queryEngine.getResultSet(predicate); |
46 | 56 | ||
47 | personInterpretation.put(Tuple.of(0), true); | 57 | personInterpretation.put(Tuple.of(0), true); |
@@ -51,42 +61,34 @@ class QueryTest { | |||
51 | assetInterpretation.put(Tuple.of(2), true); | 61 | assetInterpretation.put(Tuple.of(2), true); |
52 | 62 | ||
53 | queryEngine.flushChanges(); | 63 | queryEngine.flushChanges(); |
54 | assertEquals(2, predicateResultSet.countResults()); | 64 | assertResults(Map.of( |
55 | compareMatchSets(predicateResultSet.allResults(), Set.of(Tuple.of(0), Tuple.of(1))); | 65 | Tuple.of(0), true, |
66 | Tuple.of(1), true, | ||
67 | Tuple.of(2), false | ||
68 | ), predicateResultSet); | ||
56 | } | 69 | } |
57 | 70 | ||
58 | @Test | 71 | @QueryEngineTest |
59 | void relationConstraintTest() { | 72 | void relationConstraintTest(QueryEvaluationHint hint) { |
60 | var person = new Symbol<>("Person", 1, Boolean.class, false); | 73 | var predicate = Query.of("RelationConstraint", (builder, p1, p2) -> builder.clause( |
61 | var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); | 74 | personView.call(p1), |
62 | var personView = new KeyOnlyRelationView<>(person); | 75 | personView.call(p2), |
63 | var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); | 76 | friendMustView.call(p1, p2) |
64 | 77 | )); | |
65 | var p1 = new Variable("p1"); | ||
66 | var p2 = new Variable("p2"); | ||
67 | var predicate = DNF.builder("RelationConstraint") | ||
68 | .parameters(p1, p2) | ||
69 | .clause( | ||
70 | new RelationViewAtom(personView, p1), | ||
71 | new RelationViewAtom(personView, p2), | ||
72 | new RelationViewAtom(friendMustView, p1, p2) | ||
73 | ) | ||
74 | .build(); | ||
75 | 78 | ||
76 | var store = ModelStore.builder() | 79 | var store = ModelStore.builder() |
77 | .symbols(person, friend) | 80 | .symbols(person, friend) |
78 | .with(ViatraModelQuery.ADAPTER) | 81 | .with(ViatraModelQueryAdapter.builder() |
79 | .queries(predicate) | 82 | .defaultHint(hint) |
83 | .queries(predicate)) | ||
80 | .build(); | 84 | .build(); |
81 | 85 | ||
82 | var model = store.createEmptyModel(); | 86 | var model = store.createEmptyModel(); |
83 | var personInterpretation = model.getInterpretation(person); | 87 | var personInterpretation = model.getInterpretation(person); |
84 | var friendInterpretation = model.getInterpretation(friend); | 88 | var friendInterpretation = model.getInterpretation(friend); |
85 | var queryEngine = model.getAdapter(ModelQuery.ADAPTER); | 89 | var queryEngine = model.getAdapter(ModelQueryAdapter.class); |
86 | var predicateResultSet = queryEngine.getResultSet(predicate); | 90 | var predicateResultSet = queryEngine.getResultSet(predicate); |
87 | 91 | ||
88 | assertEquals(0, predicateResultSet.countResults()); | ||
89 | |||
90 | personInterpretation.put(Tuple.of(0), true); | 92 | personInterpretation.put(Tuple.of(0), true); |
91 | personInterpretation.put(Tuple.of(1), true); | 93 | personInterpretation.put(Tuple.of(1), true); |
92 | personInterpretation.put(Tuple.of(2), true); | 94 | personInterpretation.put(Tuple.of(2), true); |
@@ -94,97 +96,36 @@ class QueryTest { | |||
94 | friendInterpretation.put(Tuple.of(0, 1), TruthValue.TRUE); | 96 | friendInterpretation.put(Tuple.of(0, 1), TruthValue.TRUE); |
95 | friendInterpretation.put(Tuple.of(1, 0), TruthValue.TRUE); | 97 | friendInterpretation.put(Tuple.of(1, 0), TruthValue.TRUE); |
96 | friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE); | 98 | friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE); |
97 | 99 | friendInterpretation.put(Tuple.of(1, 3), TruthValue.TRUE); | |
98 | assertEquals(0, predicateResultSet.countResults()); | ||
99 | 100 | ||
100 | queryEngine.flushChanges(); | 101 | queryEngine.flushChanges(); |
101 | assertEquals(3, predicateResultSet.countResults()); | 102 | assertResults(Map.of( |
102 | compareMatchSets(predicateResultSet.allResults(), Set.of(Tuple.of(0, 1), Tuple.of(1, 0), Tuple.of(1, 2))); | 103 | Tuple.of(0, 1), true, |
104 | Tuple.of(1, 0), true, | ||
105 | Tuple.of(1, 2), true, | ||
106 | Tuple.of(2, 1), false | ||
107 | ), predicateResultSet); | ||
103 | } | 108 | } |
104 | 109 | ||
105 | @Test | 110 | @QueryEngineTest |
106 | void andTest() { | 111 | void existTest(QueryEvaluationHint hint) { |
107 | var person = new Symbol<>("Person", 1, Boolean.class, false); | 112 | var predicate = Query.of("Exists", (builder, p1) -> builder.clause((p2) -> List.of( |
108 | var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); | 113 | personView.call(p1), |
109 | var personView = new KeyOnlyRelationView<>(person); | 114 | personView.call(p2), |
110 | var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); | 115 | friendMustView.call(p1, p2) |
111 | 116 | ))); | |
112 | var p1 = new Variable("p1"); | ||
113 | var p2 = new Variable("p2"); | ||
114 | var predicate = DNF.builder("RelationConstraint") | ||
115 | .parameters(p1, p2) | ||
116 | .clause( | ||
117 | new RelationViewAtom(personView, p1), | ||
118 | new RelationViewAtom(personView, p2), | ||
119 | new RelationViewAtom(friendMustView, p1, p2), | ||
120 | new RelationViewAtom(friendMustView, p2, p1) | ||
121 | ) | ||
122 | .build(); | ||
123 | 117 | ||
124 | var store = ModelStore.builder() | 118 | var store = ModelStore.builder() |
125 | .symbols(person, friend) | 119 | .symbols(person, friend) |
126 | .with(ViatraModelQuery.ADAPTER) | 120 | .with(ViatraModelQueryAdapter.builder() |
127 | .queries(predicate) | 121 | .defaultHint(hint) |
122 | .queries(predicate)) | ||
128 | .build(); | 123 | .build(); |
129 | 124 | ||
130 | var model = store.createEmptyModel(); | 125 | var model = store.createEmptyModel(); |
131 | var personInterpretation = model.getInterpretation(person); | 126 | var personInterpretation = model.getInterpretation(person); |
132 | var friendInterpretation = model.getInterpretation(friend); | 127 | var friendInterpretation = model.getInterpretation(friend); |
133 | var queryEngine = model.getAdapter(ModelQuery.ADAPTER); | 128 | var queryEngine = model.getAdapter(ModelQueryAdapter.class); |
134 | var predicateResultSet = queryEngine.getResultSet(predicate); | ||
135 | |||
136 | assertEquals(0, predicateResultSet.countResults()); | ||
137 | |||
138 | personInterpretation.put(Tuple.of(0), true); | ||
139 | personInterpretation.put(Tuple.of(1), true); | ||
140 | personInterpretation.put(Tuple.of(2), true); | ||
141 | |||
142 | friendInterpretation.put(Tuple.of(0, 1), TruthValue.TRUE); | ||
143 | friendInterpretation.put(Tuple.of(0, 2), TruthValue.TRUE); | ||
144 | |||
145 | queryEngine.flushChanges(); | ||
146 | assertEquals(0, predicateResultSet.countResults()); | ||
147 | |||
148 | friendInterpretation.put(Tuple.of(1, 0), TruthValue.TRUE); | ||
149 | queryEngine.flushChanges(); | ||
150 | assertEquals(2, predicateResultSet.countResults()); | ||
151 | compareMatchSets(predicateResultSet.allResults(), Set.of(Tuple.of(0, 1), Tuple.of(1, 0))); | ||
152 | |||
153 | friendInterpretation.put(Tuple.of(2, 0), TruthValue.TRUE); | ||
154 | queryEngine.flushChanges(); | ||
155 | assertEquals(4, predicateResultSet.countResults()); | ||
156 | compareMatchSets(predicateResultSet.allResults(), Set.of(Tuple.of(0, 1), Tuple.of(1, 0), Tuple.of(0, 2), | ||
157 | Tuple.of(2, 0))); | ||
158 | } | ||
159 | |||
160 | @Test | ||
161 | void existTest() { | ||
162 | var person = new Symbol<>("Person", 1, Boolean.class, false); | ||
163 | var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); | ||
164 | var personView = new KeyOnlyRelationView<>(person); | ||
165 | var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); | ||
166 | |||
167 | var p1 = new Variable("p1"); | ||
168 | var p2 = new Variable("p2"); | ||
169 | var predicate = DNF.builder("RelationConstraint") | ||
170 | .parameters(p1) | ||
171 | .clause( | ||
172 | new RelationViewAtom(personView, p1), | ||
173 | new RelationViewAtom(personView, p2), | ||
174 | new RelationViewAtom(friendMustView, p1, p2) | ||
175 | ) | ||
176 | .build(); | ||
177 | |||
178 | var store = ModelStore.builder() | ||
179 | .symbols(person, friend) | ||
180 | .with(ViatraModelQuery.ADAPTER) | ||
181 | .queries(predicate) | ||
182 | .build(); | ||
183 | |||
184 | var model = store.createEmptyModel(); | ||
185 | var personInterpretation = model.getInterpretation(person); | ||
186 | var friendInterpretation = model.getInterpretation(friend); | ||
187 | var queryEngine = model.getAdapter(ModelQuery.ADAPTER); | ||
188 | var predicateResultSet = queryEngine.getResultSet(predicate); | 129 | var predicateResultSet = queryEngine.getResultSet(predicate); |
189 | 130 | ||
190 | personInterpretation.put(Tuple.of(0), true); | 131 | personInterpretation.put(Tuple.of(0), true); |
@@ -194,50 +135,44 @@ class QueryTest { | |||
194 | friendInterpretation.put(Tuple.of(0, 1), TruthValue.TRUE); | 135 | friendInterpretation.put(Tuple.of(0, 1), TruthValue.TRUE); |
195 | friendInterpretation.put(Tuple.of(1, 0), TruthValue.TRUE); | 136 | friendInterpretation.put(Tuple.of(1, 0), TruthValue.TRUE); |
196 | friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE); | 137 | friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE); |
197 | 138 | friendInterpretation.put(Tuple.of(3, 2), TruthValue.TRUE); | |
198 | assertEquals(0, predicateResultSet.countResults()); | ||
199 | 139 | ||
200 | queryEngine.flushChanges(); | 140 | queryEngine.flushChanges(); |
201 | assertEquals(2, predicateResultSet.countResults()); | 141 | assertResults(Map.of( |
202 | compareMatchSets(predicateResultSet.allResults(), Set.of(Tuple.of(0), Tuple.of(1))); | 142 | Tuple.of(0), true, |
143 | Tuple.of(1), true, | ||
144 | Tuple.of(2), false, | ||
145 | Tuple.of(3), false | ||
146 | ), predicateResultSet); | ||
203 | } | 147 | } |
204 | 148 | ||
205 | @Test | 149 | @QueryEngineTest |
206 | void orTest() { | 150 | void orTest(QueryEvaluationHint hint) { |
207 | var person = new Symbol<>("Person", 1, Boolean.class, false); | 151 | var animal = Symbol.of("Animal", 1); |
208 | var animal = new Symbol<>("Animal", 1, Boolean.class, false); | 152 | var animalView = new KeyOnlyView<>(animal); |
209 | var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); | 153 | |
210 | var personView = new KeyOnlyRelationView<>(person); | 154 | var predicate = Query.of("Or", (builder, p1, p2) -> builder.clause( |
211 | var animalView = new KeyOnlyRelationView<>(animal); | 155 | personView.call(p1), |
212 | var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); | 156 | personView.call(p2), |
213 | 157 | friendMustView.call(p1, p2) | |
214 | var p1 = new Variable("p1"); | 158 | ).clause( |
215 | var p2 = new Variable("p2"); | 159 | animalView.call(p1), |
216 | var predicate = DNF.builder("Or") | 160 | animalView.call(p2), |
217 | .parameters(p1, p2) | 161 | friendMustView.call(p1, p2) |
218 | .clause( | 162 | )); |
219 | new RelationViewAtom(personView, p1), | ||
220 | new RelationViewAtom(personView, p2), | ||
221 | new RelationViewAtom(friendMustView, p1, p2) | ||
222 | ) | ||
223 | .clause( | ||
224 | new RelationViewAtom(animalView, p1), | ||
225 | new RelationViewAtom(animalView, p2), | ||
226 | new RelationViewAtom(friendMustView, p1, p2) | ||
227 | ) | ||
228 | .build(); | ||
229 | 163 | ||
230 | var store = ModelStore.builder() | 164 | var store = ModelStore.builder() |
231 | .symbols(person, animal, friend) | 165 | .symbols(person, animal, friend) |
232 | .with(ViatraModelQuery.ADAPTER) | 166 | .with(ViatraModelQueryAdapter.builder() |
233 | .queries(predicate) | 167 | .defaultHint(hint) |
168 | .queries(predicate)) | ||
234 | .build(); | 169 | .build(); |
235 | 170 | ||
236 | var model = store.createEmptyModel(); | 171 | var model = store.createEmptyModel(); |
237 | var personInterpretation = model.getInterpretation(person); | 172 | var personInterpretation = model.getInterpretation(person); |
238 | var animalInterpretation = model.getInterpretation(animal); | 173 | var animalInterpretation = model.getInterpretation(animal); |
239 | var friendInterpretation = model.getInterpretation(friend); | 174 | var friendInterpretation = model.getInterpretation(friend); |
240 | var queryEngine = model.getAdapter(ModelQuery.ADAPTER); | 175 | var queryEngine = model.getAdapter(ModelQueryAdapter.class); |
241 | var predicateResultSet = queryEngine.getResultSet(predicate); | 176 | var predicateResultSet = queryEngine.getResultSet(predicate); |
242 | 177 | ||
243 | personInterpretation.put(Tuple.of(0), true); | 178 | personInterpretation.put(Tuple.of(0), true); |
@@ -252,35 +187,33 @@ class QueryTest { | |||
252 | friendInterpretation.put(Tuple.of(3, 0), TruthValue.TRUE); | 187 | friendInterpretation.put(Tuple.of(3, 0), TruthValue.TRUE); |
253 | 188 | ||
254 | queryEngine.flushChanges(); | 189 | queryEngine.flushChanges(); |
255 | assertEquals(2, predicateResultSet.countResults()); | 190 | assertResults(Map.of( |
256 | compareMatchSets(predicateResultSet.allResults(), Set.of(Tuple.of(0, 1), Tuple.of(2, 3))); | 191 | Tuple.of(0, 1), true, |
192 | Tuple.of(0, 2), false, | ||
193 | Tuple.of(2, 3), true, | ||
194 | Tuple.of(3, 0), false, | ||
195 | Tuple.of(3, 2), false | ||
196 | ), predicateResultSet); | ||
257 | } | 197 | } |
258 | 198 | ||
259 | @Test | 199 | @QueryEngineTest |
260 | void equalityTest() { | 200 | void equalityTest(QueryEvaluationHint hint) { |
261 | var person = new Symbol<>("Person", 1, Boolean.class, false); | 201 | var predicate = Query.of("Equality", (builder, p1, p2) -> builder.clause( |
262 | var personView = new KeyOnlyRelationView<>(person); | 202 | personView.call(p1), |
263 | 203 | personView.call(p2), | |
264 | var p1 = new Variable("p1"); | 204 | p1.isEquivalent(p2) |
265 | var p2 = new Variable("p2"); | 205 | )); |
266 | var predicate = DNF.builder("Equality") | ||
267 | .parameters(p1, p2) | ||
268 | .clause( | ||
269 | new RelationViewAtom(personView, p1), | ||
270 | new RelationViewAtom(personView, p2), | ||
271 | new EquivalenceAtom(p1, p2) | ||
272 | ) | ||
273 | .build(); | ||
274 | 206 | ||
275 | var store = ModelStore.builder() | 207 | var store = ModelStore.builder() |
276 | .symbols(person) | 208 | .symbols(person) |
277 | .with(ViatraModelQuery.ADAPTER) | 209 | .with(ViatraModelQueryAdapter.builder() |
278 | .queries(predicate) | 210 | .defaultHint(hint) |
211 | .queries(predicate)) | ||
279 | .build(); | 212 | .build(); |
280 | 213 | ||
281 | var model = store.createEmptyModel(); | 214 | var model = store.createEmptyModel(); |
282 | var personInterpretation = model.getInterpretation(person); | 215 | var personInterpretation = model.getInterpretation(person); |
283 | var queryEngine = model.getAdapter(ModelQuery.ADAPTER); | 216 | var queryEngine = model.getAdapter(ModelQueryAdapter.class); |
284 | var predicateResultSet = queryEngine.getResultSet(predicate); | 217 | var predicateResultSet = queryEngine.getResultSet(predicate); |
285 | 218 | ||
286 | personInterpretation.put(Tuple.of(0), true); | 219 | personInterpretation.put(Tuple.of(0), true); |
@@ -288,41 +221,36 @@ class QueryTest { | |||
288 | personInterpretation.put(Tuple.of(2), true); | 221 | personInterpretation.put(Tuple.of(2), true); |
289 | 222 | ||
290 | queryEngine.flushChanges(); | 223 | queryEngine.flushChanges(); |
291 | assertEquals(3, predicateResultSet.countResults()); | 224 | assertResults(Map.of( |
292 | compareMatchSets(predicateResultSet.allResults(), Set.of(Tuple.of(0, 0), Tuple.of(1, 1), Tuple.of(2, 2))); | 225 | Tuple.of(0, 0), true, |
226 | Tuple.of(1, 1), true, | ||
227 | Tuple.of(2, 2), true, | ||
228 | Tuple.of(0, 1), false, | ||
229 | Tuple.of(3, 3), false | ||
230 | ), predicateResultSet); | ||
293 | } | 231 | } |
294 | 232 | ||
295 | @Test | 233 | @QueryEngineTest |
296 | void inequalityTest() { | 234 | void inequalityTest(QueryEvaluationHint hint) { |
297 | var person = new Symbol<>("Person", 1, Boolean.class, false); | 235 | var predicate = Query.of("Inequality", (builder, p1, p2, p3) -> builder.clause( |
298 | var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); | 236 | personView.call(p1), |
299 | var personView = new KeyOnlyRelationView<>(person); | 237 | personView.call(p2), |
300 | var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); | 238 | friendMustView.call(p1, p3), |
301 | 239 | friendMustView.call(p2, p3), | |
302 | var p1 = new Variable("p1"); | 240 | p1.notEquivalent(p2) |
303 | var p2 = new Variable("p2"); | 241 | )); |
304 | var p3 = new Variable("p3"); | ||
305 | var predicate = DNF.builder("Inequality") | ||
306 | .parameters(p1, p2, p3) | ||
307 | .clause( | ||
308 | new RelationViewAtom(personView, p1), | ||
309 | new RelationViewAtom(personView, p2), | ||
310 | new RelationViewAtom(friendMustView, p1, p3), | ||
311 | new RelationViewAtom(friendMustView, p2, p3), | ||
312 | new EquivalenceAtom(false, p1, p2) | ||
313 | ) | ||
314 | .build(); | ||
315 | 242 | ||
316 | var store = ModelStore.builder() | 243 | var store = ModelStore.builder() |
317 | .symbols(person, friend) | 244 | .symbols(person, friend) |
318 | .with(ViatraModelQuery.ADAPTER) | 245 | .with(ViatraModelQueryAdapter.builder() |
319 | .queries(predicate) | 246 | .defaultHint(hint) |
247 | .queries(predicate)) | ||
320 | .build(); | 248 | .build(); |
321 | 249 | ||
322 | var model = store.createEmptyModel(); | 250 | var model = store.createEmptyModel(); |
323 | var personInterpretation = model.getInterpretation(person); | 251 | var personInterpretation = model.getInterpretation(person); |
324 | var friendInterpretation = model.getInterpretation(friend); | 252 | var friendInterpretation = model.getInterpretation(friend); |
325 | var queryEngine = model.getAdapter(ModelQuery.ADAPTER); | 253 | var queryEngine = model.getAdapter(ModelQueryAdapter.class); |
326 | var predicateResultSet = queryEngine.getResultSet(predicate); | 254 | var predicateResultSet = queryEngine.getResultSet(predicate); |
327 | 255 | ||
328 | personInterpretation.put(Tuple.of(0), true); | 256 | personInterpretation.put(Tuple.of(0), true); |
@@ -333,49 +261,37 @@ class QueryTest { | |||
333 | friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE); | 261 | friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE); |
334 | 262 | ||
335 | queryEngine.flushChanges(); | 263 | queryEngine.flushChanges(); |
336 | assertEquals(2, predicateResultSet.countResults()); | 264 | assertResults(Map.of( |
337 | compareMatchSets(predicateResultSet.allResults(), Set.of(Tuple.of(0, 1, 2), Tuple.of(1, 0, 2))); | 265 | Tuple.of(0, 1, 2), true, |
266 | Tuple.of(1, 0, 2), true, | ||
267 | Tuple.of(0, 0, 2), false | ||
268 | ), predicateResultSet); | ||
338 | } | 269 | } |
339 | 270 | ||
340 | @Test | 271 | @QueryEngineTest |
341 | void patternCallTest() { | 272 | void patternCallTest(QueryEvaluationHint hint) { |
342 | var person = new Symbol<>("Person", 1, Boolean.class, false); | 273 | var friendPredicate = Query.of("Friend", (builder, p1, p2) -> builder.clause( |
343 | var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); | 274 | personView.call(p1), |
344 | var personView = new KeyOnlyRelationView<>(person); | 275 | personView.call(p2), |
345 | var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); | 276 | friendMustView.call(p1, p2) |
346 | 277 | )); | |
347 | var p1 = new Variable("p1"); | 278 | var predicate = Query.of("PositivePatternCall", (builder, p3, p4) -> builder.clause( |
348 | var p2 = new Variable("p2"); | 279 | personView.call(p3), |
349 | var friendPredicate = DNF.builder("RelationConstraint") | 280 | personView.call(p4), |
350 | .parameters(p1, p2) | 281 | friendPredicate.call(p3, p4) |
351 | .clause( | 282 | )); |
352 | new RelationViewAtom(personView, p1), | ||
353 | new RelationViewAtom(personView, p2), | ||
354 | new RelationViewAtom(friendMustView, p1, p2) | ||
355 | ) | ||
356 | .build(); | ||
357 | |||
358 | var p3 = new Variable("p3"); | ||
359 | var p4 = new Variable("p4"); | ||
360 | var predicate = DNF.builder("PositivePatternCall") | ||
361 | .parameters(p3, p4) | ||
362 | .clause( | ||
363 | new RelationViewAtom(personView, p3), | ||
364 | new RelationViewAtom(personView, p4), | ||
365 | new DNFCallAtom(friendPredicate, p3, p4) | ||
366 | ) | ||
367 | .build(); | ||
368 | 283 | ||
369 | var store = ModelStore.builder() | 284 | var store = ModelStore.builder() |
370 | .symbols(person, friend) | 285 | .symbols(person, friend) |
371 | .with(ViatraModelQuery.ADAPTER) | 286 | .with(ViatraModelQueryAdapter.builder() |
372 | .queries(predicate) | 287 | .defaultHint(hint) |
288 | .queries(predicate)) | ||
373 | .build(); | 289 | .build(); |
374 | 290 | ||
375 | var model = store.createEmptyModel(); | 291 | var model = store.createEmptyModel(); |
376 | var personInterpretation = model.getInterpretation(person); | 292 | var personInterpretation = model.getInterpretation(person); |
377 | var friendInterpretation = model.getInterpretation(friend); | 293 | var friendInterpretation = model.getInterpretation(friend); |
378 | var queryEngine = model.getAdapter(ModelQuery.ADAPTER); | 294 | var queryEngine = model.getAdapter(ModelQueryAdapter.class); |
379 | var predicateResultSet = queryEngine.getResultSet(predicate); | 295 | var predicateResultSet = queryEngine.getResultSet(predicate); |
380 | 296 | ||
381 | personInterpretation.put(Tuple.of(0), true); | 297 | personInterpretation.put(Tuple.of(0), true); |
@@ -387,37 +303,33 @@ class QueryTest { | |||
387 | friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE); | 303 | friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE); |
388 | 304 | ||
389 | queryEngine.flushChanges(); | 305 | queryEngine.flushChanges(); |
390 | assertEquals(3, predicateResultSet.countResults()); | 306 | assertResults(Map.of( |
307 | Tuple.of(0, 1), true, | ||
308 | Tuple.of(1, 0), true, | ||
309 | Tuple.of(1, 2), true, | ||
310 | Tuple.of(2, 1), false | ||
311 | ), predicateResultSet); | ||
391 | } | 312 | } |
392 | 313 | ||
393 | @Test | 314 | @QueryEngineTest |
394 | void negativeRelationViewTest() { | 315 | void negativeRelationViewTest(QueryEvaluationHint hint) { |
395 | var person = new Symbol<>("Person", 1, Boolean.class, false); | 316 | var predicate = Query.of("NegativePatternCall", (builder, p1, p2) -> builder.clause( |
396 | var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); | 317 | personView.call(p1), |
397 | var personView = new KeyOnlyRelationView<>(person); | 318 | personView.call(p2), |
398 | var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); | 319 | not(friendMustView.call(p1, p2)) |
399 | 320 | )); | |
400 | var p1 = new Variable("p1"); | ||
401 | var p2 = new Variable("p2"); | ||
402 | var predicate = DNF.builder("NegativePatternCall") | ||
403 | .parameters(p1, p2) | ||
404 | .clause( | ||
405 | new RelationViewAtom(personView, p1), | ||
406 | new RelationViewAtom(personView, p2), | ||
407 | new RelationViewAtom(false, friendMustView, p1, p2) | ||
408 | ) | ||
409 | .build(); | ||
410 | 321 | ||
411 | var store = ModelStore.builder() | 322 | var store = ModelStore.builder() |
412 | .symbols(person, friend) | 323 | .symbols(person, friend) |
413 | .with(ViatraModelQuery.ADAPTER) | 324 | .with(ViatraModelQueryAdapter.builder() |
414 | .queries(predicate) | 325 | .defaultHint(hint) |
326 | .queries(predicate)) | ||
415 | .build(); | 327 | .build(); |
416 | 328 | ||
417 | var model = store.createEmptyModel(); | 329 | var model = store.createEmptyModel(); |
418 | var personInterpretation = model.getInterpretation(person); | 330 | var personInterpretation = model.getInterpretation(person); |
419 | var friendInterpretation = model.getInterpretation(friend); | 331 | var friendInterpretation = model.getInterpretation(friend); |
420 | var queryEngine = model.getAdapter(ModelQuery.ADAPTER); | 332 | var queryEngine = model.getAdapter(ModelQueryAdapter.class); |
421 | var predicateResultSet = queryEngine.getResultSet(predicate); | 333 | var predicateResultSet = queryEngine.getResultSet(predicate); |
422 | 334 | ||
423 | personInterpretation.put(Tuple.of(0), true); | 335 | personInterpretation.put(Tuple.of(0), true); |
@@ -429,48 +341,44 @@ class QueryTest { | |||
429 | friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE); | 341 | friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE); |
430 | 342 | ||
431 | queryEngine.flushChanges(); | 343 | queryEngine.flushChanges(); |
432 | assertEquals(6, predicateResultSet.countResults()); | 344 | assertResults(Map.of( |
345 | Tuple.of(0, 0), true, | ||
346 | Tuple.of(0, 2), true, | ||
347 | Tuple.of(1, 1), true, | ||
348 | Tuple.of(2, 0), true, | ||
349 | Tuple.of(2, 1), true, | ||
350 | Tuple.of(2, 2), true, | ||
351 | Tuple.of(0, 1), false, | ||
352 | Tuple.of(1, 0), false, | ||
353 | Tuple.of(1, 2), false, | ||
354 | Tuple.of(0, 3), false | ||
355 | ), predicateResultSet); | ||
433 | } | 356 | } |
434 | 357 | ||
435 | @Test | 358 | @QueryEngineTest |
436 | void negativePatternCallTest() { | 359 | void negativePatternCallTest(QueryEvaluationHint hint) { |
437 | var person = new Symbol<>("Person", 1, Boolean.class, false); | 360 | var friendPredicate = Query.of("Friend", (builder, p1, p2) -> builder.clause( |
438 | var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); | 361 | personView.call(p1), |
439 | var personView = new KeyOnlyRelationView<>(person); | 362 | personView.call(p2), |
440 | var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); | 363 | friendMustView.call(p1, p2) |
441 | 364 | )); | |
442 | var p1 = new Variable("p1"); | 365 | var predicate = Query.of("NegativePatternCall", (builder, p3, p4) -> builder.clause( |
443 | var p2 = new Variable("p2"); | 366 | personView.call(p3), |
444 | var friendPredicate = DNF.builder("RelationConstraint") | 367 | personView.call(p4), |
445 | .parameters(p1, p2) | 368 | not(friendPredicate.call(p3, p4)) |
446 | .clause( | 369 | )); |
447 | new RelationViewAtom(personView, p1), | ||
448 | new RelationViewAtom(personView, p2), | ||
449 | new RelationViewAtom(friendMustView, p1, p2) | ||
450 | ) | ||
451 | .build(); | ||
452 | |||
453 | var p3 = new Variable("p3"); | ||
454 | var p4 = new Variable("p4"); | ||
455 | var predicate = DNF.builder("NegativePatternCall") | ||
456 | .parameters(p3, p4) | ||
457 | .clause( | ||
458 | new RelationViewAtom(personView, p3), | ||
459 | new RelationViewAtom(personView, p4), | ||
460 | new DNFCallAtom(false, friendPredicate, p3, p4) | ||
461 | ) | ||
462 | .build(); | ||
463 | 370 | ||
464 | var store = ModelStore.builder() | 371 | var store = ModelStore.builder() |
465 | .symbols(person, friend) | 372 | .symbols(person, friend) |
466 | .with(ViatraModelQuery.ADAPTER) | 373 | .with(ViatraModelQueryAdapter.builder() |
467 | .queries(predicate) | 374 | .defaultHint(hint) |
375 | .queries(predicate)) | ||
468 | .build(); | 376 | .build(); |
469 | 377 | ||
470 | var model = store.createEmptyModel(); | 378 | var model = store.createEmptyModel(); |
471 | var personInterpretation = model.getInterpretation(person); | 379 | var personInterpretation = model.getInterpretation(person); |
472 | var friendInterpretation = model.getInterpretation(friend); | 380 | var friendInterpretation = model.getInterpretation(friend); |
473 | var queryEngine = model.getAdapter(ModelQuery.ADAPTER); | 381 | var queryEngine = model.getAdapter(ModelQueryAdapter.class); |
474 | var predicateResultSet = queryEngine.getResultSet(predicate); | 382 | var predicateResultSet = queryEngine.getResultSet(predicate); |
475 | 383 | ||
476 | personInterpretation.put(Tuple.of(0), true); | 384 | personInterpretation.put(Tuple.of(0), true); |
@@ -482,37 +390,38 @@ class QueryTest { | |||
482 | friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE); | 390 | friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE); |
483 | 391 | ||
484 | queryEngine.flushChanges(); | 392 | queryEngine.flushChanges(); |
485 | assertEquals(6, predicateResultSet.countResults()); | 393 | assertResults(Map.of( |
394 | Tuple.of(0, 0), true, | ||
395 | Tuple.of(0, 2), true, | ||
396 | Tuple.of(1, 1), true, | ||
397 | Tuple.of(2, 0), true, | ||
398 | Tuple.of(2, 1), true, | ||
399 | Tuple.of(2, 2), true, | ||
400 | Tuple.of(0, 1), false, | ||
401 | Tuple.of(1, 0), false, | ||
402 | Tuple.of(1, 2), false, | ||
403 | Tuple.of(0, 3), false | ||
404 | ), predicateResultSet); | ||
486 | } | 405 | } |
487 | 406 | ||
488 | @Test | 407 | @QueryEngineTest |
489 | void negativeRelationViewWithQuantificationTest() { | 408 | void negativeRelationViewWithQuantificationTest(QueryEvaluationHint hint) { |
490 | var person = new Symbol<>("Person", 1, Boolean.class, false); | 409 | var predicate = Query.of("Negative", (builder, p1) -> builder.clause( |
491 | var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); | 410 | personView.call(p1), |
492 | var personView = new KeyOnlyRelationView<>(person); | 411 | not(friendMustView.call(p1, Variable.of())) |
493 | var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); | 412 | )); |
494 | |||
495 | var p1 = new Variable("p1"); | ||
496 | var p2 = new Variable("p2"); | ||
497 | |||
498 | var predicate = DNF.builder("Count") | ||
499 | .parameters(p1) | ||
500 | .clause( | ||
501 | new RelationViewAtom(personView, p1), | ||
502 | new RelationViewAtom(false, friendMustView, p1, p2) | ||
503 | ) | ||
504 | .build(); | ||
505 | 413 | ||
506 | var store = ModelStore.builder() | 414 | var store = ModelStore.builder() |
507 | .symbols(person, friend) | 415 | .symbols(person, friend) |
508 | .with(ViatraModelQuery.ADAPTER) | 416 | .with(ViatraModelQueryAdapter.builder() |
509 | .queries(predicate) | 417 | .defaultHint(hint) |
418 | .queries(predicate)) | ||
510 | .build(); | 419 | .build(); |
511 | 420 | ||
512 | var model = store.createEmptyModel(); | 421 | var model = store.createEmptyModel(); |
513 | var personInterpretation = model.getInterpretation(person); | 422 | var personInterpretation = model.getInterpretation(person); |
514 | var friendInterpretation = model.getInterpretation(friend); | 423 | var friendInterpretation = model.getInterpretation(friend); |
515 | var queryEngine = model.getAdapter(ModelQuery.ADAPTER); | 424 | var queryEngine = model.getAdapter(ModelQueryAdapter.class); |
516 | var predicateResultSet = queryEngine.getResultSet(predicate); | 425 | var predicateResultSet = queryEngine.getResultSet(predicate); |
517 | 426 | ||
518 | personInterpretation.put(Tuple.of(0), true); | 427 | personInterpretation.put(Tuple.of(0), true); |
@@ -523,46 +432,37 @@ class QueryTest { | |||
523 | friendInterpretation.put(Tuple.of(0, 2), TruthValue.TRUE); | 432 | friendInterpretation.put(Tuple.of(0, 2), TruthValue.TRUE); |
524 | 433 | ||
525 | queryEngine.flushChanges(); | 434 | queryEngine.flushChanges(); |
526 | assertEquals(2, predicateResultSet.countResults()); | 435 | assertResults(Map.of( |
436 | Tuple.of(0), false, | ||
437 | Tuple.of(1), true, | ||
438 | Tuple.of(2), true, | ||
439 | Tuple.of(3), false | ||
440 | ), predicateResultSet); | ||
527 | } | 441 | } |
528 | 442 | ||
529 | @Test | 443 | @QueryEngineTest |
530 | void negativeWithQuantificationTest() { | 444 | void negativeWithQuantificationTest(QueryEvaluationHint hint) { |
531 | var person = new Symbol<>("Person", 1, Boolean.class, false); | 445 | var called = Query.of("Called", (builder, p1, p2) -> builder.clause( |
532 | var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); | 446 | personView.call(p1), |
533 | var personView = new KeyOnlyRelationView<>(person); | 447 | personView.call(p2), |
534 | var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); | 448 | friendMustView.call(p1, p2) |
535 | 449 | )); | |
536 | var p1 = new Variable("p1"); | 450 | var predicate = Query.of("Negative", (builder, p1) -> builder.clause( |
537 | var p2 = new Variable("p2"); | 451 | personView.call(p1), |
538 | 452 | not(called.call(p1, Variable.of())) | |
539 | var called = DNF.builder("Called") | 453 | )); |
540 | .parameters(p1, p2) | ||
541 | .clause( | ||
542 | new RelationViewAtom(personView, p1), | ||
543 | new RelationViewAtom(personView, p2), | ||
544 | new RelationViewAtom(friendMustView, p1, p2) | ||
545 | ) | ||
546 | .build(); | ||
547 | |||
548 | var predicate = DNF.builder("Count") | ||
549 | .parameters(p1) | ||
550 | .clause( | ||
551 | new RelationViewAtom(personView, p1), | ||
552 | new DNFCallAtom(false, called, p1, p2) | ||
553 | ) | ||
554 | .build(); | ||
555 | 454 | ||
556 | var store = ModelStore.builder() | 455 | var store = ModelStore.builder() |
557 | .symbols(person, friend) | 456 | .symbols(person, friend) |
558 | .with(ViatraModelQuery.ADAPTER) | 457 | .with(ViatraModelQueryAdapter.builder() |
559 | .queries(predicate) | 458 | .defaultHint(hint) |
459 | .queries(predicate)) | ||
560 | .build(); | 460 | .build(); |
561 | 461 | ||
562 | var model = store.createEmptyModel(); | 462 | var model = store.createEmptyModel(); |
563 | var personInterpretation = model.getInterpretation(person); | 463 | var personInterpretation = model.getInterpretation(person); |
564 | var friendInterpretation = model.getInterpretation(friend); | 464 | var friendInterpretation = model.getInterpretation(friend); |
565 | var queryEngine = model.getAdapter(ModelQuery.ADAPTER); | 465 | var queryEngine = model.getAdapter(ModelQueryAdapter.class); |
566 | var predicateResultSet = queryEngine.getResultSet(predicate); | 466 | var predicateResultSet = queryEngine.getResultSet(predicate); |
567 | 467 | ||
568 | personInterpretation.put(Tuple.of(0), true); | 468 | personInterpretation.put(Tuple.of(0), true); |
@@ -573,37 +473,33 @@ class QueryTest { | |||
573 | friendInterpretation.put(Tuple.of(0, 2), TruthValue.TRUE); | 473 | friendInterpretation.put(Tuple.of(0, 2), TruthValue.TRUE); |
574 | 474 | ||
575 | queryEngine.flushChanges(); | 475 | queryEngine.flushChanges(); |
576 | assertEquals(2, predicateResultSet.countResults()); | 476 | assertResults(Map.of( |
477 | Tuple.of(0), false, | ||
478 | Tuple.of(1), true, | ||
479 | Tuple.of(2), true, | ||
480 | Tuple.of(3), false | ||
481 | ), predicateResultSet); | ||
577 | } | 482 | } |
578 | 483 | ||
579 | @Test | 484 | @QueryEngineTest |
580 | void transitiveRelationViewTest() { | 485 | void transitiveRelationViewTest(QueryEvaluationHint hint) { |
581 | var person = new Symbol<>("Person", 1, Boolean.class, false); | 486 | var predicate = Query.of("Transitive", (builder, p1, p2) -> builder.clause( |
582 | var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); | 487 | personView.call(p1), |
583 | var personView = new KeyOnlyRelationView<>(person); | 488 | personView.call(p2), |
584 | var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); | 489 | friendMustView.callTransitive(p1, p2) |
585 | 490 | )); | |
586 | var p1 = new Variable("p1"); | ||
587 | var p2 = new Variable("p2"); | ||
588 | var predicate = DNF.builder("TransitivePatternCall") | ||
589 | .parameters(p1, p2) | ||
590 | .clause( | ||
591 | new RelationViewAtom(personView, p1), | ||
592 | new RelationViewAtom(personView, p2), | ||
593 | new RelationViewAtom(CallPolarity.TRANSITIVE, friendMustView, p1, p2) | ||
594 | ) | ||
595 | .build(); | ||
596 | 491 | ||
597 | var store = ModelStore.builder() | 492 | var store = ModelStore.builder() |
598 | .symbols(person, friend) | 493 | .symbols(person, friend) |
599 | .with(ViatraModelQuery.ADAPTER) | 494 | .with(ViatraModelQueryAdapter.builder() |
600 | .queries(predicate) | 495 | .defaultHint(hint) |
496 | .queries(predicate)) | ||
601 | .build(); | 497 | .build(); |
602 | 498 | ||
603 | var model = store.createEmptyModel(); | 499 | var model = store.createEmptyModel(); |
604 | var personInterpretation = model.getInterpretation(person); | 500 | var personInterpretation = model.getInterpretation(person); |
605 | var friendInterpretation = model.getInterpretation(friend); | 501 | var friendInterpretation = model.getInterpretation(friend); |
606 | var queryEngine = model.getAdapter(ModelQuery.ADAPTER); | 502 | var queryEngine = model.getAdapter(ModelQueryAdapter.class); |
607 | var predicateResultSet = queryEngine.getResultSet(predicate); | 503 | var predicateResultSet = queryEngine.getResultSet(predicate); |
608 | 504 | ||
609 | personInterpretation.put(Tuple.of(0), true); | 505 | personInterpretation.put(Tuple.of(0), true); |
@@ -614,48 +510,44 @@ class QueryTest { | |||
614 | friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE); | 510 | friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE); |
615 | 511 | ||
616 | queryEngine.flushChanges(); | 512 | queryEngine.flushChanges(); |
617 | assertEquals(3, predicateResultSet.countResults()); | 513 | assertResults(Map.of( |
514 | Tuple.of(0, 0), false, | ||
515 | Tuple.of(0, 1), true, | ||
516 | Tuple.of(0, 2), true, | ||
517 | Tuple.of(1, 0), false, | ||
518 | Tuple.of(1, 1), false, | ||
519 | Tuple.of(1, 2), true, | ||
520 | Tuple.of(2, 0), false, | ||
521 | Tuple.of(2, 1), false, | ||
522 | Tuple.of(2, 2), false, | ||
523 | Tuple.of(2, 3), false | ||
524 | ), predicateResultSet); | ||
618 | } | 525 | } |
619 | 526 | ||
620 | @Test | 527 | @QueryEngineTest |
621 | void transitivePatternCallTest() { | 528 | void transitivePatternCallTest(QueryEvaluationHint hint) { |
622 | var person = new Symbol<>("Person", 1, Boolean.class, false); | 529 | var called = Query.of("Called", (builder, p1, p2) -> builder.clause( |
623 | var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); | 530 | personView.call(p1), |
624 | var personView = new KeyOnlyRelationView<>(person); | 531 | personView.call(p2), |
625 | var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); | 532 | friendMustView.call(p1, p2) |
626 | 533 | )); | |
627 | var p1 = new Variable("p1"); | 534 | var predicate = Query.of("Transitive", (builder, p1, p2) -> builder.clause( |
628 | var p2 = new Variable("p2"); | 535 | personView.call(p1), |
629 | var friendPredicate = DNF.builder("RelationConstraint") | 536 | personView.call(p2), |
630 | .parameters(p1, p2) | 537 | called.callTransitive(p1, p2) |
631 | .clause( | 538 | )); |
632 | new RelationViewAtom(personView, p1), | ||
633 | new RelationViewAtom(personView, p2), | ||
634 | new RelationViewAtom(friendMustView, p1, p2) | ||
635 | ) | ||
636 | .build(); | ||
637 | |||
638 | var p3 = new Variable("p3"); | ||
639 | var p4 = new Variable("p4"); | ||
640 | var predicate = DNF.builder("TransitivePatternCall") | ||
641 | .parameters(p3, p4) | ||
642 | .clause( | ||
643 | new RelationViewAtom(personView, p3), | ||
644 | new RelationViewAtom(personView, p4), | ||
645 | new DNFCallAtom(CallPolarity.TRANSITIVE, friendPredicate, p3, p4) | ||
646 | ) | ||
647 | .build(); | ||
648 | 539 | ||
649 | var store = ModelStore.builder() | 540 | var store = ModelStore.builder() |
650 | .symbols(person, friend) | 541 | .symbols(person, friend) |
651 | .with(ViatraModelQuery.ADAPTER) | 542 | .with(ViatraModelQueryAdapter.builder() |
652 | .queries(predicate) | 543 | .defaultHint(hint) |
544 | .queries(predicate)) | ||
653 | .build(); | 545 | .build(); |
654 | 546 | ||
655 | var model = store.createEmptyModel(); | 547 | var model = store.createEmptyModel(); |
656 | var personInterpretation = model.getInterpretation(person); | 548 | var personInterpretation = model.getInterpretation(person); |
657 | var friendInterpretation = model.getInterpretation(friend); | 549 | var friendInterpretation = model.getInterpretation(friend); |
658 | var queryEngine = model.getAdapter(ModelQuery.ADAPTER); | 550 | var queryEngine = model.getAdapter(ModelQueryAdapter.class); |
659 | var predicateResultSet = queryEngine.getResultSet(predicate); | 551 | var predicateResultSet = queryEngine.getResultSet(predicate); |
660 | 552 | ||
661 | personInterpretation.put(Tuple.of(0), true); | 553 | personInterpretation.put(Tuple.of(0), true); |
@@ -666,16 +558,150 @@ class QueryTest { | |||
666 | friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE); | 558 | friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE); |
667 | 559 | ||
668 | queryEngine.flushChanges(); | 560 | queryEngine.flushChanges(); |
669 | assertEquals(3, predicateResultSet.countResults()); | 561 | assertResults(Map.of( |
562 | Tuple.of(0, 0), false, | ||
563 | Tuple.of(0, 1), true, | ||
564 | Tuple.of(0, 2), true, | ||
565 | Tuple.of(1, 0), false, | ||
566 | Tuple.of(1, 1), false, | ||
567 | Tuple.of(1, 2), true, | ||
568 | Tuple.of(2, 0), false, | ||
569 | Tuple.of(2, 1), false, | ||
570 | Tuple.of(2, 2), false, | ||
571 | Tuple.of(2, 3), false | ||
572 | ), predicateResultSet); | ||
573 | } | ||
574 | |||
575 | @Test | ||
576 | void filteredIntegerViewTest() { | ||
577 | var distance = Symbol.of("distance", 2, Integer.class); | ||
578 | var nearView = new FilteredView<>(distance, value -> value < 2); | ||
579 | var farView = new FilteredView<>(distance, value -> value >= 5); | ||
580 | var dangerQuery = Query.of("danger", (builder, a1, a2) -> builder.clause((a3) -> List.of( | ||
581 | a1.notEquivalent(a2), | ||
582 | nearView.call(a1, a3), | ||
583 | nearView.call(a2, a3), | ||
584 | not(farView.call(a1, a2)) | ||
585 | ))); | ||
586 | var store = ModelStore.builder() | ||
587 | .symbols(distance) | ||
588 | .with(ViatraModelQueryAdapter.builder() | ||
589 | .queries(dangerQuery)) | ||
590 | .build(); | ||
591 | |||
592 | var model = store.createEmptyModel(); | ||
593 | var distanceInterpretation = model.getInterpretation(distance); | ||
594 | distanceInterpretation.put(Tuple.of(0, 1), 1); | ||
595 | distanceInterpretation.put(Tuple.of(1, 0), 1); | ||
596 | distanceInterpretation.put(Tuple.of(0, 2), 1); | ||
597 | distanceInterpretation.put(Tuple.of(2, 0), 1); | ||
598 | distanceInterpretation.put(Tuple.of(1, 2), 3); | ||
599 | distanceInterpretation.put(Tuple.of(2, 1), 3); | ||
600 | var queryEngine = model.getAdapter(ModelQueryAdapter.class); | ||
601 | var dangerResultSet = queryEngine.getResultSet(dangerQuery); | ||
602 | queryEngine.flushChanges(); | ||
603 | assertResults(Map.of( | ||
604 | Tuple.of(0, 1), false, | ||
605 | Tuple.of(0, 2), false, | ||
606 | Tuple.of(1, 2), true, | ||
607 | Tuple.of(2, 1), true | ||
608 | ), dangerResultSet); | ||
609 | } | ||
610 | |||
611 | @Test | ||
612 | void filteredDoubleViewTest() { | ||
613 | var distance = Symbol.of("distance", 2, Double.class); | ||
614 | var nearView = new FilteredView<>(distance, value -> value < 2); | ||
615 | var farView = new FilteredView<>(distance, value -> value >= 5); | ||
616 | var dangerQuery = Query.of("danger", (builder, a1, a2) -> builder.clause((a3) -> List.of( | ||
617 | a1.notEquivalent(a2), | ||
618 | nearView.call(a1, a3), | ||
619 | nearView.call(a2, a3), | ||
620 | not(farView.call(a1, a2)) | ||
621 | ))); | ||
622 | var store = ModelStore.builder() | ||
623 | .symbols(distance) | ||
624 | .with(ViatraModelQueryAdapter.builder() | ||
625 | .queries(dangerQuery)) | ||
626 | .build(); | ||
627 | |||
628 | var model = store.createEmptyModel(); | ||
629 | var distanceInterpretation = model.getInterpretation(distance); | ||
630 | distanceInterpretation.put(Tuple.of(0, 1), 1.0); | ||
631 | distanceInterpretation.put(Tuple.of(1, 0), 1.0); | ||
632 | distanceInterpretation.put(Tuple.of(0, 2), 1.0); | ||
633 | distanceInterpretation.put(Tuple.of(2, 0), 1.0); | ||
634 | distanceInterpretation.put(Tuple.of(1, 2), 3.0); | ||
635 | distanceInterpretation.put(Tuple.of(2, 1), 3.0); | ||
636 | var queryEngine = model.getAdapter(ModelQueryAdapter.class); | ||
637 | var dangerResultSet = queryEngine.getResultSet(dangerQuery); | ||
638 | queryEngine.flushChanges(); | ||
639 | assertResults(Map.of( | ||
640 | Tuple.of(0, 1), false, | ||
641 | Tuple.of(0, 2), false, | ||
642 | Tuple.of(1, 2), true, | ||
643 | Tuple.of(2, 1), true | ||
644 | ), dangerResultSet); | ||
645 | } | ||
646 | |||
647 | @QueryEngineTest | ||
648 | void assumeTest(QueryEvaluationHint hint) { | ||
649 | var age = Symbol.of("age", 1, Integer.class); | ||
650 | var ageView = new FunctionView<>(age); | ||
651 | |||
652 | var query = Query.of("Constraint", (builder, p1) -> builder.clause(Integer.class, (x) -> List.of( | ||
653 | personView.call(p1), | ||
654 | ageView.call(p1, x), | ||
655 | assume(greaterEq(x, constant(18))) | ||
656 | ))); | ||
657 | |||
658 | var store = ModelStore.builder() | ||
659 | .symbols(person, age) | ||
660 | .with(ViatraModelQueryAdapter.builder() | ||
661 | .defaultHint(hint) | ||
662 | .queries(query)) | ||
663 | .build(); | ||
664 | |||
665 | var model = store.createEmptyModel(); | ||
666 | var personInterpretation = model.getInterpretation(person); | ||
667 | var ageInterpretation = model.getInterpretation(age); | ||
668 | var queryEngine = model.getAdapter(ModelQueryAdapter.class); | ||
669 | var queryResultSet = queryEngine.getResultSet(query); | ||
670 | |||
671 | personInterpretation.put(Tuple.of(0), true); | ||
672 | personInterpretation.put(Tuple.of(1), true); | ||
673 | |||
674 | ageInterpretation.put(Tuple.of(0), 12); | ||
675 | ageInterpretation.put(Tuple.of(1), 24); | ||
676 | |||
677 | queryEngine.flushChanges(); | ||
678 | assertResults(Map.of( | ||
679 | Tuple.of(0), false, | ||
680 | Tuple.of(1), true, | ||
681 | Tuple.of(2), false | ||
682 | ), queryResultSet); | ||
670 | } | 683 | } |
671 | 684 | ||
672 | static void compareMatchSets(Stream<TupleLike> matchSet, Set<Tuple> expected) { | 685 | @Test |
673 | Set<Tuple> translatedMatchSet = new HashSet<>(); | 686 | void alwaysFalseTest() { |
674 | var iterator = matchSet.iterator(); | 687 | var predicate = Query.of("AlwaysFalse", builder -> builder.parameter("p1")); |
675 | while (iterator.hasNext()) { | 688 | |
676 | var element = iterator.next(); | 689 | var store = ModelStore.builder() |
677 | translatedMatchSet.add(element.toTuple()); | 690 | .symbols(person) |
678 | } | 691 | .with(ViatraModelQueryAdapter.builder() |
679 | assertEquals(expected, translatedMatchSet); | 692 | .queries(predicate)) |
693 | .build(); | ||
694 | |||
695 | var model = store.createEmptyModel(); | ||
696 | var personInterpretation = model.getInterpretation(person); | ||
697 | var queryEngine = model.getAdapter(ModelQueryAdapter.class); | ||
698 | var predicateResultSet = queryEngine.getResultSet(predicate); | ||
699 | |||
700 | personInterpretation.put(Tuple.of(0), true); | ||
701 | personInterpretation.put(Tuple.of(1), true); | ||
702 | personInterpretation.put(Tuple.of(2), true); | ||
703 | |||
704 | queryEngine.flushChanges(); | ||
705 | assertResults(Map.of(), predicateResultSet); | ||
680 | } | 706 | } |
681 | } | 707 | } |
diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTransactionTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTransactionTest.java index 98995339..66f043c6 100644 --- a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTransactionTest.java +++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTransactionTest.java | |||
@@ -1,43 +1,163 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
1 | package tools.refinery.store.query.viatra; | 6 | package tools.refinery.store.query.viatra; |
2 | 7 | ||
8 | import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint; | ||
9 | import org.junit.jupiter.api.Disabled; | ||
3 | import org.junit.jupiter.api.Test; | 10 | import org.junit.jupiter.api.Test; |
4 | import tools.refinery.store.model.ModelStore; | 11 | import tools.refinery.store.model.ModelStore; |
5 | import tools.refinery.store.query.DNF; | 12 | import tools.refinery.store.query.ModelQueryAdapter; |
6 | import tools.refinery.store.query.ModelQuery; | 13 | import tools.refinery.store.query.dnf.Query; |
7 | import tools.refinery.store.query.Variable; | 14 | import tools.refinery.store.query.dnf.RelationalQuery; |
8 | import tools.refinery.store.query.atom.RelationViewAtom; | 15 | import tools.refinery.store.query.view.AnySymbolView; |
9 | import tools.refinery.store.query.view.KeyOnlyRelationView; | 16 | import tools.refinery.store.query.view.FilteredView; |
17 | import tools.refinery.store.query.view.FunctionView; | ||
18 | import tools.refinery.store.query.view.KeyOnlyView; | ||
10 | import tools.refinery.store.representation.Symbol; | 19 | import tools.refinery.store.representation.Symbol; |
11 | import tools.refinery.store.tuple.Tuple; | 20 | import tools.refinery.store.tuple.Tuple; |
12 | 21 | ||
13 | import static org.junit.jupiter.api.Assertions.*; | 22 | import java.util.Map; |
23 | import java.util.Optional; | ||
24 | |||
25 | import static org.junit.jupiter.api.Assertions.assertFalse; | ||
26 | import static org.junit.jupiter.api.Assertions.assertTrue; | ||
27 | import static tools.refinery.store.query.viatra.tests.QueryAssertions.assertNullableResults; | ||
28 | import static tools.refinery.store.query.viatra.tests.QueryAssertions.assertResults; | ||
14 | 29 | ||
15 | class QueryTransactionTest { | 30 | class QueryTransactionTest { |
31 | private static final Symbol<Boolean> person = Symbol.of("Person", 1); | ||
32 | private static final Symbol<Integer> age = Symbol.of("age", 1, Integer.class); | ||
33 | private static final AnySymbolView personView = new KeyOnlyView<>(person); | ||
34 | private static final AnySymbolView ageView = new FunctionView<>(age); | ||
35 | private static final RelationalQuery predicate = Query.of("TypeConstraint", (builder, p1) -> | ||
36 | builder.clause(personView.call(p1))); | ||
37 | |||
16 | @Test | 38 | @Test |
17 | void flushTest() { | 39 | void flushTest() { |
18 | var person = new Symbol<>("Person", 1, Boolean.class, false); | 40 | var store = ModelStore.builder() |
19 | var asset = new Symbol<>("Asset", 1, Boolean.class, false); | 41 | .symbols(person) |
20 | var personView = new KeyOnlyRelationView<>(person); | 42 | .with(ViatraModelQueryAdapter.builder() |
21 | 43 | .queries(predicate)) | |
22 | var p1 = new Variable("p1"); | ||
23 | var predicate = DNF.builder("TypeConstraint") | ||
24 | .parameters(p1) | ||
25 | .clause(new RelationViewAtom(personView, p1)) | ||
26 | .build(); | 44 | .build(); |
27 | 45 | ||
46 | var model = store.createEmptyModel(); | ||
47 | var personInterpretation = model.getInterpretation(person); | ||
48 | var queryEngine = model.getAdapter(ModelQueryAdapter.class); | ||
49 | var predicateResultSet = queryEngine.getResultSet(predicate); | ||
50 | |||
51 | assertResults(Map.of( | ||
52 | Tuple.of(0), false, | ||
53 | Tuple.of(1), false, | ||
54 | Tuple.of(2), false, | ||
55 | Tuple.of(3), false | ||
56 | ), predicateResultSet); | ||
57 | assertFalse(queryEngine.hasPendingChanges()); | ||
58 | |||
59 | personInterpretation.put(Tuple.of(0), true); | ||
60 | personInterpretation.put(Tuple.of(1), true); | ||
61 | |||
62 | assertResults(Map.of( | ||
63 | Tuple.of(0), false, | ||
64 | Tuple.of(1), false, | ||
65 | Tuple.of(2), false, | ||
66 | Tuple.of(3), false | ||
67 | ), predicateResultSet); | ||
68 | assertTrue(queryEngine.hasPendingChanges()); | ||
69 | |||
70 | queryEngine.flushChanges(); | ||
71 | assertResults(Map.of( | ||
72 | Tuple.of(0), true, | ||
73 | Tuple.of(1), true, | ||
74 | Tuple.of(2), false, | ||
75 | Tuple.of(3), false | ||
76 | ), predicateResultSet); | ||
77 | assertFalse(queryEngine.hasPendingChanges()); | ||
78 | |||
79 | personInterpretation.put(Tuple.of(1), false); | ||
80 | personInterpretation.put(Tuple.of(2), true); | ||
81 | |||
82 | assertResults(Map.of( | ||
83 | Tuple.of(0), true, | ||
84 | Tuple.of(1), true, | ||
85 | Tuple.of(2), false, | ||
86 | Tuple.of(3), false | ||
87 | ), predicateResultSet); | ||
88 | assertTrue(queryEngine.hasPendingChanges()); | ||
89 | |||
90 | queryEngine.flushChanges(); | ||
91 | assertResults(Map.of( | ||
92 | Tuple.of(0), true, | ||
93 | Tuple.of(1), false, | ||
94 | Tuple.of(2), true, | ||
95 | Tuple.of(3), false | ||
96 | ), predicateResultSet); | ||
97 | assertFalse(queryEngine.hasPendingChanges()); | ||
98 | } | ||
99 | |||
100 | @Test | ||
101 | void localSearchTest() { | ||
102 | var store = ModelStore.builder() | ||
103 | .symbols(person) | ||
104 | .with(ViatraModelQueryAdapter.builder() | ||
105 | .defaultHint(new QueryEvaluationHint(null, QueryEvaluationHint.BackendRequirement.DEFAULT_SEARCH)) | ||
106 | .queries(predicate)) | ||
107 | .build(); | ||
108 | |||
109 | var model = store.createEmptyModel(); | ||
110 | var personInterpretation = model.getInterpretation(person); | ||
111 | var queryEngine = model.getAdapter(ModelQueryAdapter.class); | ||
112 | var predicateResultSet = queryEngine.getResultSet(predicate); | ||
113 | |||
114 | assertResults(Map.of( | ||
115 | Tuple.of(0), false, | ||
116 | Tuple.of(1), false, | ||
117 | Tuple.of(2), false, | ||
118 | Tuple.of(3), false | ||
119 | ), predicateResultSet); | ||
120 | assertFalse(queryEngine.hasPendingChanges()); | ||
121 | |||
122 | personInterpretation.put(Tuple.of(0), true); | ||
123 | personInterpretation.put(Tuple.of(1), true); | ||
124 | |||
125 | assertResults(Map.of( | ||
126 | Tuple.of(0), true, | ||
127 | Tuple.of(1), true, | ||
128 | Tuple.of(2), false, | ||
129 | Tuple.of(3), false | ||
130 | ), predicateResultSet); | ||
131 | assertFalse(queryEngine.hasPendingChanges()); | ||
132 | |||
133 | personInterpretation.put(Tuple.of(1), false); | ||
134 | personInterpretation.put(Tuple.of(2), true); | ||
135 | |||
136 | assertResults(Map.of( | ||
137 | Tuple.of(0), true, | ||
138 | Tuple.of(1), false, | ||
139 | Tuple.of(2), true, | ||
140 | Tuple.of(3), false | ||
141 | ), predicateResultSet); | ||
142 | assertFalse(queryEngine.hasPendingChanges()); | ||
143 | } | ||
144 | |||
145 | @Test | ||
146 | void unrelatedChangesTest() { | ||
147 | var asset = Symbol.of("Asset", 1); | ||
148 | |||
28 | var store = ModelStore.builder() | 149 | var store = ModelStore.builder() |
29 | .symbols(person, asset) | 150 | .symbols(person, asset) |
30 | .with(ViatraModelQuery.ADAPTER) | 151 | .with(ViatraModelQueryAdapter.builder() |
31 | .queries(predicate) | 152 | .queries(predicate)) |
32 | .build(); | 153 | .build(); |
33 | 154 | ||
34 | var model = store.createEmptyModel(); | 155 | var model = store.createEmptyModel(); |
35 | var personInterpretation = model.getInterpretation(person); | 156 | var personInterpretation = model.getInterpretation(person); |
36 | var assetInterpretation = model.getInterpretation(asset); | 157 | var assetInterpretation = model.getInterpretation(asset); |
37 | var queryEngine = model.getAdapter(ModelQuery.ADAPTER); | 158 | var queryEngine = model.getAdapter(ModelQueryAdapter.class); |
38 | var predicateResultSet = queryEngine.getResultSet(predicate); | 159 | var predicateResultSet = queryEngine.getResultSet(predicate); |
39 | 160 | ||
40 | assertEquals(0, predicateResultSet.countResults()); | ||
41 | assertFalse(queryEngine.hasPendingChanges()); | 161 | assertFalse(queryEngine.hasPendingChanges()); |
42 | 162 | ||
43 | personInterpretation.put(Tuple.of(0), true); | 163 | personInterpretation.put(Tuple.of(0), true); |
@@ -46,19 +166,208 @@ class QueryTransactionTest { | |||
46 | assetInterpretation.put(Tuple.of(1), true); | 166 | assetInterpretation.put(Tuple.of(1), true); |
47 | assetInterpretation.put(Tuple.of(2), true); | 167 | assetInterpretation.put(Tuple.of(2), true); |
48 | 168 | ||
49 | assertEquals(0, predicateResultSet.countResults()); | 169 | assertResults(Map.of( |
170 | Tuple.of(0), false, | ||
171 | Tuple.of(1), false, | ||
172 | Tuple.of(2), false, | ||
173 | Tuple.of(3), false, | ||
174 | Tuple.of(4), false | ||
175 | ), predicateResultSet); | ||
50 | assertTrue(queryEngine.hasPendingChanges()); | 176 | assertTrue(queryEngine.hasPendingChanges()); |
51 | 177 | ||
52 | queryEngine.flushChanges(); | 178 | queryEngine.flushChanges(); |
53 | assertEquals(2, predicateResultSet.countResults()); | 179 | assertResults(Map.of( |
180 | Tuple.of(0), true, | ||
181 | Tuple.of(1), true, | ||
182 | Tuple.of(2), false, | ||
183 | Tuple.of(3), false, | ||
184 | Tuple.of(4), false | ||
185 | ), predicateResultSet); | ||
54 | assertFalse(queryEngine.hasPendingChanges()); | 186 | assertFalse(queryEngine.hasPendingChanges()); |
55 | 187 | ||
56 | personInterpretation.put(Tuple.of(4), true); | 188 | assetInterpretation.put(Tuple.of(3), true); |
57 | assertEquals(2, predicateResultSet.countResults()); | 189 | assertFalse(queryEngine.hasPendingChanges()); |
58 | assertTrue(queryEngine.hasPendingChanges()); | 190 | |
191 | assertResults(Map.of( | ||
192 | Tuple.of(0), true, | ||
193 | Tuple.of(1), true, | ||
194 | Tuple.of(2), false, | ||
195 | Tuple.of(3), false, | ||
196 | Tuple.of(4), false | ||
197 | ), predicateResultSet); | ||
198 | |||
199 | queryEngine.flushChanges(); | ||
200 | assertResults(Map.of( | ||
201 | Tuple.of(0), true, | ||
202 | Tuple.of(1), true, | ||
203 | Tuple.of(2), false, | ||
204 | Tuple.of(3), false, | ||
205 | Tuple.of(4), false | ||
206 | ), predicateResultSet); | ||
207 | assertFalse(queryEngine.hasPendingChanges()); | ||
208 | } | ||
209 | |||
210 | @Test | ||
211 | void tupleChangingChangeTest() { | ||
212 | var query = Query.of("TypeConstraint", Integer.class, (builder, p1, output) -> builder.clause( | ||
213 | personView.call(p1), | ||
214 | ageView.call(p1, output) | ||
215 | )); | ||
216 | |||
217 | var store = ModelStore.builder() | ||
218 | .symbols(person, age) | ||
219 | .with(ViatraModelQueryAdapter.builder() | ||
220 | .queries(query)) | ||
221 | .build(); | ||
222 | |||
223 | var model = store.createEmptyModel(); | ||
224 | var personInterpretation = model.getInterpretation(person); | ||
225 | var ageInterpretation = model.getInterpretation(age); | ||
226 | var queryEngine = model.getAdapter(ModelQueryAdapter.class); | ||
227 | var queryResultSet = queryEngine.getResultSet(query); | ||
228 | |||
229 | personInterpretation.put(Tuple.of(0), true); | ||
230 | |||
231 | ageInterpretation.put(Tuple.of(0), 24); | ||
232 | |||
233 | queryEngine.flushChanges(); | ||
234 | assertResults(Map.of(Tuple.of(0), 24), queryResultSet); | ||
235 | |||
236 | ageInterpretation.put(Tuple.of(0), 25); | ||
59 | 237 | ||
60 | queryEngine.flushChanges(); | 238 | queryEngine.flushChanges(); |
61 | assertEquals(3, predicateResultSet.countResults()); | 239 | assertResults(Map.of(Tuple.of(0), 25), queryResultSet); |
240 | |||
241 | ageInterpretation.put(Tuple.of(0), null); | ||
242 | |||
243 | queryEngine.flushChanges(); | ||
244 | assertNullableResults(Map.of(Tuple.of(0), Optional.empty()), queryResultSet); | ||
245 | } | ||
246 | |||
247 | @Test | ||
248 | void tuplePreservingUnchangedTest() { | ||
249 | var adultView = new FilteredView<>(age, "adult", n -> n != null && n >= 18); | ||
250 | |||
251 | var query = Query.of("TypeConstraint", (builder, p1) -> builder.clause( | ||
252 | personView.call(p1), | ||
253 | adultView.call(p1) | ||
254 | )); | ||
255 | |||
256 | var store = ModelStore.builder() | ||
257 | .symbols(person, age) | ||
258 | .with(ViatraModelQueryAdapter.builder() | ||
259 | .queries(query)) | ||
260 | .build(); | ||
261 | |||
262 | var model = store.createEmptyModel(); | ||
263 | var personInterpretation = model.getInterpretation(person); | ||
264 | var ageInterpretation = model.getInterpretation(age); | ||
265 | var queryEngine = model.getAdapter(ModelQueryAdapter.class); | ||
266 | var queryResultSet = queryEngine.getResultSet(query); | ||
267 | |||
268 | personInterpretation.put(Tuple.of(0), true); | ||
269 | |||
270 | ageInterpretation.put(Tuple.of(0), 24); | ||
271 | |||
272 | queryEngine.flushChanges(); | ||
273 | assertResults(Map.of(Tuple.of(0), true), queryResultSet); | ||
274 | |||
275 | ageInterpretation.put(Tuple.of(0), 25); | ||
276 | |||
277 | queryEngine.flushChanges(); | ||
278 | assertResults(Map.of(Tuple.of(0), true), queryResultSet); | ||
279 | |||
280 | ageInterpretation.put(Tuple.of(0), 17); | ||
281 | |||
282 | queryEngine.flushChanges(); | ||
283 | assertResults(Map.of(Tuple.of(0), false), queryResultSet); | ||
284 | } | ||
285 | |||
286 | @Disabled("TODO Fix DiffCursor") | ||
287 | @Test | ||
288 | void commitAfterFlushTest() { | ||
289 | var store = ModelStore.builder() | ||
290 | .symbols(person) | ||
291 | .with(ViatraModelQueryAdapter.builder() | ||
292 | .queries(predicate)) | ||
293 | .build(); | ||
294 | |||
295 | var model = store.createEmptyModel(); | ||
296 | var personInterpretation = model.getInterpretation(person); | ||
297 | var queryEngine = model.getAdapter(ModelQueryAdapter.class); | ||
298 | var predicateResultSet = queryEngine.getResultSet(predicate); | ||
299 | |||
300 | personInterpretation.put(Tuple.of(0), true); | ||
301 | personInterpretation.put(Tuple.of(1), true); | ||
302 | |||
303 | queryEngine.flushChanges(); | ||
304 | assertResults(Map.of( | ||
305 | Tuple.of(0), true, | ||
306 | Tuple.of(1), true, | ||
307 | Tuple.of(2), false, | ||
308 | Tuple.of(3), false | ||
309 | ), predicateResultSet); | ||
310 | |||
311 | var state1 = model.commit(); | ||
312 | |||
313 | personInterpretation.put(Tuple.of(1), false); | ||
314 | personInterpretation.put(Tuple.of(2), true); | ||
315 | |||
316 | queryEngine.flushChanges(); | ||
317 | assertResults(Map.of( | ||
318 | Tuple.of(0), true, | ||
319 | Tuple.of(1), false, | ||
320 | Tuple.of(2), true, | ||
321 | Tuple.of(3), false | ||
322 | ), predicateResultSet); | ||
323 | |||
324 | model.restore(state1); | ||
325 | |||
326 | assertFalse(queryEngine.hasPendingChanges()); | ||
327 | assertResults(Map.of( | ||
328 | Tuple.of(0), true, | ||
329 | Tuple.of(1), true, | ||
330 | Tuple.of(2), false, | ||
331 | Tuple.of(3), false | ||
332 | ), predicateResultSet); | ||
333 | } | ||
334 | |||
335 | @Disabled("TODO Fix DiffCursor") | ||
336 | @Test | ||
337 | void commitWithoutFlushTest() { | ||
338 | var store = ModelStore.builder() | ||
339 | .symbols(person) | ||
340 | .with(ViatraModelQueryAdapter.builder() | ||
341 | .queries(predicate)) | ||
342 | .build(); | ||
343 | |||
344 | var model = store.createEmptyModel(); | ||
345 | var personInterpretation = model.getInterpretation(person); | ||
346 | var queryEngine = model.getAdapter(ModelQueryAdapter.class); | ||
347 | var predicateResultSet = queryEngine.getResultSet(predicate); | ||
348 | |||
349 | personInterpretation.put(Tuple.of(0), true); | ||
350 | personInterpretation.put(Tuple.of(1), true); | ||
351 | |||
352 | assertResults(Map.of(), predicateResultSet); | ||
353 | assertTrue(queryEngine.hasPendingChanges()); | ||
354 | |||
355 | var state1 = model.commit(); | ||
356 | |||
357 | personInterpretation.put(Tuple.of(1), false); | ||
358 | personInterpretation.put(Tuple.of(2), true); | ||
359 | |||
360 | assertResults(Map.of(), predicateResultSet); | ||
361 | assertTrue(queryEngine.hasPendingChanges()); | ||
362 | |||
363 | model.restore(state1); | ||
364 | |||
365 | assertResults(Map.of( | ||
366 | Tuple.of(0), true, | ||
367 | Tuple.of(1), true, | ||
368 | Tuple.of(2), false, | ||
369 | Tuple.of(3), false | ||
370 | ), predicateResultSet); | ||
62 | assertFalse(queryEngine.hasPendingChanges()); | 371 | assertFalse(queryEngine.hasPendingChanges()); |
63 | } | 372 | } |
64 | } | 373 | } |
diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperatorStreamTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperatorStreamTest.java deleted file mode 100644 index c529117e..00000000 --- a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperatorStreamTest.java +++ /dev/null | |||
@@ -1,51 +0,0 @@ | |||
1 | package tools.refinery.store.query.viatra.internal.cardinality; | ||
2 | |||
3 | import org.junit.jupiter.params.ParameterizedTest; | ||
4 | import org.junit.jupiter.params.provider.Arguments; | ||
5 | import org.junit.jupiter.params.provider.MethodSource; | ||
6 | import tools.refinery.store.representation.cardinality.UpperCardinalities; | ||
7 | import tools.refinery.store.representation.cardinality.UpperCardinality; | ||
8 | |||
9 | import java.util.List; | ||
10 | import java.util.stream.Stream; | ||
11 | |||
12 | import static org.hamcrest.MatcherAssert.assertThat; | ||
13 | import static org.hamcrest.Matchers.equalTo; | ||
14 | |||
15 | class UpperCardinalitySumAggregationOperatorStreamTest { | ||
16 | @ParameterizedTest | ||
17 | @MethodSource | ||
18 | void testStream(List<UpperCardinality> list, UpperCardinality expected) { | ||
19 | var result = UpperCardinalitySumAggregationOperator.INSTANCE.aggregateStream(list.stream()); | ||
20 | assertThat(result, equalTo(expected)); | ||
21 | } | ||
22 | |||
23 | static Stream<Arguments> testStream() { | ||
24 | return Stream.of( | ||
25 | Arguments.of(List.of(), UpperCardinalities.ZERO), | ||
26 | Arguments.of(List.of(UpperCardinality.of(3)), UpperCardinality.of(3)), | ||
27 | Arguments.of( | ||
28 | List.of( | ||
29 | UpperCardinality.of(2), | ||
30 | UpperCardinality.of(3) | ||
31 | ), | ||
32 | UpperCardinality.of(5) | ||
33 | ), | ||
34 | Arguments.of(List.of(UpperCardinalities.UNBOUNDED), UpperCardinalities.UNBOUNDED), | ||
35 | Arguments.of( | ||
36 | List.of( | ||
37 | UpperCardinalities.UNBOUNDED, | ||
38 | UpperCardinalities.UNBOUNDED | ||
39 | ), | ||
40 | UpperCardinalities.UNBOUNDED | ||
41 | ), | ||
42 | Arguments.of( | ||
43 | List.of( | ||
44 | UpperCardinalities.UNBOUNDED, | ||
45 | UpperCardinality.of(3) | ||
46 | ), | ||
47 | UpperCardinalities.UNBOUNDED | ||
48 | ) | ||
49 | ); | ||
50 | } | ||
51 | } | ||
diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperatorTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperatorTest.java deleted file mode 100644 index 20dad543..00000000 --- a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperatorTest.java +++ /dev/null | |||
@@ -1,87 +0,0 @@ | |||
1 | package tools.refinery.store.query.viatra.internal.cardinality; | ||
2 | |||
3 | import org.junit.jupiter.api.BeforeEach; | ||
4 | import org.junit.jupiter.api.Test; | ||
5 | import tools.refinery.store.representation.cardinality.UpperCardinalities; | ||
6 | import tools.refinery.store.representation.cardinality.UpperCardinality; | ||
7 | |||
8 | import static org.hamcrest.MatcherAssert.assertThat; | ||
9 | import static org.hamcrest.Matchers.equalTo; | ||
10 | |||
11 | class UpperCardinalitySumAggregationOperatorTest { | ||
12 | private UpperCardinalitySumAggregationOperator.Accumulator accumulator; | ||
13 | |||
14 | @BeforeEach | ||
15 | void beforeEach() { | ||
16 | accumulator = UpperCardinalitySumAggregationOperator.INSTANCE.createNeutral(); | ||
17 | } | ||
18 | |||
19 | @Test | ||
20 | void emptyAggregationTest() { | ||
21 | assertResult(UpperCardinality.of(0)); | ||
22 | } | ||
23 | |||
24 | @Test | ||
25 | void singleBoundedTest() { | ||
26 | insert(UpperCardinality.of(3)); | ||
27 | assertResult(UpperCardinality.of(3)); | ||
28 | } | ||
29 | |||
30 | @Test | ||
31 | void multipleBoundedTest() { | ||
32 | insert(UpperCardinality.of(2)); | ||
33 | insert(UpperCardinality.of(3)); | ||
34 | assertResult(UpperCardinality.of(5)); | ||
35 | } | ||
36 | |||
37 | @Test | ||
38 | void singleUnboundedTest() { | ||
39 | insert(UpperCardinalities.UNBOUNDED); | ||
40 | assertResult(UpperCardinalities.UNBOUNDED); | ||
41 | } | ||
42 | |||
43 | @Test | ||
44 | void multipleUnboundedTest() { | ||
45 | insert(UpperCardinalities.UNBOUNDED); | ||
46 | insert(UpperCardinalities.UNBOUNDED); | ||
47 | assertResult(UpperCardinalities.UNBOUNDED); | ||
48 | } | ||
49 | |||
50 | @Test | ||
51 | void removeBoundedTest() { | ||
52 | insert(UpperCardinality.of(2)); | ||
53 | insert(UpperCardinality.of(3)); | ||
54 | remove(UpperCardinality.of(2)); | ||
55 | assertResult(UpperCardinality.of(3)); | ||
56 | } | ||
57 | |||
58 | @Test | ||
59 | void removeAllUnboundedTest() { | ||
60 | insert(UpperCardinalities.UNBOUNDED); | ||
61 | insert(UpperCardinality.of(3)); | ||
62 | remove(UpperCardinalities.UNBOUNDED); | ||
63 | assertResult(UpperCardinality.of(3)); | ||
64 | } | ||
65 | |||
66 | @Test | ||
67 | void removeSomeUnboundedTest() { | ||
68 | insert(UpperCardinalities.UNBOUNDED); | ||
69 | insert(UpperCardinalities.UNBOUNDED); | ||
70 | insert(UpperCardinality.of(3)); | ||
71 | remove(UpperCardinalities.UNBOUNDED); | ||
72 | assertResult(UpperCardinalities.UNBOUNDED); | ||
73 | } | ||
74 | |||
75 | private void insert(UpperCardinality value) { | ||
76 | accumulator = UpperCardinalitySumAggregationOperator.INSTANCE.update(accumulator, value, true); | ||
77 | } | ||
78 | |||
79 | private void remove(UpperCardinality value) { | ||
80 | accumulator = UpperCardinalitySumAggregationOperator.INSTANCE.update(accumulator, value, false); | ||
81 | } | ||
82 | |||
83 | private void assertResult(UpperCardinality expected) { | ||
84 | var result = UpperCardinalitySumAggregationOperator.INSTANCE.getAggregate(accumulator); | ||
85 | assertThat(result, equalTo(expected)); | ||
86 | } | ||
87 | } | ||
diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/matcher/MatcherUtilsTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/matcher/MatcherUtilsTest.java new file mode 100644 index 00000000..968c6c5e --- /dev/null +++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/matcher/MatcherUtilsTest.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 | */ | ||
6 | package tools.refinery.store.query.viatra.internal.matcher; | ||
7 | |||
8 | import org.eclipse.viatra.query.runtime.matchers.tuple.*; | ||
9 | import org.junit.jupiter.api.Test; | ||
10 | import tools.refinery.store.tuple.Tuple; | ||
11 | import tools.refinery.store.tuple.*; | ||
12 | |||
13 | import java.util.List; | ||
14 | |||
15 | import static org.hamcrest.MatcherAssert.assertThat; | ||
16 | import static org.hamcrest.Matchers.*; | ||
17 | import static org.junit.jupiter.api.Assertions.assertThrows; | ||
18 | |||
19 | class MatcherUtilsTest { | ||
20 | @Test | ||
21 | void toViatra0Test() { | ||
22 | var viatraTuple = MatcherUtils.toViatraTuple(Tuple.of()); | ||
23 | assertThat(viatraTuple.getSize(), is(0)); | ||
24 | assertThat(viatraTuple, instanceOf(FlatTuple0.class)); | ||
25 | } | ||
26 | |||
27 | @Test | ||
28 | void toViatra1Test() { | ||
29 | var viatraTuple = MatcherUtils.toViatraTuple(Tuple.of(2)); | ||
30 | assertThat(viatraTuple.getSize(), is(1)); | ||
31 | assertThat(viatraTuple.get(0), is(Tuple.of(2))); | ||
32 | assertThat(viatraTuple, instanceOf(FlatTuple1.class)); | ||
33 | } | ||
34 | |||
35 | @Test | ||
36 | void toViatra2Test() { | ||
37 | var viatraTuple = MatcherUtils.toViatraTuple(Tuple.of(2, 3)); | ||
38 | assertThat(viatraTuple.getSize(), is(2)); | ||
39 | assertThat(viatraTuple.get(0), is(Tuple.of(2))); | ||
40 | assertThat(viatraTuple.get(1), is(Tuple.of(3))); | ||
41 | assertThat(viatraTuple, instanceOf(FlatTuple2.class)); | ||
42 | } | ||
43 | |||
44 | @Test | ||
45 | void toViatra3Test() { | ||
46 | var viatraTuple = MatcherUtils.toViatraTuple(Tuple.of(2, 3, 5)); | ||
47 | assertThat(viatraTuple.getSize(), is(3)); | ||
48 | assertThat(viatraTuple.get(0), is(Tuple.of(2))); | ||
49 | assertThat(viatraTuple.get(1), is(Tuple.of(3))); | ||
50 | assertThat(viatraTuple.get(2), is(Tuple.of(5))); | ||
51 | assertThat(viatraTuple, instanceOf(FlatTuple3.class)); | ||
52 | } | ||
53 | |||
54 | @Test | ||
55 | void toViatra4Test() { | ||
56 | var viatraTuple = MatcherUtils.toViatraTuple(Tuple.of(2, 3, 5, 8)); | ||
57 | assertThat(viatraTuple.getSize(), is(4)); | ||
58 | assertThat(viatraTuple.get(0), is(Tuple.of(2))); | ||
59 | assertThat(viatraTuple.get(1), is(Tuple.of(3))); | ||
60 | assertThat(viatraTuple.get(2), is(Tuple.of(5))); | ||
61 | assertThat(viatraTuple.get(3), is(Tuple.of(8))); | ||
62 | assertThat(viatraTuple, instanceOf(FlatTuple4.class)); | ||
63 | } | ||
64 | |||
65 | @Test | ||
66 | void toViatra5Test() { | ||
67 | var viatraTuple = MatcherUtils.toViatraTuple(Tuple.of(2, 3, 5, 8, 13)); | ||
68 | assertThat(viatraTuple.getSize(), is(5)); | ||
69 | assertThat(viatraTuple.get(0), is(Tuple.of(2))); | ||
70 | assertThat(viatraTuple.get(1), is(Tuple.of(3))); | ||
71 | assertThat(viatraTuple.get(2), is(Tuple.of(5))); | ||
72 | assertThat(viatraTuple.get(3), is(Tuple.of(8))); | ||
73 | assertThat(viatraTuple.get(4), is(Tuple.of(13))); | ||
74 | assertThat(viatraTuple, instanceOf(FlatTuple.class)); | ||
75 | } | ||
76 | |||
77 | @Test | ||
78 | void toRefinery0Test() { | ||
79 | var refineryTuple = MatcherUtils.toRefineryTuple(Tuples.flatTupleOf()); | ||
80 | assertThat(refineryTuple.getSize(), is(0)); | ||
81 | assertThat(refineryTuple, instanceOf(Tuple0.class)); | ||
82 | } | ||
83 | |||
84 | @Test | ||
85 | void toRefinery1Test() { | ||
86 | var refineryTuple = MatcherUtils.toRefineryTuple(Tuples.flatTupleOf(Tuple.of(2))); | ||
87 | assertThat(refineryTuple.getSize(), is(1)); | ||
88 | assertThat(refineryTuple.get(0), is(2)); | ||
89 | assertThat(refineryTuple, instanceOf(Tuple1.class)); | ||
90 | } | ||
91 | |||
92 | @Test | ||
93 | void toRefinery2Test() { | ||
94 | var refineryTuple = MatcherUtils.toRefineryTuple(Tuples.flatTupleOf(Tuple.of(2), Tuple.of(3))); | ||
95 | assertThat(refineryTuple.getSize(), is(2)); | ||
96 | assertThat(refineryTuple.get(0), is(2)); | ||
97 | assertThat(refineryTuple.get(1), is(3)); | ||
98 | assertThat(refineryTuple, instanceOf(Tuple2.class)); | ||
99 | } | ||
100 | |||
101 | @Test | ||
102 | void toRefinery3Test() { | ||
103 | var refineryTuple = MatcherUtils.toRefineryTuple(Tuples.flatTupleOf(Tuple.of(2), Tuple.of(3), Tuple.of(5))); | ||
104 | assertThat(refineryTuple.getSize(), is(3)); | ||
105 | assertThat(refineryTuple.get(0), is(2)); | ||
106 | assertThat(refineryTuple.get(1), is(3)); | ||
107 | assertThat(refineryTuple.get(2), is(5)); | ||
108 | assertThat(refineryTuple, instanceOf(Tuple3.class)); | ||
109 | } | ||
110 | |||
111 | @Test | ||
112 | void toRefinery4Test() { | ||
113 | var refineryTuple = MatcherUtils.toRefineryTuple(Tuples.flatTupleOf(Tuple.of(2), Tuple.of(3), Tuple.of(5), | ||
114 | Tuple.of(8))); | ||
115 | assertThat(refineryTuple.getSize(), is(4)); | ||
116 | assertThat(refineryTuple.get(0), is(2)); | ||
117 | assertThat(refineryTuple.get(1), is(3)); | ||
118 | assertThat(refineryTuple.get(2), is(5)); | ||
119 | assertThat(refineryTuple.get(3), is(8)); | ||
120 | assertThat(refineryTuple, instanceOf(Tuple4.class)); | ||
121 | } | ||
122 | |||
123 | @Test | ||
124 | void toRefinery5Test() { | ||
125 | var refineryTuple = MatcherUtils.toRefineryTuple(Tuples.flatTupleOf(Tuple.of(2), Tuple.of(3), Tuple.of(5), | ||
126 | Tuple.of(8), Tuple.of(13))); | ||
127 | assertThat(refineryTuple.getSize(), is(5)); | ||
128 | assertThat(refineryTuple.get(0), is(2)); | ||
129 | assertThat(refineryTuple.get(1), is(3)); | ||
130 | assertThat(refineryTuple.get(2), is(5)); | ||
131 | assertThat(refineryTuple.get(3), is(8)); | ||
132 | assertThat(refineryTuple.get(4), is(13)); | ||
133 | assertThat(refineryTuple, instanceOf(TupleN.class)); | ||
134 | } | ||
135 | |||
136 | @Test | ||
137 | void toRefineryInvalidValueTest() { | ||
138 | var viatraTuple = Tuples.flatTupleOf(Tuple.of(2), -98); | ||
139 | assertThrows(IllegalArgumentException.class, () -> MatcherUtils.toRefineryTuple(viatraTuple)); | ||
140 | } | ||
141 | |||
142 | @Test | ||
143 | void keyToRefinery0Test() { | ||
144 | var refineryTuple = MatcherUtils.keyToRefineryTuple(Tuples.flatTupleOf(-99)); | ||
145 | assertThat(refineryTuple.getSize(), is(0)); | ||
146 | assertThat(refineryTuple, instanceOf(Tuple0.class)); | ||
147 | } | ||
148 | |||
149 | @Test | ||
150 | void keyToRefinery1Test() { | ||
151 | var refineryTuple = MatcherUtils.keyToRefineryTuple(Tuples.flatTupleOf(Tuple.of(2), -99)); | ||
152 | assertThat(refineryTuple.getSize(), is(1)); | ||
153 | assertThat(refineryTuple.get(0), is(2)); | ||
154 | assertThat(refineryTuple, instanceOf(Tuple1.class)); | ||
155 | } | ||
156 | |||
157 | @Test | ||
158 | void keyToRefinery2Test() { | ||
159 | var refineryTuple = MatcherUtils.keyToRefineryTuple(Tuples.flatTupleOf(Tuple.of(2), Tuple.of(3), -99)); | ||
160 | assertThat(refineryTuple.getSize(), is(2)); | ||
161 | assertThat(refineryTuple.get(0), is(2)); | ||
162 | assertThat(refineryTuple.get(1), is(3)); | ||
163 | assertThat(refineryTuple, instanceOf(Tuple2.class)); | ||
164 | } | ||
165 | |||
166 | @Test | ||
167 | void keyToRefinery3Test() { | ||
168 | var refineryTuple = MatcherUtils.keyToRefineryTuple(Tuples.flatTupleOf(Tuple.of(2), Tuple.of(3), Tuple.of(5), | ||
169 | -99)); | ||
170 | assertThat(refineryTuple.getSize(), is(3)); | ||
171 | assertThat(refineryTuple.get(0), is(2)); | ||
172 | assertThat(refineryTuple.get(1), is(3)); | ||
173 | assertThat(refineryTuple.get(2), is(5)); | ||
174 | assertThat(refineryTuple, instanceOf(Tuple3.class)); | ||
175 | } | ||
176 | |||
177 | @Test | ||
178 | void keyToRefinery4Test() { | ||
179 | var refineryTuple = MatcherUtils.keyToRefineryTuple(Tuples.flatTupleOf(Tuple.of(2), Tuple.of(3), Tuple.of(5), | ||
180 | Tuple.of(8), -99)); | ||
181 | assertThat(refineryTuple.getSize(), is(4)); | ||
182 | assertThat(refineryTuple.get(0), is(2)); | ||
183 | assertThat(refineryTuple.get(1), is(3)); | ||
184 | assertThat(refineryTuple.get(2), is(5)); | ||
185 | assertThat(refineryTuple.get(3), is(8)); | ||
186 | assertThat(refineryTuple, instanceOf(Tuple4.class)); | ||
187 | } | ||
188 | |||
189 | @Test | ||
190 | void keyToRefinery5Test() { | ||
191 | var refineryTuple = MatcherUtils.keyToRefineryTuple(Tuples.flatTupleOf(Tuple.of(2), Tuple.of(3), Tuple.of(5), | ||
192 | Tuple.of(8), Tuple.of(13), -99)); | ||
193 | assertThat(refineryTuple.getSize(), is(5)); | ||
194 | assertThat(refineryTuple.get(0), is(2)); | ||
195 | assertThat(refineryTuple.get(1), is(3)); | ||
196 | assertThat(refineryTuple.get(2), is(5)); | ||
197 | assertThat(refineryTuple.get(3), is(8)); | ||
198 | assertThat(refineryTuple.get(4), is(13)); | ||
199 | assertThat(refineryTuple, instanceOf(TupleN.class)); | ||
200 | } | ||
201 | |||
202 | @Test | ||
203 | void keyToRefineryTooShortTest() { | ||
204 | var viatraTuple = Tuples.flatTupleOf(); | ||
205 | assertThrows(IllegalArgumentException.class, () -> MatcherUtils.keyToRefineryTuple(viatraTuple)); | ||
206 | } | ||
207 | |||
208 | @Test | ||
209 | void keyToRefineryInvalidValueTest() { | ||
210 | var viatraTuple = Tuples.flatTupleOf(Tuple.of(2), -98, -99); | ||
211 | assertThrows(IllegalArgumentException.class, () -> MatcherUtils.keyToRefineryTuple(viatraTuple)); | ||
212 | } | ||
213 | |||
214 | @Test | ||
215 | void getSingleValueTest() { | ||
216 | var value = MatcherUtils.getSingleValue(List.of(Tuples.flatTupleOf(Tuple.of(2), -99))); | ||
217 | assertThat(value, is(-99)); | ||
218 | } | ||
219 | |||
220 | // Static analysis accurately determines that the result is always {@code null}, but we check anyways. | ||
221 | @SuppressWarnings("ConstantValue") | ||
222 | @Test | ||
223 | void getSingleValueNullTest() { | ||
224 | var value = MatcherUtils.getSingleValue((Iterable<? extends ITuple>) null); | ||
225 | assertThat(value, nullValue()); | ||
226 | } | ||
227 | |||
228 | @Test | ||
229 | void getSingleValueEmptyTest() { | ||
230 | var value = MatcherUtils.getSingleValue(List.of()); | ||
231 | assertThat(value, nullValue()); | ||
232 | } | ||
233 | |||
234 | @Test | ||
235 | void getSingleValueMultipleTest() { | ||
236 | var viatraTuples = List.of(Tuples.flatTupleOf(Tuple.of(2), -98), Tuples.flatTupleOf(Tuple.of(2), -99)); | ||
237 | assertThrows(IllegalStateException.class, () -> MatcherUtils.getSingleValue(viatraTuples)); | ||
238 | } | ||
239 | } | ||
diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryAssertions.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryAssertions.java new file mode 100644 index 00000000..ca089a9d --- /dev/null +++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryAssertions.java | |||
@@ -0,0 +1,57 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.viatra.tests; | ||
7 | |||
8 | import org.junit.jupiter.api.function.Executable; | ||
9 | import tools.refinery.store.query.resultset.ResultSet; | ||
10 | import tools.refinery.store.tuple.Tuple; | ||
11 | |||
12 | import java.util.*; | ||
13 | |||
14 | import static org.hamcrest.MatcherAssert.assertThat; | ||
15 | import static org.hamcrest.Matchers.is; | ||
16 | import static org.hamcrest.Matchers.nullValue; | ||
17 | import static org.junit.jupiter.api.Assertions.assertAll; | ||
18 | |||
19 | public final class QueryAssertions { | ||
20 | private QueryAssertions() { | ||
21 | throw new IllegalStateException("This is a static utility class and should not be instantiated directly"); | ||
22 | } | ||
23 | |||
24 | public static <T> void assertNullableResults(Map<Tuple, Optional<T>> expected, ResultSet<T> resultSet) { | ||
25 | var nullableValuesMap = new LinkedHashMap<Tuple, T>(expected.size()); | ||
26 | for (var entry : expected.entrySet()) { | ||
27 | nullableValuesMap.put(entry.getKey(), entry.getValue().orElse(null)); | ||
28 | } | ||
29 | assertResults(nullableValuesMap, resultSet); | ||
30 | } | ||
31 | |||
32 | public static <T> void assertResults(Map<Tuple, T> expected, ResultSet<T> resultSet) { | ||
33 | var defaultValue = resultSet.getQuery().defaultValue(); | ||
34 | var filteredExpected = new LinkedHashMap<Tuple, T>(); | ||
35 | var executables = new ArrayList<Executable>(); | ||
36 | for (var entry : expected.entrySet()) { | ||
37 | var key = entry.getKey(); | ||
38 | var value = entry.getValue(); | ||
39 | if (!Objects.equals(value, defaultValue)) { | ||
40 | filteredExpected.put(key, value); | ||
41 | } | ||
42 | executables.add(() -> assertThat("value for key " + key,resultSet.get(key), is(value))); | ||
43 | } | ||
44 | executables.add(() -> assertThat("results size", resultSet.size(), is(filteredExpected.size()))); | ||
45 | |||
46 | var actual = new LinkedHashMap<Tuple, T>(); | ||
47 | var cursor = resultSet.getAll(); | ||
48 | while (cursor.move()) { | ||
49 | var key = cursor.getKey(); | ||
50 | var previous = actual.put(key, cursor.getValue()); | ||
51 | assertThat("duplicate value for key " + key, previous, nullValue()); | ||
52 | } | ||
53 | executables.add(() -> assertThat("results cursor", actual, is(filteredExpected))); | ||
54 | |||
55 | assertAll(executables); | ||
56 | } | ||
57 | } | ||
diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryBackendHint.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryBackendHint.java new file mode 100644 index 00000000..dc0e92c8 --- /dev/null +++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryBackendHint.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 | */ | ||
6 | package tools.refinery.store.query.viatra.tests; | ||
7 | |||
8 | import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint; | ||
9 | |||
10 | /** | ||
11 | * Overrides {@link QueryEvaluationHint#toString()} for pretty names in parametric test names. | ||
12 | */ | ||
13 | class QueryBackendHint extends QueryEvaluationHint { | ||
14 | public QueryBackendHint(BackendRequirement backendRequirementType) { | ||
15 | super(null, backendRequirementType); | ||
16 | } | ||
17 | |||
18 | @Override | ||
19 | public String toString() { | ||
20 | return switch (getQueryBackendRequirementType()) { | ||
21 | case UNSPECIFIED -> "default"; | ||
22 | case DEFAULT_CACHING -> "incremental"; | ||
23 | case DEFAULT_SEARCH -> "localSearch"; | ||
24 | default -> throw new IllegalStateException("Unknown BackendRequirement"); | ||
25 | }; | ||
26 | } | ||
27 | } | ||
diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryEngineTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryEngineTest.java new file mode 100644 index 00000000..d4f16da7 --- /dev/null +++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryEngineTest.java | |||
@@ -0,0 +1,21 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.viatra.tests; | ||
7 | |||
8 | import org.junit.jupiter.params.ParameterizedTest; | ||
9 | import org.junit.jupiter.params.provider.ArgumentsSource; | ||
10 | |||
11 | import java.lang.annotation.ElementType; | ||
12 | import java.lang.annotation.Retention; | ||
13 | import java.lang.annotation.RetentionPolicy; | ||
14 | import java.lang.annotation.Target; | ||
15 | |||
16 | @ParameterizedTest(name = "backend = {0}") | ||
17 | @ArgumentsSource(QueryEvaluationHintSource.class) | ||
18 | @Target(ElementType.METHOD) | ||
19 | @Retention(RetentionPolicy.RUNTIME) | ||
20 | public @interface QueryEngineTest { | ||
21 | } | ||
diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryEvaluationHintSource.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryEvaluationHintSource.java new file mode 100644 index 00000000..9e75d5f3 --- /dev/null +++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryEvaluationHintSource.java | |||
@@ -0,0 +1,24 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.query.viatra.tests; | ||
7 | |||
8 | import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint; | ||
9 | import org.junit.jupiter.api.extension.ExtensionContext; | ||
10 | import org.junit.jupiter.params.provider.Arguments; | ||
11 | import org.junit.jupiter.params.provider.ArgumentsProvider; | ||
12 | |||
13 | import java.util.stream.Stream; | ||
14 | |||
15 | public class QueryEvaluationHintSource implements ArgumentsProvider { | ||
16 | @Override | ||
17 | public Stream<? extends Arguments> provideArguments(ExtensionContext context) { | ||
18 | return Stream.of( | ||
19 | Arguments.of(new QueryBackendHint(QueryEvaluationHint.BackendRequirement.UNSPECIFIED)), | ||
20 | Arguments.of(new QueryBackendHint(QueryEvaluationHint.BackendRequirement.DEFAULT_CACHING)), | ||
21 | Arguments.of(new QueryBackendHint(QueryEvaluationHint.BackendRequirement.DEFAULT_SEARCH)) | ||
22 | ); | ||
23 | } | ||
24 | } | ||