diff options
author | 2023-02-24 20:21:15 +0100 | |
---|---|---|
committer | 2023-02-24 23:29:49 +0100 | |
commit | f8a3c575e400259a4985233c07b7a50e5d4d82c5 (patch) | |
tree | f5975a19fcce28eba17b5af8adde5a37ddba83c6 /subprojects/store-query/src/test/java/tools | |
parent | refactor: split query and partial from store (diff) | |
download | refinery-f8a3c575e400259a4985233c07b7a50e5d4d82c5.tar.gz refinery-f8a3c575e400259a4985233c07b7a50e5d4d82c5.tar.zst refinery-f8a3c575e400259a4985233c07b7a50e5d4d82c5.zip |
feat: Dnf reduction and structural equality
Diffstat (limited to 'subprojects/store-query/src/test/java/tools')
3 files changed, 467 insertions, 0 deletions
diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/DnfBuilderTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/DnfBuilderTest.java new file mode 100644 index 00000000..e6701fe3 --- /dev/null +++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/DnfBuilderTest.java | |||
@@ -0,0 +1,218 @@ | |||
1 | package tools.refinery.store.query; | ||
2 | |||
3 | import org.junit.jupiter.api.Test; | ||
4 | import tools.refinery.store.query.literal.BooleanLiteral; | ||
5 | import tools.refinery.store.query.view.KeyOnlyRelationView; | ||
6 | import tools.refinery.store.representation.Symbol; | ||
7 | |||
8 | import static org.hamcrest.MatcherAssert.assertThat; | ||
9 | import static tools.refinery.store.query.literal.Literals.not; | ||
10 | import static tools.refinery.store.query.tests.QueryMatchers.structurallyEqualTo; | ||
11 | |||
12 | class DnfBuilderTest { | ||
13 | @Test | ||
14 | void eliminateTrueTest() { | ||
15 | var p = new Variable("p"); | ||
16 | var q = new Variable("q"); | ||
17 | var friend = new Symbol<>("friend", 2, Boolean.class, false); | ||
18 | var friendView = new KeyOnlyRelationView<>(friend); | ||
19 | |||
20 | var actual = Dnf.builder() | ||
21 | .parameters(p, q) | ||
22 | .clause(BooleanLiteral.TRUE, friendView.call(p, q)) | ||
23 | .build(); | ||
24 | var expected = Dnf.builder().parameters(p, q).clause(friendView.call(p, q)).build(); | ||
25 | |||
26 | assertThat(actual, structurallyEqualTo(expected)); | ||
27 | } | ||
28 | |||
29 | @Test | ||
30 | void eliminateFalseTest() { | ||
31 | var p = new Variable("p"); | ||
32 | var q = new Variable("q"); | ||
33 | var friend = new Symbol<>("friend", 2, Boolean.class, false); | ||
34 | var friendView = new KeyOnlyRelationView<>(friend); | ||
35 | |||
36 | var actual = Dnf.builder() | ||
37 | .parameters(p, q) | ||
38 | .clause(friendView.call(p, q)) | ||
39 | .clause(friendView.call(q, p), BooleanLiteral.FALSE) | ||
40 | .build(); | ||
41 | var expected = Dnf.builder().parameters(p, q).clause(friendView.call(p, q)).build(); | ||
42 | |||
43 | assertThat(actual, structurallyEqualTo(expected)); | ||
44 | } | ||
45 | |||
46 | @Test | ||
47 | void alwaysTrueTest() { | ||
48 | var p = new Variable("p"); | ||
49 | var q = new Variable("q"); | ||
50 | var friend = new Symbol<>("friend", 2, Boolean.class, false); | ||
51 | var friendView = new KeyOnlyRelationView<>(friend); | ||
52 | |||
53 | var actual = Dnf.builder() | ||
54 | .parameters(p, q) | ||
55 | .clause(friendView.call(p, q)) | ||
56 | .clause(BooleanLiteral.TRUE) | ||
57 | .build(); | ||
58 | var expected = Dnf.builder().parameters(p, q).clause().build(); | ||
59 | |||
60 | assertThat(actual, structurallyEqualTo(expected)); | ||
61 | } | ||
62 | |||
63 | @Test | ||
64 | void alwaysFalseTest() { | ||
65 | var p = new Variable("p"); | ||
66 | var q = new Variable("q"); | ||
67 | var friend = new Symbol<>("friend", 2, Boolean.class, false); | ||
68 | var friendView = new KeyOnlyRelationView<>(friend); | ||
69 | |||
70 | var actual = Dnf.builder() | ||
71 | .parameters(p, q) | ||
72 | .clause(friendView.call(p, q), BooleanLiteral.FALSE) | ||
73 | .build(); | ||
74 | var expected = Dnf.builder().parameters(p, q).build(); | ||
75 | |||
76 | assertThat(actual, structurallyEqualTo(expected)); | ||
77 | } | ||
78 | |||
79 | @Test | ||
80 | void eliminateTrueDnfTest() { | ||
81 | var p = new Variable("p"); | ||
82 | var q = new Variable("q"); | ||
83 | var friend = new Symbol<>("friend", 2, Boolean.class, false); | ||
84 | var friendView = new KeyOnlyRelationView<>(friend); | ||
85 | var trueDnf = Dnf.builder().parameter(p).clause().build(); | ||
86 | |||
87 | var actual = Dnf.builder() | ||
88 | .parameters(p, q) | ||
89 | .clause(trueDnf.call(q), friendView.call(p, q)) | ||
90 | .build(); | ||
91 | var expected = Dnf.builder().parameters(p, q).clause(friendView.call(p, q)).build(); | ||
92 | |||
93 | assertThat(actual, structurallyEqualTo(expected)); | ||
94 | } | ||
95 | |||
96 | @Test | ||
97 | void eliminateFalseDnfTest() { | ||
98 | var p = new Variable("p"); | ||
99 | var q = new Variable("q"); | ||
100 | var friend = new Symbol<>("friend", 2, Boolean.class, false); | ||
101 | var friendView = new KeyOnlyRelationView<>(friend); | ||
102 | var falseDnf = Dnf.builder().parameter(p).build(); | ||
103 | |||
104 | var actual = Dnf.builder() | ||
105 | .parameters(p, q) | ||
106 | .clause(friendView.call(p, q)) | ||
107 | .clause(friendView.call(q, p), falseDnf.call(q)) | ||
108 | .build(); | ||
109 | var expected = Dnf.builder().parameters(p, q).clause(friendView.call(p, q)).build(); | ||
110 | |||
111 | assertThat(actual, structurallyEqualTo(expected)); | ||
112 | } | ||
113 | |||
114 | @Test | ||
115 | void alwaysTrueDnfTest() { | ||
116 | var p = new Variable("p"); | ||
117 | var q = new Variable("q"); | ||
118 | var friend = new Symbol<>("friend", 2, Boolean.class, false); | ||
119 | var friendView = new KeyOnlyRelationView<>(friend); | ||
120 | var trueDnf = Dnf.builder().parameter(p).clause().build(); | ||
121 | |||
122 | var actual = Dnf.builder() | ||
123 | .parameters(p, q) | ||
124 | .clause(friendView.call(p, q)) | ||
125 | .clause(trueDnf.call(q)) | ||
126 | .build(); | ||
127 | var expected = Dnf.builder().parameters(p, q).clause().build(); | ||
128 | |||
129 | assertThat(actual, structurallyEqualTo(expected)); | ||
130 | } | ||
131 | |||
132 | @Test | ||
133 | void alwaysFalseDnfTest() { | ||
134 | var p = new Variable("p"); | ||
135 | var q = new Variable("q"); | ||
136 | var friend = new Symbol<>("friend", 2, Boolean.class, false); | ||
137 | var friendView = new KeyOnlyRelationView<>(friend); | ||
138 | var falseDnf = Dnf.builder().parameter(p).build(); | ||
139 | |||
140 | var actual = Dnf.builder() | ||
141 | .parameters(p, q) | ||
142 | .clause(friendView.call(p, q), falseDnf.call(q)) | ||
143 | .build(); | ||
144 | var expected = Dnf.builder().parameters(p, q).build(); | ||
145 | |||
146 | assertThat(actual, structurallyEqualTo(expected)); | ||
147 | } | ||
148 | |||
149 | @Test | ||
150 | void eliminateNotFalseDnfTest() { | ||
151 | var p = new Variable("p"); | ||
152 | var q = new Variable("q"); | ||
153 | var friend = new Symbol<>("friend", 2, Boolean.class, false); | ||
154 | var friendView = new KeyOnlyRelationView<>(friend); | ||
155 | var falseDnf = Dnf.builder().parameter(p).build(); | ||
156 | |||
157 | var actual = Dnf.builder() | ||
158 | .parameters(p, q) | ||
159 | .clause(not(falseDnf.call(q)), friendView.call(p, q)) | ||
160 | .build(); | ||
161 | var expected = Dnf.builder().parameters(p, q).clause(friendView.call(p, q)).build(); | ||
162 | |||
163 | assertThat(actual, structurallyEqualTo(expected)); | ||
164 | } | ||
165 | |||
166 | @Test | ||
167 | void eliminateNotTrueDnfTest() { | ||
168 | var p = new Variable("p"); | ||
169 | var q = new Variable("q"); | ||
170 | var friend = new Symbol<>("friend", 2, Boolean.class, false); | ||
171 | var friendView = new KeyOnlyRelationView<>(friend); | ||
172 | var trueDnf = Dnf.builder().parameter(p).clause().build(); | ||
173 | |||
174 | var actual = Dnf.builder() | ||
175 | .parameters(p, q) | ||
176 | .clause(friendView.call(p, q)) | ||
177 | .clause(friendView.call(q, p), not(trueDnf.call(q))) | ||
178 | .build(); | ||
179 | var expected = Dnf.builder().parameters(p, q).clause(friendView.call(p, q)).build(); | ||
180 | |||
181 | assertThat(actual, structurallyEqualTo(expected)); | ||
182 | } | ||
183 | |||
184 | @Test | ||
185 | void alwaysNotFalseDnfTest() { | ||
186 | var p = new Variable("p"); | ||
187 | var q = new Variable("q"); | ||
188 | var friend = new Symbol<>("friend", 2, Boolean.class, false); | ||
189 | var friendView = new KeyOnlyRelationView<>(friend); | ||
190 | var falseDnf = Dnf.builder().parameter(p).build(); | ||
191 | |||
192 | var actual = Dnf.builder() | ||
193 | .parameters(p, q) | ||
194 | .clause(friendView.call(p, q)) | ||
195 | .clause(not(falseDnf.call(q))) | ||
196 | .build(); | ||
197 | var expected = Dnf.builder().parameters(p, q).clause().build(); | ||
198 | |||
199 | assertThat(actual, structurallyEqualTo(expected)); | ||
200 | } | ||
201 | |||
202 | @Test | ||
203 | void alwaysNotTrueDnfTest() { | ||
204 | var p = new Variable("p"); | ||
205 | var q = new Variable("q"); | ||
206 | var friend = new Symbol<>("friend", 2, Boolean.class, false); | ||
207 | var friendView = new KeyOnlyRelationView<>(friend); | ||
208 | var trueDnf = Dnf.builder().parameter(p).clause().build(); | ||
209 | |||
210 | var actual = Dnf.builder() | ||
211 | .parameters(p, q) | ||
212 | .clause(friendView.call(p, q), not(trueDnf.call(q))) | ||
213 | .build(); | ||
214 | var expected = Dnf.builder().parameters(p, q).build(); | ||
215 | |||
216 | assertThat(actual, structurallyEqualTo(expected)); | ||
217 | } | ||
218 | } | ||
diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/DnfToStringTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/DnfToStringTest.java new file mode 100644 index 00000000..e6e4bef3 --- /dev/null +++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/DnfToStringTest.java | |||
@@ -0,0 +1,172 @@ | |||
1 | package tools.refinery.store.query; | ||
2 | |||
3 | import org.junit.jupiter.api.Test; | ||
4 | import tools.refinery.store.query.view.KeyOnlyRelationView; | ||
5 | import tools.refinery.store.representation.Symbol; | ||
6 | |||
7 | import static org.hamcrest.MatcherAssert.assertThat; | ||
8 | import static org.hamcrest.Matchers.is; | ||
9 | import static tools.refinery.store.query.literal.Literals.not; | ||
10 | |||
11 | class DnfToStringTest { | ||
12 | @Test | ||
13 | void noClausesTest() { | ||
14 | var p = new Variable("p"); | ||
15 | var dnf = Dnf.builder("Example").parameter(p).build(); | ||
16 | |||
17 | assertThat(dnf.toString(), is(""" | ||
18 | pred Example(p) <-> | ||
19 | <no clauses>. | ||
20 | """)); | ||
21 | } | ||
22 | |||
23 | @Test | ||
24 | void noParametersTest() { | ||
25 | var dnf = Dnf.builder("Example").build(); | ||
26 | |||
27 | assertThat(dnf.toString(), is(""" | ||
28 | pred Example() <-> | ||
29 | <no clauses>. | ||
30 | """)); | ||
31 | } | ||
32 | |||
33 | @Test | ||
34 | void emptyClauseTest() { | ||
35 | var p = new Variable("p"); | ||
36 | var dnf = Dnf.builder("Example").parameter(p).clause().build(); | ||
37 | |||
38 | assertThat(dnf.toString(), is(""" | ||
39 | pred Example(p) <-> | ||
40 | <empty>. | ||
41 | """)); | ||
42 | } | ||
43 | |||
44 | @Test | ||
45 | void relationViewPositiveTest() { | ||
46 | var p = new Variable("p"); | ||
47 | var q = new Variable("q"); | ||
48 | var friend = new Symbol<>("friend", 2, Boolean.class, false); | ||
49 | var friendView = new KeyOnlyRelationView<>(friend); | ||
50 | var dnf = Dnf.builder("Example").parameter(p).clause(friendView.call(p, q)).build(); | ||
51 | |||
52 | assertThat(dnf.toString(), is(""" | ||
53 | pred Example(p) <-> | ||
54 | @RelationView("key") friend(p, q). | ||
55 | """)); | ||
56 | } | ||
57 | |||
58 | @Test | ||
59 | void relationViewNegativeTest() { | ||
60 | var p = new Variable("p"); | ||
61 | var q = new Variable("q"); | ||
62 | var friend = new Symbol<>("friend", 2, Boolean.class, false); | ||
63 | var friendView = new KeyOnlyRelationView<>(friend); | ||
64 | var dnf = Dnf.builder("Example").parameter(p).clause(not(friendView.call(p, q))).build(); | ||
65 | |||
66 | assertThat(dnf.toString(), is(""" | ||
67 | pred Example(p) <-> | ||
68 | !(@RelationView("key") friend(p, q)). | ||
69 | """)); | ||
70 | } | ||
71 | |||
72 | @Test | ||
73 | void relationViewTransitiveTest() { | ||
74 | var p = new Variable("p"); | ||
75 | var q = new Variable("q"); | ||
76 | var friend = new Symbol<>("friend", 2, Boolean.class, false); | ||
77 | var friendView = new KeyOnlyRelationView<>(friend); | ||
78 | var dnf = Dnf.builder("Example").parameter(p).clause(friendView.callTransitive(p, q)).build(); | ||
79 | |||
80 | assertThat(dnf.toString(), is(""" | ||
81 | pred Example(p) <-> | ||
82 | @RelationView("key") friend+(p, q). | ||
83 | """)); | ||
84 | } | ||
85 | |||
86 | @Test | ||
87 | void multipleParametersTest() { | ||
88 | var p = new Variable("p"); | ||
89 | var q = new Variable("q"); | ||
90 | var friend = new Symbol<>("friend", 2, Boolean.class, false); | ||
91 | var friendView = new KeyOnlyRelationView<>(friend); | ||
92 | var dnf = Dnf.builder("Example").parameters(p, q).clause(friendView.call(p, q)).build(); | ||
93 | |||
94 | assertThat(dnf.toString(), is(""" | ||
95 | pred Example(p, q) <-> | ||
96 | @RelationView("key") friend(p, q). | ||
97 | """)); | ||
98 | } | ||
99 | |||
100 | @Test | ||
101 | void multipleLiteralsTest() { | ||
102 | var p = new Variable("p"); | ||
103 | var q = new Variable("q"); | ||
104 | var person = new Symbol<>("person", 1, Boolean.class, false); | ||
105 | var personView = new KeyOnlyRelationView<>(person); | ||
106 | var friend = new Symbol<>("friend", 2, Boolean.class, false); | ||
107 | var friendView = new KeyOnlyRelationView<>(friend); | ||
108 | var dnf = Dnf.builder("Example") | ||
109 | .parameter(p) | ||
110 | .clause( | ||
111 | personView.call(p), | ||
112 | personView.call(q), | ||
113 | friendView.call(p, q) | ||
114 | ) | ||
115 | .build(); | ||
116 | |||
117 | assertThat(dnf.toString(), is(""" | ||
118 | pred Example(p) <-> | ||
119 | @RelationView("key") person(p), | ||
120 | @RelationView("key") person(q), | ||
121 | @RelationView("key") friend(p, q). | ||
122 | """)); | ||
123 | } | ||
124 | |||
125 | @Test | ||
126 | void multipleClausesTest() { | ||
127 | var p = new Variable("p"); | ||
128 | var q = new Variable("q"); | ||
129 | var friend = new Symbol<>("friend", 2, Boolean.class, false); | ||
130 | var friendView = new KeyOnlyRelationView<>(friend); | ||
131 | var dnf = Dnf.builder("Example") | ||
132 | .parameter(p) | ||
133 | .clause(friendView.call(p, q)) | ||
134 | .clause(friendView.call(q, p)) | ||
135 | .build(); | ||
136 | |||
137 | assertThat(dnf.toString(), is(""" | ||
138 | pred Example(p) <-> | ||
139 | @RelationView("key") friend(p, q) | ||
140 | ; | ||
141 | @RelationView("key") friend(q, p). | ||
142 | """)); | ||
143 | } | ||
144 | |||
145 | @Test | ||
146 | void dnfTest() { | ||
147 | var p = new Variable("p"); | ||
148 | var q = new Variable("q"); | ||
149 | var r = new Variable("r"); | ||
150 | var s = new Variable("s"); | ||
151 | var person = new Symbol<>("person", 1, Boolean.class, false); | ||
152 | var personView = new KeyOnlyRelationView<>(person); | ||
153 | var friend = new Symbol<>("friend", 2, Boolean.class, false); | ||
154 | var friendView = new KeyOnlyRelationView<>(friend); | ||
155 | var called = Dnf.builder("Called").parameters(r, s).clause(friendView.call(r, s)).build(); | ||
156 | var dnf = Dnf.builder("Example") | ||
157 | .parameter(p) | ||
158 | .clause( | ||
159 | personView.call(p), | ||
160 | personView.call(q), | ||
161 | not(called.call(p, q)) | ||
162 | ) | ||
163 | .build(); | ||
164 | |||
165 | assertThat(dnf.toString(), is(""" | ||
166 | pred Example(p) <-> | ||
167 | @RelationView("key") person(p), | ||
168 | @RelationView("key") person(q), | ||
169 | !(@Dnf Called(p, q)). | ||
170 | """)); | ||
171 | } | ||
172 | } | ||
diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/tests/StructurallyEqualToTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/tests/StructurallyEqualToTest.java new file mode 100644 index 00000000..0cda22df --- /dev/null +++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/tests/StructurallyEqualToTest.java | |||
@@ -0,0 +1,77 @@ | |||
1 | package tools.refinery.store.query.tests; | ||
2 | |||
3 | import org.junit.jupiter.api.Test; | ||
4 | import tools.refinery.store.query.Dnf; | ||
5 | import tools.refinery.store.query.Variable; | ||
6 | import tools.refinery.store.query.view.KeyOnlyRelationView; | ||
7 | import tools.refinery.store.representation.Symbol; | ||
8 | |||
9 | import static org.hamcrest.CoreMatchers.containsString; | ||
10 | import static org.hamcrest.MatcherAssert.assertThat; | ||
11 | import static org.junit.jupiter.api.Assertions.assertThrows; | ||
12 | import static tools.refinery.store.query.tests.QueryMatchers.structurallyEqualTo; | ||
13 | |||
14 | class StructurallyEqualToTest { | ||
15 | @Test | ||
16 | void flatEqualsTest() { | ||
17 | var p = new Variable("p"); | ||
18 | var q = new Variable("q"); | ||
19 | var person = new Symbol<>("Person", 1, Boolean.class, false); | ||
20 | var personView = new KeyOnlyRelationView<>(person); | ||
21 | |||
22 | var expected = Dnf.builder("Expected").parameters(q).clause(personView.call(q)).build(); | ||
23 | var actual = Dnf.builder("Actual").parameters(p).clause(personView.call(p)).build(); | ||
24 | |||
25 | assertThat(actual, structurallyEqualTo(expected)); | ||
26 | } | ||
27 | |||
28 | @Test | ||
29 | void flatNotEqualsTest() { | ||
30 | var p = new Variable("p"); | ||
31 | var q = new Variable("q"); | ||
32 | var person = new Symbol<>("Person", 1, Boolean.class, false); | ||
33 | var personView = new KeyOnlyRelationView<>(person); | ||
34 | |||
35 | var expected = Dnf.builder("Expected").parameters(q).clause(personView.call(q)).build(); | ||
36 | var actual = Dnf.builder("Actual").parameters(p).clause(personView.call(q)).build(); | ||
37 | |||
38 | var assertion = structurallyEqualTo(expected); | ||
39 | assertThrows(AssertionError.class, () -> assertThat(actual, assertion)); | ||
40 | } | ||
41 | |||
42 | @Test | ||
43 | void deepEqualsTest() { | ||
44 | var p = new Variable("p"); | ||
45 | var q = new Variable("q"); | ||
46 | var person = new Symbol<>("Person", 1, Boolean.class, false); | ||
47 | var personView = new KeyOnlyRelationView<>(person); | ||
48 | |||
49 | var expected = Dnf.builder("Expected").parameters(q).clause( | ||
50 | Dnf.builder("Expected2").parameters(p).clause(personView.call(p)).build().call(q) | ||
51 | ).build(); | ||
52 | var actual = Dnf.builder("Actual").parameters(q).clause( | ||
53 | Dnf.builder("Actual2").parameters(p).clause(personView.call(p)).build().call(q) | ||
54 | ).build(); | ||
55 | |||
56 | assertThat(actual, structurallyEqualTo(expected)); | ||
57 | } | ||
58 | |||
59 | @Test | ||
60 | void deepNotEqualsTest() { | ||
61 | var p = new Variable("p"); | ||
62 | var q = new Variable("q"); | ||
63 | var person = new Symbol<>("Person", 1, Boolean.class, false); | ||
64 | var personView = new KeyOnlyRelationView<>(person); | ||
65 | |||
66 | var expected = Dnf.builder("Expected").parameters(q).clause( | ||
67 | Dnf.builder("Expected2").parameters(p).clause(personView.call(p)).build().call(q) | ||
68 | ).build(); | ||
69 | var actual = Dnf.builder("Actual").parameters(q).clause( | ||
70 | Dnf.builder("Actual2").parameters(p).clause(personView.call(q)).build().call(q) | ||
71 | ).build(); | ||
72 | |||
73 | var assertion = structurallyEqualTo(expected); | ||
74 | var error = assertThrows(AssertionError.class, () -> assertThat(actual, assertion)); | ||
75 | assertThat(error.getMessage(), containsString(" called from Expected ")); | ||
76 | } | ||
77 | } | ||