diff options
author | Kristóf Marussy <kristof@marussy.com> | 2022-09-19 21:33:55 +0200 |
---|---|---|
committer | Kristóf Marussy <kristof@marussy.com> | 2022-09-19 21:42:05 +0200 |
commit | 7fb99f0225911a8962aaf3493b89f41e791df359 (patch) | |
tree | f289ac1433f91e2b1c9e1a5eab92ae6b52aa9d83 /subprojects/language/src/test | |
parent | refactor(language): clarify containment hierarchy (diff) | |
download | refinery-7fb99f0225911a8962aaf3493b89f41e791df359.tar.gz refinery-7fb99f0225911a8962aaf3493b89f41e791df359.tar.zst refinery-7fb99f0225911a8962aaf3493b89f41e791df359.zip |
feat(language): problem desugaring
Diffstat (limited to 'subprojects/language/src/test')
-rw-r--r-- | subprojects/language/src/test/java/tools/refinery/language/tests/utils/SymbolCollectorTest.java | 276 |
1 files changed, 276 insertions, 0 deletions
diff --git a/subprojects/language/src/test/java/tools/refinery/language/tests/utils/SymbolCollectorTest.java b/subprojects/language/src/test/java/tools/refinery/language/tests/utils/SymbolCollectorTest.java new file mode 100644 index 00000000..e2e3218c --- /dev/null +++ b/subprojects/language/src/test/java/tools/refinery/language/tests/utils/SymbolCollectorTest.java | |||
@@ -0,0 +1,276 @@ | |||
1 | package tools.refinery.language.tests.utils; | ||
2 | |||
3 | import com.google.inject.Inject; | ||
4 | import org.eclipse.xtext.testing.InjectWith; | ||
5 | import org.eclipse.xtext.testing.extensions.InjectionExtension; | ||
6 | import org.hamcrest.Matcher; | ||
7 | import org.junit.jupiter.api.Test; | ||
8 | import org.junit.jupiter.api.extension.ExtendWith; | ||
9 | import org.junit.jupiter.params.ParameterizedTest; | ||
10 | import org.junit.jupiter.params.provider.Arguments; | ||
11 | import org.junit.jupiter.params.provider.MethodSource; | ||
12 | import tools.refinery.language.model.problem.*; | ||
13 | import tools.refinery.language.model.tests.utils.ProblemParseHelper; | ||
14 | import tools.refinery.language.tests.ProblemInjectorProvider; | ||
15 | import tools.refinery.language.utils.ProblemDesugarer; | ||
16 | |||
17 | import java.util.stream.Stream; | ||
18 | |||
19 | import static org.hamcrest.MatcherAssert.assertThat; | ||
20 | import static org.hamcrest.Matchers.*; | ||
21 | import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; | ||
22 | |||
23 | @ExtendWith(InjectionExtension.class) | ||
24 | @InjectWith(ProblemInjectorProvider.class) | ||
25 | class SymbolCollectorTest { | ||
26 | @Inject | ||
27 | private ProblemParseHelper parseHelper; | ||
28 | |||
29 | @Inject | ||
30 | private ProblemDesugarer desugarer; | ||
31 | |||
32 | @Test | ||
33 | void implicitNodeTest() { | ||
34 | var problem = parseHelper.parse(""" | ||
35 | exists(a). | ||
36 | """); | ||
37 | var collectedSymbols = desugarer.collectSymbols(problem.get()); | ||
38 | var node = problem.node("a"); | ||
39 | assertThat(collectedSymbols.nodes(), hasKey(node)); | ||
40 | assertThat(collectedSymbols.nodes().get(node).individual(), is(false)); | ||
41 | } | ||
42 | |||
43 | @Test | ||
44 | void individualNodeTest() { | ||
45 | var problem = parseHelper.parse(""" | ||
46 | indiv a. | ||
47 | """); | ||
48 | var collectedSymbols = desugarer.collectSymbols(problem.get()); | ||
49 | var node = problem.individualNode("a"); | ||
50 | assertThat(collectedSymbols.nodes(), hasKey(node)); | ||
51 | assertThat(collectedSymbols.nodes().get(node).individual(), is(true)); | ||
52 | } | ||
53 | |||
54 | @Test | ||
55 | void classTest() { | ||
56 | var problem = parseHelper.parse(""" | ||
57 | class Foo. | ||
58 | """); | ||
59 | var collectedSymbols = desugarer.collectSymbols(problem.get()); | ||
60 | var classDeclaration = problem.findClass("Foo").get(); | ||
61 | assertThat(collectedSymbols.relations(), hasKey(classDeclaration)); | ||
62 | var classInfo = collectedSymbols.relations().get(classDeclaration); | ||
63 | assertThat(classInfo.parameters(), hasSize(1)); | ||
64 | assertThat(classInfo.kind(), is(PredicateKind.CONTAINED)); | ||
65 | assertThat(classInfo.hasDefinition(), is(false)); | ||
66 | var newNode = classDeclaration.getNewNode(); | ||
67 | assertThat(collectedSymbols.nodes(), hasKey(newNode)); | ||
68 | assertThat(collectedSymbols.nodes().get(newNode).individual(), is(false)); | ||
69 | assertThat(classInfo.assertions(), assertsNode(newNode, LogicValue.TRUE)); | ||
70 | assertThat(collectedSymbols.relations().get(problem.builtinSymbols().exists()).assertions(), | ||
71 | assertsNode(newNode, LogicValue.UNKNOWN)); | ||
72 | assertThat(collectedSymbols.relations().get(problem.builtinSymbols().equals()).assertions(), | ||
73 | assertsNode(newNode, LogicValue.UNKNOWN)); | ||
74 | } | ||
75 | |||
76 | @Test | ||
77 | void abstractClassTest() { | ||
78 | var problem = parseHelper.parse(""" | ||
79 | abstract class Foo. | ||
80 | """); | ||
81 | var collectedSymbols = desugarer.collectSymbols(problem.get()); | ||
82 | assertThat(collectedSymbols.relations().get(problem.findClass("Foo").get()).assertions(), hasSize(0)); | ||
83 | } | ||
84 | |||
85 | @Test | ||
86 | void referenceTest() { | ||
87 | var problem = parseHelper.parse(""" | ||
88 | class Foo { | ||
89 | Foo[] bar opposite quux | ||
90 | Foo quux opposite bar | ||
91 | } | ||
92 | """); | ||
93 | var collectedSymbols = desugarer.collectSymbols(problem.get()); | ||
94 | var fooClass = problem.findClass("Foo"); | ||
95 | var barReference = fooClass.reference("bar"); | ||
96 | var barInfo = collectedSymbols.relations().get(barReference); | ||
97 | var quuxReference = fooClass.reference("quux"); | ||
98 | var quuxInfo = collectedSymbols.relations().get(quuxReference); | ||
99 | assertThat(barInfo.kind(), is(PredicateKind.DEFAULT)); | ||
100 | assertThat(barInfo.opposite(), is(quuxReference)); | ||
101 | assertThat(barInfo.multiplicity(), is(instanceOf(UnboundedMultiplicity.class))); | ||
102 | assertThat(barInfo.hasDefinition(), is(false)); | ||
103 | assertThat(quuxInfo.kind(), is(PredicateKind.DEFAULT)); | ||
104 | assertThat(quuxInfo.opposite(), is(barReference)); | ||
105 | assertThat(quuxInfo.multiplicity(), is(instanceOf(ExactMultiplicity.class))); | ||
106 | assertThat(quuxInfo.multiplicity(), hasProperty("exactValue", is(1))); | ||
107 | assertThat(quuxInfo.hasDefinition(), is(false)); | ||
108 | } | ||
109 | |||
110 | @Test | ||
111 | void containmentReferenceTest() { | ||
112 | var problem = parseHelper.parse(""" | ||
113 | class Foo { | ||
114 | contains Foo[] bar | ||
115 | } | ||
116 | """); | ||
117 | var collectedSymbols = desugarer.collectSymbols(problem.get()); | ||
118 | assertThat(collectedSymbols.relations().get(problem.findClass("Foo").reference("bar")).kind(), | ||
119 | is(PredicateKind.CONTAINMENT)); | ||
120 | } | ||
121 | |||
122 | @Test | ||
123 | void dataReferenceTest() { | ||
124 | var problem = parseHelper.parse(""" | ||
125 | class Foo { | ||
126 | int bar | ||
127 | } | ||
128 | """); | ||
129 | var collectedSymbols = desugarer.collectSymbols(problem.get()); | ||
130 | assertThat(collectedSymbols.relations().get(problem.findClass("Foo").reference("bar")).kind(), | ||
131 | is(PredicateKind.CONTAINMENT)); | ||
132 | } | ||
133 | |||
134 | @Test | ||
135 | void enumTest() { | ||
136 | var problem = parseHelper.parse(""" | ||
137 | enum Foo { | ||
138 | bar, quux | ||
139 | } | ||
140 | """); | ||
141 | var collectedSymbols = desugarer.collectSymbols(problem.get()); | ||
142 | var enumDeclaration = problem.findEnum("Foo"); | ||
143 | var enumInfo = collectedSymbols.relations().get(enumDeclaration.get()); | ||
144 | assertThat(enumInfo.kind(), is(PredicateKind.DEFAULT)); | ||
145 | assertThat(enumInfo.assertions(), assertsNode(enumDeclaration.literal("bar"), LogicValue.TRUE)); | ||
146 | assertThat(enumInfo.assertions(), assertsNode(enumDeclaration.literal("quux"), LogicValue.TRUE)); | ||
147 | } | ||
148 | |||
149 | @ParameterizedTest | ||
150 | @MethodSource | ||
151 | void predicateTest(String keyword, PredicateKind kind) { | ||
152 | var problem = parseHelper.parse(keyword + " foo(node x) <-> domain(x); data(x)."); | ||
153 | var collectedSymbols = desugarer.collectSymbols(problem.get()); | ||
154 | var predicateInfo = collectedSymbols.relations().get(problem.pred("foo").get()); | ||
155 | assertThat(predicateInfo.kind(), is(kind)); | ||
156 | assertThat(predicateInfo.parameters(), hasSize(1)); | ||
157 | assertThat(predicateInfo.bodies(), hasSize(2)); | ||
158 | assertThat(predicateInfo.hasDefinition(), is(true)); | ||
159 | } | ||
160 | |||
161 | static Stream<Arguments> predicateTest() { | ||
162 | return Stream.of(Arguments.of("pred", PredicateKind.DEFAULT), Arguments.of("error", PredicateKind.ERROR), | ||
163 | Arguments.of("contained", PredicateKind.CONTAINED), Arguments.of("containment", | ||
164 | PredicateKind.CONTAINMENT)); | ||
165 | } | ||
166 | |||
167 | @ParameterizedTest | ||
168 | @MethodSource("logicValues") | ||
169 | void assertionTest(String keyword, LogicValue value) { | ||
170 | var problem = parseHelper.parse(""" | ||
171 | pred foo(node x). | ||
172 | foo(a): %s. | ||
173 | """.formatted(keyword)); | ||
174 | var collectedSymbols = desugarer.collectSymbols(problem.get()); | ||
175 | assertThat(collectedSymbols.relations().get(problem.pred("foo").get()).assertions(), | ||
176 | assertsNode(problem.node("a"), value)); | ||
177 | } | ||
178 | |||
179 | @ParameterizedTest | ||
180 | @MethodSource("logicValues") | ||
181 | void defaultAssertionTest(String keyword, LogicValue value) { | ||
182 | var problem = parseHelper.parse(""" | ||
183 | pred foo(node x). | ||
184 | default foo(a): %s. | ||
185 | """.formatted(keyword)); | ||
186 | var collectedSymbols = desugarer.collectSymbols(problem.get()); | ||
187 | assertThat(collectedSymbols.relations().get(problem.pred("foo").get()).defaultAssertions(), | ||
188 | assertsNode(problem.node("a"), value)); | ||
189 | } | ||
190 | |||
191 | static Stream<Arguments> logicValues() { | ||
192 | return Stream.of(Arguments.of("true", LogicValue.TRUE), Arguments.of("false", LogicValue.FALSE), | ||
193 | Arguments.of("unknown", LogicValue.UNKNOWN), Arguments.of("error", LogicValue.ERROR)); | ||
194 | } | ||
195 | |||
196 | @Test | ||
197 | void invalidAssertionArityTest() { | ||
198 | var problem = parseHelper.parse(""" | ||
199 | pred foo(node x). | ||
200 | foo(a, b). | ||
201 | """); | ||
202 | var collectedSymbols = desugarer.collectSymbols(problem.get()); | ||
203 | assertThat(collectedSymbols.relations().get(problem.pred("foo").get()).assertions(), hasSize(0)); | ||
204 | } | ||
205 | |||
206 | @ParameterizedTest | ||
207 | @MethodSource("valueTypes") | ||
208 | void nodeValueAssertionTest(String value, String typeName) { | ||
209 | var problem = parseHelper.parse("a: %s.".formatted(value)); | ||
210 | var collectedSymbols = desugarer.collectSymbols(problem.get()); | ||
211 | var node = problem.node("a"); | ||
212 | var nodeInfo = collectedSymbols.nodes().get(node); | ||
213 | assertThat(nodeInfo.individual(), is(false)); | ||
214 | assertThat(nodeInfo.valueAssertions(), hasSize(1)); | ||
215 | assertThat(collectedSymbols.relations().get(problem.builtin().findClass(typeName).get()).assertions(), | ||
216 | assertsNode(node, LogicValue.TRUE)); | ||
217 | } | ||
218 | |||
219 | @ParameterizedTest | ||
220 | @MethodSource("valueTypes") | ||
221 | void constantInAssertionTest(String value, String typeName) { | ||
222 | var problem = parseHelper.parse(""" | ||
223 | containment pred foo(node x, data y). | ||
224 | foo(a, %s). | ||
225 | """.formatted(value)); | ||
226 | var collectedSymbols = desugarer.collectSymbols(problem.get()); | ||
227 | var node = problem.assertion(0).arg(1).constantNode(); | ||
228 | var nodeInfo = collectedSymbols.nodes().get(node); | ||
229 | assertThat(nodeInfo.individual(), is(false)); | ||
230 | assertThat(nodeInfo.valueAssertions(), hasSize(1)); | ||
231 | assertThat(collectedSymbols.relations().get(problem.pred("foo").get()).assertions(), assertsNode(node, | ||
232 | LogicValue.TRUE)); | ||
233 | assertThat(collectedSymbols.relations().get(problem.builtin().findClass(typeName).get()).assertions(), | ||
234 | assertsNode(node, LogicValue.TRUE)); | ||
235 | } | ||
236 | |||
237 | @ParameterizedTest | ||
238 | @MethodSource("valueTypes") | ||
239 | void constantInUnknownAssertionTest(String value, String typeName) { | ||
240 | var problem = parseHelper.parse(""" | ||
241 | containment pred foo(node x, data y). | ||
242 | foo(a, %s): unknown. | ||
243 | """.formatted(value)); | ||
244 | var collectedSymbols = desugarer.collectSymbols(problem.get()); | ||
245 | var node = problem.assertion(0).arg(1).constantNode(); | ||
246 | var nodeInfo = collectedSymbols.nodes().get(node); | ||
247 | assertThat(nodeInfo.individual(), is(false)); | ||
248 | assertThat(nodeInfo.valueAssertions(), hasSize(1)); | ||
249 | assertThat(collectedSymbols.relations().get(problem.pred("foo").get()).assertions(), assertsNode(node, | ||
250 | LogicValue.UNKNOWN)); | ||
251 | assertThat(collectedSymbols.relations().get(problem.builtin().findClass(typeName).get()).assertions(), | ||
252 | assertsNode(node, LogicValue.TRUE)); | ||
253 | assertThat(collectedSymbols.relations().get(problem.builtinSymbols().exists()).assertions(), assertsNode(node, | ||
254 | LogicValue.UNKNOWN)); | ||
255 | } | ||
256 | |||
257 | @Test | ||
258 | void invalidProblemTest() { | ||
259 | var problem = parseHelper.parse(""" | ||
260 | class Foo { | ||
261 | bar[] opposite quux | ||
262 | Foo quux opposite bar | ||
263 | } | ||
264 | """).get(); | ||
265 | assertDoesNotThrow(() -> desugarer.collectSymbols(problem)); | ||
266 | } | ||
267 | |||
268 | static Stream<Arguments> valueTypes() { | ||
269 | return Stream.of(Arguments.of("3", "int"), Arguments.of("3.14", "real"), Arguments.of("\"foo\"", "string")); | ||
270 | } | ||
271 | |||
272 | private static Matcher<Iterable<? super Assertion>> assertsNode(Node node, LogicValue value) { | ||
273 | return hasItem(allOf(hasProperty("arguments", hasItem(hasProperty("node", is(node)))), hasProperty("value", | ||
274 | is(value)))); | ||
275 | } | ||
276 | } | ||