Skip to content

Commit 9c2bd57

Browse files
committed
Add cross-context assertions to randoms.
1 parent 230fe25 commit 9c2bd57

4 files changed

Lines changed: 70 additions & 5 deletions

File tree

randomizedtesting-jupiter/src/main/java/com/carrotsearch/randomizedtesting/jupiter/AssertingRandom.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.carrotsearch.randomizedtesting.jupiter;
22

3+
import java.io.Closeable;
34
import java.util.Locale;
45
import java.util.Objects;
56
import java.util.Random;
@@ -8,7 +9,7 @@
89
* A {@link Random} with a delegate, preventing {@link Random#setSeed(long)} and locked to only be
910
* usable by a single {@link Thread}.
1011
*/
11-
final class AssertingRandom extends Random {
12+
final class AssertingRandom extends Random implements Closeable {
1213
private final Random delegate;
1314
private final Thread ownerRef;
1415
private final String ownerName;
@@ -23,7 +24,7 @@ final class AssertingRandom extends Random {
2324

2425
/**
2526
* Creates an instance to be used by <code>owner</code> thread and delegating to <code>delegate
26-
* </code> until {@link #destroy()}ed.
27+
* </code> until {@link #close()}ed.
2728
*/
2829
public AssertingRandom(Thread owner, Random delegate) {
2930
// Must be here, the only Random constructor. Has side effects on setSeed, see below.
@@ -118,7 +119,7 @@ public int hashCode() {
118119
}
119120

120121
/** This object will no longer be usable after this method is called. */
121-
void destroy() {
122+
public void close() {
122123
this.valid = false;
123124
}
124125

randomizedtesting-jupiter/src/main/java/com/carrotsearch/randomizedtesting/jupiter/RandomizedContext.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
package com.carrotsearch.randomizedtesting.jupiter;
22

3+
import java.io.Closeable;
4+
import java.io.IOException;
35
import java.util.ArrayList;
46
import java.util.Collections;
57
import java.util.Objects;
68
import java.util.Random;
79
import org.junit.jupiter.api.extension.ExtensionContext;
810

9-
public final class RandomizedContext {
11+
public final class RandomizedContext implements Closeable {
1012
private final RandomizedContext parent;
1113
private final Seed seed;
1214
final String contextId;
@@ -83,4 +85,11 @@ RandomizedContext deriveNew(ExtensionContext extensionContext) {
8385
return new RandomizedContext(
8486
extensionContext.getUniqueId(), this, randomFactory, nextSeed, firstAndRest.rest());
8587
}
88+
89+
@Override
90+
public void close() throws IOException {
91+
if (random instanceof Closeable c) {
92+
c.close();
93+
}
94+
}
8695
}

randomizedtesting-jupiter/src/test/java/com/carrotsearch/randomizedtesting/jupiter/F003_RandomInjection.java

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import org.junit.jupiter.api.Nested;
2121
import org.junit.jupiter.api.Test;
2222
import org.junit.jupiter.api.TestFactory;
23+
import org.junit.jupiter.api.TestInstance;
2324

2425
/** Verifies that {@link java.util.Random} instances are properly injected as parameters. */
2526
public class F003_RandomInjection {
@@ -135,7 +136,11 @@ void testMethod(PrintWriter pw, Random rnd) {
135136
class TestRandomAssertions {
136137
@Test
137138
public void testAllHooks() {
138-
collectExecutionResults(testKitBuilder(T1.class))
139+
collectExecutionResults(
140+
testKitBuilder(T1.class)
141+
.configurationParameter(
142+
RandomizedContextSupplier.SysProps.TESTS_RANDOM_ASSERTING.propertyKey,
143+
"true"))
139144
.results()
140145
.allEvents()
141146
.assertThatEvents()
@@ -165,5 +170,45 @@ void testMethod(Random random) throws Exception {
165170
.hasMessageContaining("This Random instance is tied to thread");
166171
}
167172
}
173+
174+
@Test
175+
public void testAssertingRandomIsClosedAfterContext() {
176+
collectExecutionResults(
177+
testKitBuilder(T2.class)
178+
.configurationParameter(
179+
RandomizedContextSupplier.SysProps.TESTS_RANDOM_ASSERTING.propertyKey,
180+
"true"))
181+
.results()
182+
.allEvents()
183+
.assertThatEvents()
184+
.doNotHave(event(finishedWithFailure()));
185+
}
186+
187+
@Randomized
188+
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
189+
static class T2 extends IgnoreInStandaloneRuns {
190+
Random rnd;
191+
192+
@Test
193+
void testMethod1(Random random) throws Exception {
194+
check(random);
195+
}
196+
197+
@Test
198+
void testMethod2(Random random) throws Exception {
199+
check(random);
200+
}
201+
202+
private void check(Random random) {
203+
if (rnd == null) {
204+
rnd = random;
205+
} else {
206+
Assertions.assertThat(rnd).isNotSameAs(random);
207+
Assertions.assertThatCode(() -> rnd.nextLong())
208+
.isExactlyInstanceOf(RuntimeException.class)
209+
.hasMessageContaining("This Random instance has been invalidated");
210+
}
211+
}
212+
}
168213
}
169214
}

randomizedtesting-jupiter/src/test/java/com/carrotsearch/randomizedtesting/jupiter/F003_RandomInjection.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,16 @@ public class TestClass {
1717

1818
The injected `Random` is initialized with the context's seed.
1919

20+
* It should be possible to pick (via system properties or JUnit5 configuratoin
21+
parameters) different `Random` implementations for the
22+
injected parameter. Lockless or those providing larger state space than
23+
the default `java.util.Random`.
24+
25+
* The injected `Random` is tied to the thread that created it. When
26+
assertions are enabled (or an explicit parameter is set), the injected
27+
Random instances should verify they are indeed used from within the
28+
right thread.
29+
2030
## Migration notes (from randomizedtesting for junit4)
2131

2232
This is new functionality, it wasn't available before.

0 commit comments

Comments
 (0)