blob: 5d9f8943ea13011e265ff4eb6747d35c3f89642b [file] [log] [blame]
Calin Juravle8f0d92b2013-08-01 17:26:00 +01001/*
2 * Written by Doug Lea with assistance from members of JCP JSR-166
3 * Expert Group and released to the public domain, as explained at
4 * http://creativecommons.org/publicdomain/zero/1.0/
5 */
6
7package jsr166;
8
Calin Juravle8f0d92b2013-08-01 17:26:00 +01009import java.util.concurrent.ThreadLocalRandom;
10import java.util.concurrent.atomic.AtomicLong;
11import java.util.concurrent.atomic.AtomicReference;
12
Narayan Kamath8e9a0e92015-04-28 11:40:00 +010013import junit.framework.Test;
14import junit.framework.TestSuite;
15
Calin Juravle8f0d92b2013-08-01 17:26:00 +010016public class ThreadLocalRandomTest extends JSR166TestCase {
17
Narayan Kamath8e9a0e92015-04-28 11:40:00 +010018 // android-note: Removed because the CTS runner does a bad job of
19 // retrying tests that have suite() declarations.
20 //
21 // public static void main(String[] args) {
22 // main(suite(), args);
23 // }
24 // public static Test suite() {
Przemyslaw Szczepaniakb8b75112016-03-11 15:59:10 +000025 // return new TestSuite(ThreadLocalRandomTest.class);
Narayan Kamath8e9a0e92015-04-28 11:40:00 +010026 // }
27
Calin Juravle8f0d92b2013-08-01 17:26:00 +010028 /*
29 * Testing coverage notes:
30 *
31 * We don't test randomness properties, but only that repeated
32 * calls, up to NCALLS tries, produce at least one different
33 * result. For bounded versions, we sample various intervals
34 * across multiples of primes.
35 */
36
Narayan Kamath8e9a0e92015-04-28 11:40:00 +010037 // max numbers of calls to detect getting stuck on one value
Calin Juravle8f0d92b2013-08-01 17:26:00 +010038 static final int NCALLS = 10000;
39
40 // max sampled int bound
41 static final int MAX_INT_BOUND = (1 << 28);
42
Narayan Kamath8e9a0e92015-04-28 11:40:00 +010043 // max sampled long bound
Calin Juravle8f0d92b2013-08-01 17:26:00 +010044 static final long MAX_LONG_BOUND = (1L << 42);
45
Narayan Kamath8e9a0e92015-04-28 11:40:00 +010046 // Number of replications for other checks
47 static final int REPS = 20;
48
Calin Juravle8f0d92b2013-08-01 17:26:00 +010049 /**
50 * setSeed throws UnsupportedOperationException
51 */
52 public void testSetSeed() {
53 try {
54 ThreadLocalRandom.current().setSeed(17);
55 shouldThrow();
56 } catch (UnsupportedOperationException success) {}
57 }
58
59 /**
Narayan Kamath8e9a0e92015-04-28 11:40:00 +010060 * Repeated calls to nextInt produce at least two distinct results
Calin Juravle8f0d92b2013-08-01 17:26:00 +010061 */
62 public void testNextInt() {
63 int f = ThreadLocalRandom.current().nextInt();
64 int i = 0;
65 while (i < NCALLS && ThreadLocalRandom.current().nextInt() == f)
66 ++i;
67 assertTrue(i < NCALLS);
68 }
69
70 /**
Narayan Kamath8e9a0e92015-04-28 11:40:00 +010071 * Repeated calls to nextLong produce at least two distinct results
Calin Juravle8f0d92b2013-08-01 17:26:00 +010072 */
73 public void testNextLong() {
74 long f = ThreadLocalRandom.current().nextLong();
75 int i = 0;
76 while (i < NCALLS && ThreadLocalRandom.current().nextLong() == f)
77 ++i;
78 assertTrue(i < NCALLS);
79 }
80
81 /**
Narayan Kamath8e9a0e92015-04-28 11:40:00 +010082 * Repeated calls to nextBoolean produce at least two distinct results
Calin Juravle8f0d92b2013-08-01 17:26:00 +010083 */
84 public void testNextBoolean() {
85 boolean f = ThreadLocalRandom.current().nextBoolean();
86 int i = 0;
87 while (i < NCALLS && ThreadLocalRandom.current().nextBoolean() == f)
88 ++i;
89 assertTrue(i < NCALLS);
90 }
91
92 /**
Narayan Kamath8e9a0e92015-04-28 11:40:00 +010093 * Repeated calls to nextFloat produce at least two distinct results
Calin Juravle8f0d92b2013-08-01 17:26:00 +010094 */
95 public void testNextFloat() {
96 float f = ThreadLocalRandom.current().nextFloat();
97 int i = 0;
98 while (i < NCALLS && ThreadLocalRandom.current().nextFloat() == f)
99 ++i;
100 assertTrue(i < NCALLS);
101 }
102
103 /**
Narayan Kamath8e9a0e92015-04-28 11:40:00 +0100104 * Repeated calls to nextDouble produce at least two distinct results
Calin Juravle8f0d92b2013-08-01 17:26:00 +0100105 */
106 public void testNextDouble() {
107 double f = ThreadLocalRandom.current().nextDouble();
Narayan Kamath8e9a0e92015-04-28 11:40:00 +0100108 int i = 0;
Calin Juravle8f0d92b2013-08-01 17:26:00 +0100109 while (i < NCALLS && ThreadLocalRandom.current().nextDouble() == f)
110 ++i;
111 assertTrue(i < NCALLS);
112 }
113
114 /**
Narayan Kamath8e9a0e92015-04-28 11:40:00 +0100115 * Repeated calls to nextGaussian produce at least two distinct results
Calin Juravle8f0d92b2013-08-01 17:26:00 +0100116 */
117 public void testNextGaussian() {
118 double f = ThreadLocalRandom.current().nextGaussian();
119 int i = 0;
120 while (i < NCALLS && ThreadLocalRandom.current().nextGaussian() == f)
121 ++i;
122 assertTrue(i < NCALLS);
123 }
124
125 /**
Narayan Kamath8e9a0e92015-04-28 11:40:00 +0100126 * nextInt(non-positive) throws IllegalArgumentException
Calin Juravle8f0d92b2013-08-01 17:26:00 +0100127 */
Narayan Kamath8e9a0e92015-04-28 11:40:00 +0100128 public void testNextIntBoundNonPositive() {
129 ThreadLocalRandom rnd = ThreadLocalRandom.current();
130 for (int bound : new int[] { 0, -17, Integer.MIN_VALUE }) {
131 try {
132 rnd.nextInt(bound);
133 shouldThrow();
134 } catch (IllegalArgumentException success) {}
135 }
Calin Juravle8f0d92b2013-08-01 17:26:00 +0100136 }
137
138 /**
Narayan Kamath8e9a0e92015-04-28 11:40:00 +0100139 * nextInt(least >= bound) throws IllegalArgumentException
Calin Juravle8f0d92b2013-08-01 17:26:00 +0100140 */
141 public void testNextIntBadBounds() {
Narayan Kamath8e9a0e92015-04-28 11:40:00 +0100142 int[][] badBoundss = {
143 { 17, 2 },
144 { -42, -42 },
145 { Integer.MAX_VALUE, Integer.MIN_VALUE },
146 };
147 ThreadLocalRandom rnd = ThreadLocalRandom.current();
148 for (int[] badBounds : badBoundss) {
149 try {
150 rnd.nextInt(badBounds[0], badBounds[1]);
151 shouldThrow();
152 } catch (IllegalArgumentException success) {}
153 }
Calin Juravle8f0d92b2013-08-01 17:26:00 +0100154 }
155
156 /**
157 * nextInt(bound) returns 0 <= value < bound;
Narayan Kamath8e9a0e92015-04-28 11:40:00 +0100158 * repeated calls produce at least two distinct results
Calin Juravle8f0d92b2013-08-01 17:26:00 +0100159 */
160 public void testNextIntBounded() {
161 // sample bound space across prime number increments
162 for (int bound = 2; bound < MAX_INT_BOUND; bound += 524959) {
163 int f = ThreadLocalRandom.current().nextInt(bound);
164 assertTrue(0 <= f && f < bound);
165 int i = 0;
166 int j;
167 while (i < NCALLS &&
168 (j = ThreadLocalRandom.current().nextInt(bound)) == f) {
169 assertTrue(0 <= j && j < bound);
170 ++i;
171 }
172 assertTrue(i < NCALLS);
173 }
174 }
175
176 /**
177 * nextInt(least, bound) returns least <= value < bound;
Narayan Kamath8e9a0e92015-04-28 11:40:00 +0100178 * repeated calls produce at least two distinct results
Calin Juravle8f0d92b2013-08-01 17:26:00 +0100179 */
180 public void testNextIntBounded2() {
181 for (int least = -15485863; least < MAX_INT_BOUND; least += 524959) {
182 for (int bound = least + 2; bound > least && bound < MAX_INT_BOUND; bound += 49979687) {
183 int f = ThreadLocalRandom.current().nextInt(least, bound);
184 assertTrue(least <= f && f < bound);
185 int i = 0;
186 int j;
187 while (i < NCALLS &&
188 (j = ThreadLocalRandom.current().nextInt(least, bound)) == f) {
189 assertTrue(least <= j && j < bound);
190 ++i;
191 }
192 assertTrue(i < NCALLS);
193 }
194 }
195 }
196
197 /**
Narayan Kamath8e9a0e92015-04-28 11:40:00 +0100198 * nextLong(non-positive) throws IllegalArgumentException
Calin Juravle8f0d92b2013-08-01 17:26:00 +0100199 */
Narayan Kamath8e9a0e92015-04-28 11:40:00 +0100200 public void testNextLongBoundNonPositive() {
201 ThreadLocalRandom rnd = ThreadLocalRandom.current();
202 for (long bound : new long[] { 0L, -17L, Long.MIN_VALUE }) {
203 try {
204 rnd.nextLong(bound);
205 shouldThrow();
206 } catch (IllegalArgumentException success) {}
207 }
Calin Juravle8f0d92b2013-08-01 17:26:00 +0100208 }
209
210 /**
Narayan Kamath8e9a0e92015-04-28 11:40:00 +0100211 * nextLong(least >= bound) throws IllegalArgumentException
Calin Juravle8f0d92b2013-08-01 17:26:00 +0100212 */
213 public void testNextLongBadBounds() {
Narayan Kamath8e9a0e92015-04-28 11:40:00 +0100214 long[][] badBoundss = {
215 { 17L, 2L },
216 { -42L, -42L },
217 { Long.MAX_VALUE, Long.MIN_VALUE },
218 };
219 ThreadLocalRandom rnd = ThreadLocalRandom.current();
220 for (long[] badBounds : badBoundss) {
221 try {
222 rnd.nextLong(badBounds[0], badBounds[1]);
223 shouldThrow();
224 } catch (IllegalArgumentException success) {}
225 }
Calin Juravle8f0d92b2013-08-01 17:26:00 +0100226 }
227
228 /**
229 * nextLong(bound) returns 0 <= value < bound;
Narayan Kamath8e9a0e92015-04-28 11:40:00 +0100230 * repeated calls produce at least two distinct results
Calin Juravle8f0d92b2013-08-01 17:26:00 +0100231 */
232 public void testNextLongBounded() {
233 for (long bound = 2; bound < MAX_LONG_BOUND; bound += 15485863) {
234 long f = ThreadLocalRandom.current().nextLong(bound);
235 assertTrue(0 <= f && f < bound);
236 int i = 0;
237 long j;
238 while (i < NCALLS &&
239 (j = ThreadLocalRandom.current().nextLong(bound)) == f) {
240 assertTrue(0 <= j && j < bound);
241 ++i;
242 }
243 assertTrue(i < NCALLS);
244 }
245 }
246
247 /**
248 * nextLong(least, bound) returns least <= value < bound;
Narayan Kamath8e9a0e92015-04-28 11:40:00 +0100249 * repeated calls produce at least two distinct results
Calin Juravle8f0d92b2013-08-01 17:26:00 +0100250 */
251 public void testNextLongBounded2() {
252 for (long least = -86028121; least < MAX_LONG_BOUND; least += 982451653L) {
253 for (long bound = least + 2; bound > least && bound < MAX_LONG_BOUND; bound += Math.abs(bound * 7919)) {
254 long f = ThreadLocalRandom.current().nextLong(least, bound);
255 assertTrue(least <= f && f < bound);
256 int i = 0;
257 long j;
258 while (i < NCALLS &&
259 (j = ThreadLocalRandom.current().nextLong(least, bound)) == f) {
260 assertTrue(least <= j && j < bound);
261 ++i;
262 }
263 assertTrue(i < NCALLS);
264 }
265 }
266 }
267
268 /**
Narayan Kamath8e9a0e92015-04-28 11:40:00 +0100269 * nextDouble(non-positive) throws IllegalArgumentException
270 */
271 public void testNextDoubleBoundNonPositive() {
272 ThreadLocalRandom rnd = ThreadLocalRandom.current();
273 double[] badBounds = {
274 0.0d,
275 -17.0d,
276 -Double.MIN_VALUE,
277 Double.NEGATIVE_INFINITY,
278 Double.NaN,
279 };
280 for (double bound : badBounds) {
281 try {
282 rnd.nextDouble(bound);
283 shouldThrow();
284 } catch (IllegalArgumentException success) {}
285 }
286 }
287
288 /**
Calin Juravle8f0d92b2013-08-01 17:26:00 +0100289 * nextDouble(least, bound) returns least <= value < bound;
Narayan Kamath8e9a0e92015-04-28 11:40:00 +0100290 * repeated calls produce at least two distinct results
Calin Juravle8f0d92b2013-08-01 17:26:00 +0100291 */
292 public void testNextDoubleBounded2() {
293 for (double least = 0.0001; least < 1.0e20; least *= 8) {
294 for (double bound = least * 1.001; bound < 1.0e20; bound *= 16) {
295 double f = ThreadLocalRandom.current().nextDouble(least, bound);
296 assertTrue(least <= f && f < bound);
297 int i = 0;
298 double j;
299 while (i < NCALLS &&
300 (j = ThreadLocalRandom.current().nextDouble(least, bound)) == f) {
301 assertTrue(least <= j && j < bound);
302 ++i;
303 }
304 assertTrue(i < NCALLS);
305 }
306 }
307 }
308
309 /**
310 * Different threads produce different pseudo-random sequences
311 */
312 public void testDifferentSequences() {
313 // Don't use main thread's ThreadLocalRandom - it is likely to
314 // be polluted by previous tests.
315 final AtomicReference<ThreadLocalRandom> threadLocalRandom =
316 new AtomicReference<ThreadLocalRandom>();
317 final AtomicLong rand = new AtomicLong();
318
319 long firstRand = 0;
320 ThreadLocalRandom firstThreadLocalRandom = null;
321
Narayan Kamath8e9a0e92015-04-28 11:40:00 +0100322 Runnable getRandomState = new CheckedRunnable() {
Calin Juravle8f0d92b2013-08-01 17:26:00 +0100323 public void realRun() {
324 ThreadLocalRandom current = ThreadLocalRandom.current();
325 assertSame(current, ThreadLocalRandom.current());
326 // test bug: the following is not guaranteed and not true in JDK8
327 // assertNotSame(current, threadLocalRandom.get());
328 rand.set(current.nextLong());
329 threadLocalRandom.set(current);
330 }};
331
332 Thread first = newStartedThread(getRandomState);
333 awaitTermination(first);
334 firstRand = rand.get();
335 firstThreadLocalRandom = threadLocalRandom.get();
336
337 for (int i = 0; i < NCALLS; i++) {
338 Thread t = newStartedThread(getRandomState);
339 awaitTermination(t);
340 if (firstRand != rand.get())
341 return;
342 }
343 fail("all threads generate the same pseudo-random sequence");
344 }
345
346}