Skip to content

Commit 8836e41

Browse files
committed
Move class initialization tests to Java fixture
1 parent d361c9e commit 8836e41

10 files changed

Lines changed: 131 additions & 239 deletions

‎AGENTS.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,8 @@
2222
- `classfile/` - Class file parser
2323
- `java_class_proto/` - Java class prototypes
2424
- `test_utils/` - Shared test utilities
25+
26+
## Testing Boundaries
27+
- Keep `java_runtime/tests/classes` limited to Java standard library class and API behavior.
28+
- Test JVM and interpreter semantics, including class initialization, bytecode execution, and monitor behavior, with compiled Java fixtures under `test_data/src` and expected output under `test_data`, executed by `tests/test_class.rs`.
29+
- Do not place JVM core behavior tests in the `java_runtime` standard library test tree.

‎java_runtime/tests/classes/java/lang/mod.rs‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ mod test_boolean;
22
mod test_byte;
33
mod test_character;
44
mod test_class;
5-
mod test_class_initialization;
65
mod test_cldc11_exceptions;
76
mod test_double;
87
mod test_float;

‎java_runtime/tests/classes/java/lang/test_class_initialization.rs‎

Lines changed: 0 additions & 238 deletions
This file was deleted.
783 Bytes
Binary file not shown.
809 Bytes
Binary file not shown.
814 Bytes
Binary file not shown.
616 Bytes
Binary file not shown.

‎test_data/ConcurrentClinit.class‎

1.7 KB
Binary file not shown.

‎test_data/ConcurrentClinit.txt‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
42
2+
42
3+
1
4+
java.lang.ExceptionInInitializerError
5+
java.lang.NoClassDefFoundError
6+
java.lang.NoClassDefFoundError
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
public class ConcurrentClinit {
2+
private static volatile boolean successfulOwnerStarted;
3+
private static volatile boolean successfulWaiterStarted;
4+
private static volatile boolean failingOwnerStarted;
5+
private static volatile boolean failingWaiterStarted;
6+
7+
private static class Successful {
8+
static int initializationCount;
9+
static int value;
10+
11+
static {
12+
initializationCount++;
13+
successfulOwnerStarted = true;
14+
while (!successfulWaiterStarted) {
15+
Thread.yield();
16+
}
17+
try {
18+
Thread.sleep(10);
19+
} catch (InterruptedException exception) {
20+
throw new RuntimeException("interrupted");
21+
}
22+
value = 42;
23+
}
24+
}
25+
26+
private static class Failing {
27+
static int value;
28+
29+
static {
30+
failingOwnerStarted = true;
31+
while (!failingWaiterStarted) {
32+
Thread.yield();
33+
}
34+
try {
35+
Thread.sleep(10);
36+
} catch (InterruptedException exception) {
37+
throw new RuntimeException("interrupted");
38+
}
39+
if (failingOwnerStarted) {
40+
throw new RuntimeException("initialization failed");
41+
}
42+
}
43+
}
44+
45+
private static class SuccessfulReader implements Runnable {
46+
private final boolean waiter;
47+
int value;
48+
49+
SuccessfulReader(boolean waiter) {
50+
this.waiter = waiter;
51+
}
52+
53+
public void run() {
54+
if (waiter) {
55+
successfulWaiterStarted = true;
56+
}
57+
value = Successful.value;
58+
}
59+
}
60+
61+
private static class FailingReader implements Runnable {
62+
private final boolean waiter;
63+
String errorClass;
64+
65+
FailingReader(boolean waiter) {
66+
this.waiter = waiter;
67+
}
68+
69+
public void run() {
70+
if (waiter) {
71+
failingWaiterStarted = true;
72+
}
73+
try {
74+
int ignored = Failing.value;
75+
} catch (Throwable throwable) {
76+
errorClass = throwable.getClass().getName();
77+
}
78+
}
79+
}
80+
81+
public static void main(String[] args) throws Exception {
82+
SuccessfulReader successfulOwner = new SuccessfulReader(false);
83+
Thread successfulOwnerThread = new Thread(successfulOwner);
84+
successfulOwnerThread.start();
85+
while (!successfulOwnerStarted) {
86+
Thread.yield();
87+
}
88+
89+
SuccessfulReader successfulWaiter = new SuccessfulReader(true);
90+
Thread successfulWaiterThread = new Thread(successfulWaiter);
91+
successfulWaiterThread.start();
92+
successfulOwnerThread.join();
93+
successfulWaiterThread.join();
94+
95+
System.out.println(successfulOwner.value);
96+
System.out.println(successfulWaiter.value);
97+
System.out.println(Successful.initializationCount);
98+
99+
FailingReader failingOwner = new FailingReader(false);
100+
Thread failingOwnerThread = new Thread(failingOwner);
101+
failingOwnerThread.start();
102+
while (!failingOwnerStarted) {
103+
Thread.yield();
104+
}
105+
106+
FailingReader failingWaiter = new FailingReader(true);
107+
Thread failingWaiterThread = new Thread(failingWaiter);
108+
failingWaiterThread.start();
109+
failingOwnerThread.join();
110+
failingWaiterThread.join();
111+
112+
System.out.println(failingOwner.errorClass);
113+
System.out.println(failingWaiter.errorClass);
114+
try {
115+
int ignored = Failing.value;
116+
} catch (Throwable throwable) {
117+
System.out.println(throwable.getClass().getName());
118+
}
119+
}
120+
}

0 commit comments

Comments
 (0)