Skip to content

Commit dc7381b

Browse files
Add regression tests for record methods checked against an external spec (#342)
A record's methods were silently not verified when the project had an @ExternalRefinementsFor spec: the launcher parsed sources at compliance level 8, where JDT does not know records. It recovered by turning the record header into a method `record Repro(int attempts)` and the record's methods into locals and a block inside it, so the real methods never existed in the model; the verifier only emitted "Java compilation encountered issues" and then reported success. This is already fixed on main by reading the compliance level from the project's pom (#352), defaulting it to 21 with Spoon 11.5.0 (#368), and skipping records in the external-spec pass (#370). These directory cases keep the spec in its own file, as in the issue, and check a record whose methods violate (and respect) the Throwable typestate. Fixes #342 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent ad055b4 commit dc7381b

4 files changed

Lines changed: 64 additions & 0 deletions

File tree

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package testSuite.classes.record_external_spec_correct;
2+
3+
// the methods of a record are checked against an external spec declared in another file (#342)
4+
public record Retry(int attempts) {
5+
void fail(String summary) {
6+
Throwable exception = new Throwable(summary);
7+
exception.initCause(new RuntimeException("first"));
8+
}
9+
10+
static Throwable wrap(String message, Throwable cause) {
11+
return new Throwable(message, cause);
12+
}
13+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package testSuite.classes.record_external_spec_correct;
2+
3+
import liquidjava.specification.ExternalRefinementsFor;
4+
import liquidjava.specification.StateRefinement;
5+
import liquidjava.specification.StateSet;
6+
7+
@ExternalRefinementsFor("java.lang.Throwable")
8+
@StateSet({"withThrowable", "noThrowable"})
9+
public interface ThrowableRefinements {
10+
@StateRefinement(to = "noThrowable(this)")
11+
void Throwable(String message);
12+
13+
@StateRefinement(to = "withThrowable(this)")
14+
void Throwable(String message, Throwable cause);
15+
16+
@StateRefinement(from = "noThrowable(this)", to = "withThrowable(this)")
17+
Throwable initCause(Throwable cause);
18+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package testSuite.classes.record_external_spec_error;
2+
3+
// the methods of a record are checked against an external spec declared in another file (#342)
4+
public record Retry(int attempts) {
5+
void fail(String summary) {
6+
Throwable exception = new Throwable(summary, new RuntimeException("first"));
7+
exception.initCause(new RuntimeException("second")); // Expect: State Refinement Error
8+
}
9+
10+
static Throwable wrap(String message) {
11+
Throwable t = new Throwable(message);
12+
t.initCause(new RuntimeException("cause"));
13+
return t.initCause(new RuntimeException("again")); // Expect: State Refinement Error
14+
}
15+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package testSuite.classes.record_external_spec_error;
2+
3+
import liquidjava.specification.ExternalRefinementsFor;
4+
import liquidjava.specification.StateRefinement;
5+
import liquidjava.specification.StateSet;
6+
7+
@ExternalRefinementsFor("java.lang.Throwable")
8+
@StateSet({"withThrowable", "noThrowable"})
9+
public interface ThrowableRefinements {
10+
@StateRefinement(to = "noThrowable(this)")
11+
void Throwable(String message);
12+
13+
@StateRefinement(to = "withThrowable(this)")
14+
void Throwable(String message, Throwable cause);
15+
16+
@StateRefinement(from = "noThrowable(this)", to = "withThrowable(this)")
17+
Throwable initCause(Throwable cause);
18+
}

0 commit comments

Comments
 (0)