Skip to content

Commit 98c485e

Browse files
committed
Add Counterexample Tests
1 parent bcaea90 commit 98c485e

8 files changed

Lines changed: 172 additions & 1 deletion

File tree

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package testSuite;
2+
3+
import liquidjava.specification.Refinement;
4+
5+
public class ErrorBoolean {
6+
7+
@Refinement("_ == true")
8+
boolean mustBeTrue(boolean value) {
9+
return value; // Refinement Error
10+
}
11+
}

liquidjava-example/src/main/java/testSuite/ErrorDependentRefinement.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ public static void main(String[] args) {
99
int smaller = 5;
1010
@Refinement("bigger > 20")
1111
int bigger = 50;
12-
@Refinement("_ > smaller && _ < bigger")
12+
@Refinement("_ > smaller && _ < bigger")
1313
int middle = 21; // Refinement Error
1414
}
1515
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package testSuite;
2+
3+
import liquidjava.specification.Refinement;
4+
5+
public class ErrorDependentUpperBound {
6+
7+
@Refinement("0 <= _ && _ < len")
8+
int nextIndex(
9+
@Refinement("_ > 0") int len,
10+
@Refinement("0 <= _ && _ < len") int i) {
11+
return i + 1; // Refinement Error
12+
}
13+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package testSuite;
2+
3+
import liquidjava.specification.Refinement;
4+
5+
public class ErrorIdentity {
6+
7+
@Refinement("_ > 0")
8+
int positiveIdentity(int x) {
9+
return x; // Refinement Error
10+
}
11+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package testSuite;
2+
3+
import liquidjava.specification.Refinement;
4+
5+
public class ErrorIntegerDivision {
6+
7+
@Refinement("_ > 0")
8+
int half(@Refinement("_ > 0") int x) {
9+
return x / 2; // Refinement Error
10+
}
11+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package testSuite;
2+
3+
import liquidjava.specification.Refinement;
4+
5+
public class ErrorLiteralZero {
6+
7+
@Refinement("_ != 0")
8+
int zero() {
9+
return 0; // Refinement Error
10+
}
11+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package testSuite;
2+
3+
import liquidjava.specification.Refinement;
4+
5+
public class ErrorRecursiveDecrement {
6+
7+
public int f(@Refinement("_ > 0") int x) {
8+
return f(x - 1); // Refinement Error
9+
}
10+
}
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
package liquidjava.api.tests;
2+
3+
import static org.junit.jupiter.api.Assertions.*;
4+
5+
import java.util.List;
6+
7+
import org.junit.jupiter.api.Test;
8+
9+
import liquidjava.api.CommandLineLauncher;
10+
import liquidjava.diagnostics.Diagnostics;
11+
import liquidjava.diagnostics.errors.LJError;
12+
import liquidjava.diagnostics.errors.RefinementError;
13+
import liquidjava.utils.Pair;
14+
15+
class TestCounterexamples {
16+
17+
private static final String TEST_SUITE = "../liquidjava-example/src/main/java/testSuite/";
18+
19+
@Test
20+
void recursiveDecrementIncludesInputAndGeneratedArgument() {
21+
RefinementError error = verify("ErrorRecursiveDecrement.java");
22+
assertAssignments(error, assignment("x", "1"), assignment("#x", "0"));
23+
}
24+
25+
@Test
26+
void integerDivisionIncludesInputAndGeneratedReturn() {
27+
RefinementError error = verify("ErrorIntegerDivision.java");
28+
assertAssignments(error, assignment("x", "1"), assignment("#ret", "0"));
29+
}
30+
31+
@Test
32+
void dependentUpperBoundIncludesBoundaryValuesInBinderOrder() {
33+
RefinementError error = verify("ErrorDependentUpperBound.java");
34+
assertAssignments(error, assignment("len", "1"), assignment("i", "0"), assignment("#ret", "1"));
35+
}
36+
37+
@Test
38+
void literalZeroHasNoCounterexampleBecauseValueIsAlreadyKnown() {
39+
RefinementError error = verify("ErrorLiteralZero.java");
40+
assertTrue(error.getCounterexample().isEmpty());
41+
}
42+
43+
@Test
44+
void identityRetainsInputAndReturnSelectedByTheModel() {
45+
RefinementError error = verify("ErrorIdentity.java");
46+
assertAssignments(error, assignment("x", "0"), assignment("#ret", "0"));
47+
}
48+
49+
@Test
50+
void staticFinalConstantHasNoCounterexampleBecauseValueIsAlreadyKnown() {
51+
RefinementError error = verify("ErrorStaticFinalConstant.java");
52+
assertTrue(error.getCounterexample().isEmpty());
53+
}
54+
55+
@Test
56+
void knownReturnAssignmentIsRemovedWhileDependentAssignmentsRemain() {
57+
RefinementError error = verify("ErrorDependentRefinement.java");
58+
assertAssignments(error, assignment("smaller", "0"), assignment("bigger", "21"));
59+
}
60+
61+
@Test
62+
void multipleParametersAndGeneratedReturnFollowBinderOrder() {
63+
RefinementError error = verify("ErrorFunctionDeclarations.java");
64+
assertAssignments(error, assignment("d", "0"), assignment("i", "1"), assignment("#ret", "2"));
65+
}
66+
67+
@Test
68+
void variableUpdateIncludesNegativeInputAndGeneratedReturn() {
69+
RefinementError error = verify("ErrorAssignmentBeforeReturn.java");
70+
assertAssignments(error, assignment("x", "-1"), assignment("#ret", "0"));
71+
}
72+
73+
@Test
74+
void pathConditionIsOmittedWhileRecursiveArgumentRemains() {
75+
RefinementError error = verify("ErrorRecursion.java");
76+
assertAssignments(error, assignment("k", "0"), assignment("#k", "-1"));
77+
}
78+
79+
@Test
80+
void booleanCounterexampleIncludesInputAndGeneratedReturn() {
81+
RefinementError error = verify("ErrorBoolean.java");
82+
assertAssignments(error, assignment("value", "false"), assignment("#ret", "false"));
83+
}
84+
85+
private static RefinementError verify(String test) {
86+
CommandLineLauncher.launch(TEST_SUITE + test);
87+
List<LJError> errors = Diagnostics.getInstance().getErrors().stream().toList();
88+
assertEquals(1, errors.size(), "Expected exactly one error from " + test);
89+
return assertInstanceOf(RefinementError.class, errors.getFirst());
90+
}
91+
92+
@SafeVarargs
93+
private static void assertAssignments(RefinementError error, Pair<String, String>... expectedAssignments) {
94+
// get counterexample assignments without instance numbers in variable names
95+
List<Pair<String, String>> actualAssignments = error.getCounterexample().assignments().stream()
96+
.map(assignment -> assignment(assignment.first().replaceAll("_[0-9]+$", ""), assignment.second()))
97+
.toList();
98+
assertEquals(List.of(expectedAssignments), actualAssignments);
99+
}
100+
101+
private static Pair<String, String> assignment(String name, String value) {
102+
return new Pair<>(name, value);
103+
}
104+
}

0 commit comments

Comments
 (0)