aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/language/src/test
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kristof@marussy.com>2023-11-18 19:43:09 +0100
committerLibravatar Kristóf Marussy <kristof@marussy.com>2023-11-19 14:41:17 +0100
commit392242099439fd3f21abb87d55ce94050e71ccb5 (patch)
tree2be45d93ae8ebbd3dd0cc051c3db26f0318cb7d2 /subprojects/language/src/test
parentfix: upper and lower scopes (diff)
downloadrefinery-392242099439fd3f21abb87d55ce94050e71ccb5.tar.gz
refinery-392242099439fd3f21abb87d55ce94050e71ccb5.tar.zst
refinery-392242099439fd3f21abb87d55ce94050e71ccb5.zip
feat(language): arity validation
Diffstat (limited to 'subprojects/language/src/test')
-rw-r--r--subprojects/language/src/test/java/tools/refinery/language/tests/validation/ArityValidationTest.java249
1 files changed, 249 insertions, 0 deletions
diff --git a/subprojects/language/src/test/java/tools/refinery/language/tests/validation/ArityValidationTest.java b/subprojects/language/src/test/java/tools/refinery/language/tests/validation/ArityValidationTest.java
new file mode 100644
index 00000000..68e9fa8d
--- /dev/null
+++ b/subprojects/language/src/test/java/tools/refinery/language/tests/validation/ArityValidationTest.java
@@ -0,0 +1,249 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.language.tests.validation;
7
8import com.google.inject.Inject;
9import org.eclipse.emf.common.util.Diagnostic;
10import org.eclipse.xtext.testing.InjectWith;
11import org.eclipse.xtext.testing.extensions.InjectionExtension;
12import org.junit.jupiter.api.Test;
13import org.junit.jupiter.api.extension.ExtendWith;
14import org.junit.jupiter.params.ParameterizedTest;
15import org.junit.jupiter.params.provider.Arguments;
16import org.junit.jupiter.params.provider.MethodSource;
17import org.junit.jupiter.params.provider.ValueSource;
18import tools.refinery.language.model.tests.utils.ProblemParseHelper;
19import tools.refinery.language.tests.ProblemInjectorProvider;
20import tools.refinery.language.validation.ProblemValidator;
21
22import java.util.stream.Stream;
23
24import static org.hamcrest.MatcherAssert.assertThat;
25import static org.hamcrest.Matchers.*;
26
27@ExtendWith(InjectionExtension.class)
28@InjectWith(ProblemInjectorProvider.class)
29class ArityValidationTest {
30 @Inject
31 private ProblemParseHelper parseHelper;
32
33 @ParameterizedTest
34 @ValueSource(strings = {"""
35 pred Foo(node n) <-> false.
36 """, """
37 pred Foo(node n, node m) <-> false.
38 """, """
39 enum Foo { FOO_A, FOO_B }
40 """})
41 void invalidSupertypeTest(String supertypeDefinition) {
42 var problem = parseHelper.parse("""
43 %s
44
45 class Bar extends Foo.
46 """.formatted(supertypeDefinition));
47 var issues = problem.validate();
48 assertThat(issues, hasItem(allOf(
49 hasProperty("severity", is(Diagnostic.ERROR)),
50 hasProperty("issueCode", is(ProblemValidator.INVALID_SUPERTYPE_ISSUE)),
51 hasProperty("message", stringContainsInOrder("Foo", "Bar"))
52 )));
53 }
54
55 @ParameterizedTest
56 @ValueSource(strings = {"""
57 class Foo.
58 """, """
59 abstract class Foo.
60 """})
61 void validSupertypeTest(String supertypeDefinition) {
62 var problem = parseHelper.parse("""
63 %s
64
65 class Bar extends Foo.
66 """.formatted(supertypeDefinition));
67 var issues = problem.validate();
68 assertThat(issues, empty());
69 }
70
71 @ParameterizedTest
72 @ValueSource(strings = {"""
73 foo().
74 """, """
75 foo(a1, a2, a3).
76 """, """
77 pred bar() <-> foo().
78 """, """
79 pred bar(node n) <-> foo(n, n, n).
80 """, """
81 pred bar(foo n) <-> false.
82 """, """
83 scope foo = 1..10.
84 """, """
85 class Bar {
86 foo[] f
87 }
88 """, """
89 class Bar {
90 refers foo[] f
91 }
92 """})
93 void invalidArityTest(String usage) {
94 var problem = parseHelper.parse("""
95 pred foo(node a, node b) <-> a != b.
96
97 %s
98 """.formatted(usage));
99 var issues = problem.validate();
100 assertThat(issues, hasItem(allOf(
101 hasProperty("severity", is(Diagnostic.ERROR)),
102 hasProperty("issueCode", is(ProblemValidator.INVALID_ARITY_ISSUE)),
103 hasProperty("message", containsString("foo"))
104 )));
105 }
106
107 @ParameterizedTest
108 @ValueSource(strings = {"""
109 foo(a).
110 """, """
111 pred bar(node m) <-> !foo(m).
112 """, """
113 pred bar(foo f) <-> true.
114 """, """
115 scope foo = 1..10.
116 """, """
117 class Bar {
118 foo[] quux
119 }
120 """, """
121 class Bar {
122 refers foo[] quux
123 }
124 """})
125 void validUnaryArityTest(String supertypeDefinition) {
126 var problem = parseHelper.parse("""
127 pred foo(node n) <-> false.
128
129 %s
130 """.formatted(supertypeDefinition));
131 var issues = problem.validate();
132 assertThat(issues, empty());
133 }
134
135 @ParameterizedTest
136 @ValueSource(strings = {"""
137 foo(a, b).
138 """, """
139 pred bar(node m) <-> !foo(m, m).
140 """, /* Also test for parameters without any type annotation. */ """
141 pred bar(m) <-> foo(m, m).
142 """})
143 void validBinaryArityTest(String supertypeDefinition) {
144 var problem = parseHelper.parse("""
145 pred foo(node n, node m) <-> false.
146
147 %s
148 """.formatted(supertypeDefinition));
149 var issues = problem.validate();
150 assertThat(issues, empty());
151 }
152
153 @Test
154 void notResolvedArityTest() {
155 var problem = parseHelper.parse("""
156 notResolved(a, b).
157 """);
158 var issues = problem.validate();
159 assertThat(issues, not(contains(hasProperty("issueCode", is(ProblemValidator.INVALID_ARITY_ISSUE)))));
160 }
161
162 @Test
163 void validTransitiveClosure() {
164 var problem = parseHelper.parse("""
165 pred foo(node a, node b) <-> false.
166
167 pred bar(a, b) <-> foo+(a, b).
168 """);
169 var issues = problem.validate();
170 assertThat(issues, not(contains(hasProperty("issueCode",
171 is(ProblemValidator.INVALID_TRANSITIVE_CLOSURE_ISSUE)))));
172 }
173
174 @Test
175 void invalidTransitiveClosure() {
176 // 0 and 1 argument transitive closures do not get parsed as transitive closure
177 // due to the ambiguity with the addition operator {@code a + (b)}.
178 var problem = parseHelper.parse("""
179 pred foo(node a, node b) <-> false.
180
181 pred bar(node a, node b) <-> foo+(a, b, a).
182 """);
183 var issues = problem.validate();
184 assertThat(issues, hasItem(allOf(
185 hasProperty("severity", is(Diagnostic.ERROR)),
186 hasProperty("issueCode", is(ProblemValidator.INVALID_TRANSITIVE_CLOSURE_ISSUE))
187 )));
188 }
189
190 @ParameterizedTest
191 @MethodSource
192 void invalidReferenceTypeTest(String definition, String referenceKind) {
193 var problem = parseHelper.parse("""
194 %s
195
196 class Bar {
197 %s Foo foo
198 }
199 """.formatted(definition, referenceKind));
200 var issues = problem.validate();
201 assertThat(issues, allOf(
202 hasItem(allOf(
203 hasProperty("severity", is(Diagnostic.ERROR)),
204 hasProperty("issueCode", is(ProblemValidator.INVALID_REFERENCE_TYPE_ISSUE)),
205 hasProperty("message", stringContainsInOrder("Foo", "foo"))
206 )),
207 not(hasItem(hasProperty("issueCode", is(ProblemValidator.INVALID_ARITY_ISSUE))))
208 ));
209 }
210
211 static Stream<Arguments> invalidReferenceTypeTest() {
212 return Stream.of(
213 "pred Foo(node n) <-> true.",
214 "pred Foo(node n, node m) <-> true.",
215 "enum Foo { FOO_A, FOO_B }"
216 ).flatMap(definition -> Stream.of(
217 Arguments.of(definition, "contains"),
218 Arguments.of(definition, "container")
219 ));
220 }
221
222
223 @ParameterizedTest
224 @MethodSource
225 void validReferenceTypeTest(String definition, String referenceKind) {
226 var problem = parseHelper.parse("""
227 %s
228
229 class Bar {
230 %s Foo foo
231 }
232 """.formatted(definition, referenceKind));
233 var issues = problem.validate();
234 assertThat(issues, not(hasItem(hasProperty("issueCode", anyOf(
235 is(ProblemValidator.INVALID_REFERENCE_TYPE_ISSUE),
236 is(ProblemValidator.INVALID_ARITY_ISSUE)
237 )))));
238 }
239
240 static Stream<Arguments> validReferenceTypeTest() {
241 return Stream.of(
242 "class Foo.",
243 "abstract class Foo."
244 ).flatMap(definition -> Stream.of(
245 Arguments.of(definition, "contains"),
246 Arguments.of(definition, "container")
247 ));
248 }
249}