ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/test/tck/SplittableRandomTest.java
Revision: 1.26
Committed: Mon Dec 16 22:55:54 2019 UTC (4 years, 4 months ago) by jsr166
Branch: MAIN
CVS Tags: HEAD
Changes since 1.25: +15 -12 lines
Log Message:
fix a few [UnusedVariable] warnings

File Contents

# Content
1 /*
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
7 import java.util.Arrays;
8 import java.util.List;
9 import java.util.SplittableRandom;
10 import java.util.concurrent.atomic.AtomicInteger;
11 import java.util.concurrent.atomic.LongAdder;
12 import java.lang.reflect.Method;
13 import java.util.function.Predicate;
14 import java.util.stream.Collectors;
15 import java.util.stream.DoubleStream;
16 import java.util.stream.IntStream;
17 import java.util.stream.LongStream;
18
19 import junit.framework.Test;
20 import junit.framework.TestSuite;
21
22 public class SplittableRandomTest extends JSR166TestCase {
23
24 public static void main(String[] args) {
25 main(suite(), args);
26 }
27 public static Test suite() {
28 return new TestSuite(SplittableRandomTest.class);
29 }
30
31 /*
32 * Testing coverage notes:
33 *
34 * 1. Many of the test methods are adapted from ThreadLocalRandomTest.
35 *
36 * 2. These tests do not check for random number generator quality.
37 * But we check for minimal API compliance by requiring that
38 * repeated calls to nextX methods, up to NCALLS tries, produce at
39 * least two distinct results. (In some possible universe, a
40 * "correct" implementation might fail, but the odds are vastly
41 * less than that of encountering a hardware failure while running
42 * the test.) For bounded nextX methods, we sample various
43 * intervals across multiples of primes. In other tests, we repeat
44 * under REPS different values.
45 */
46
47 // max numbers of calls to detect getting stuck on one value
48 static final int NCALLS = 10000;
49
50 // max sampled int bound
51 static final int MAX_INT_BOUND = (1 << 26);
52
53 // max sampled long bound
54 static final long MAX_LONG_BOUND = (1L << 40);
55
56 // Number of replications for other checks
57 static final int REPS =
58 Integer.getInteger("SplittableRandomTest.reps", 4);
59
60 /**
61 * Repeated calls to nextInt produce at least two distinct results
62 */
63 public void testNextInt() {
64 SplittableRandom sr = new SplittableRandom();
65 int f = sr.nextInt();
66 int i = 0;
67 while (i < NCALLS && sr.nextInt() == f)
68 ++i;
69 assertTrue(i < NCALLS);
70 }
71
72 /**
73 * Repeated calls to nextLong produce at least two distinct results
74 */
75 public void testNextLong() {
76 SplittableRandom sr = new SplittableRandom();
77 long f = sr.nextLong();
78 int i = 0;
79 while (i < NCALLS && sr.nextLong() == f)
80 ++i;
81 assertTrue(i < NCALLS);
82 }
83
84 /**
85 * Repeated calls to nextDouble produce at least two distinct results
86 */
87 public void testNextDouble() {
88 SplittableRandom sr = new SplittableRandom();
89 double f = sr.nextDouble();
90 int i = 0;
91 while (i < NCALLS && sr.nextDouble() == f)
92 ++i;
93 assertTrue(i < NCALLS);
94 }
95
96 /**
97 * Two SplittableRandoms created with the same seed produce the
98 * same values for nextLong.
99 */
100 public void testSeedConstructor() {
101 for (long seed = 2; seed < MAX_LONG_BOUND; seed += 15485863) {
102 SplittableRandom sr1 = new SplittableRandom(seed);
103 SplittableRandom sr2 = new SplittableRandom(seed);
104 for (int i = 0; i < REPS; ++i)
105 assertEquals(sr1.nextLong(), sr2.nextLong());
106 }
107 }
108
109 /**
110 * A SplittableRandom produced by split() of a default-constructed
111 * SplittableRandom generates a different sequence
112 */
113 public void testSplit1() {
114 SplittableRandom sr = new SplittableRandom();
115 for (int reps = 0; reps < REPS; ++reps) {
116 SplittableRandom sc = sr.split();
117 int i = 0;
118 while (i < NCALLS && sr.nextLong() == sc.nextLong())
119 ++i;
120 assertTrue(i < NCALLS);
121 }
122 }
123
124 /**
125 * A SplittableRandom produced by split() of a seeded-constructed
126 * SplittableRandom generates a different sequence
127 */
128 public void testSplit2() {
129 SplittableRandom sr = new SplittableRandom(12345);
130 for (int reps = 0; reps < REPS; ++reps) {
131 SplittableRandom sc = sr.split();
132 int i = 0;
133 while (i < NCALLS && sr.nextLong() == sc.nextLong())
134 ++i;
135 assertTrue(i < NCALLS);
136 }
137 }
138
139 /**
140 * nextInt(non-positive) throws IllegalArgumentException
141 */
142 public void testNextIntBoundNonPositive() {
143 SplittableRandom sr = new SplittableRandom();
144 assertThrows(
145 IllegalArgumentException.class,
146 () -> sr.nextInt(-17),
147 () -> sr.nextInt(0),
148 () -> sr.nextInt(Integer.MIN_VALUE));
149 }
150
151 /**
152 * nextInt(least >= bound) throws IllegalArgumentException
153 */
154 public void testNextIntBadBounds() {
155 SplittableRandom sr = new SplittableRandom();
156 assertThrows(
157 IllegalArgumentException.class,
158 () -> sr.nextInt(17, 2),
159 () -> sr.nextInt(-42, -42),
160 () -> sr.nextInt(Integer.MAX_VALUE, Integer.MIN_VALUE));
161 }
162
163 /**
164 * nextInt(bound) returns 0 <= value < bound;
165 * repeated calls produce at least two distinct results
166 */
167 public void testNextIntBounded() {
168 SplittableRandom sr = new SplittableRandom();
169 for (int i = 0; i < 2; i++) assertEquals(0, sr.nextInt(1));
170 // sample bound space across prime number increments
171 for (int bound = 2; bound < MAX_INT_BOUND; bound += 524959) {
172 int f = sr.nextInt(bound);
173 assertTrue(0 <= f && f < bound);
174 int i = 0;
175 int j;
176 while (i < NCALLS &&
177 (j = sr.nextInt(bound)) == f) {
178 assertTrue(0 <= j && j < bound);
179 ++i;
180 }
181 assertTrue(i < NCALLS);
182 }
183 }
184
185 /**
186 * nextInt(least, bound) returns least <= value < bound;
187 * repeated calls produce at least two distinct results
188 */
189 public void testNextIntBounded2() {
190 SplittableRandom sr = new SplittableRandom();
191 for (int least = -15485863; least < MAX_INT_BOUND; least += 524959) {
192 for (int bound = least + 2; bound > least && bound < MAX_INT_BOUND; bound += 49979687) {
193 int f = sr.nextInt(least, bound);
194 assertTrue(least <= f && f < bound);
195 int i = 0;
196 int j;
197 while (i < NCALLS &&
198 (j = sr.nextInt(least, bound)) == f) {
199 assertTrue(least <= j && j < bound);
200 ++i;
201 }
202 assertTrue(i < NCALLS);
203 }
204 }
205 }
206
207 /**
208 * nextLong(non-positive) throws IllegalArgumentException
209 */
210 public void testNextLongBoundNonPositive() {
211 SplittableRandom sr = new SplittableRandom();
212 assertThrows(
213 IllegalArgumentException.class,
214 () -> sr.nextLong(-17L),
215 () -> sr.nextLong(0L),
216 () -> sr.nextLong(Long.MIN_VALUE));
217 }
218
219 /**
220 * nextLong(least >= bound) throws IllegalArgumentException
221 */
222 public void testNextLongBadBounds() {
223 SplittableRandom sr = new SplittableRandom();
224 assertThrows(
225 IllegalArgumentException.class,
226 () -> sr.nextLong(17L, 2L),
227 () -> sr.nextLong(-42L, -42L),
228 () -> sr.nextLong(Long.MAX_VALUE, Long.MIN_VALUE));
229 }
230
231 /**
232 * nextLong(bound) returns 0 <= value < bound;
233 * repeated calls produce at least two distinct results
234 */
235 public void testNextLongBounded() {
236 SplittableRandom sr = new SplittableRandom();
237 for (int i = 0; i < 2; i++) assertEquals(0L, sr.nextLong(1L));
238 for (long bound = 2; bound < MAX_LONG_BOUND; bound += 15485863) {
239 long f = sr.nextLong(bound);
240 assertTrue(0 <= f && f < bound);
241 int i = 0;
242 long j;
243 while (i < NCALLS &&
244 (j = sr.nextLong(bound)) == f) {
245 assertTrue(0 <= j && j < bound);
246 ++i;
247 }
248 assertTrue(i < NCALLS);
249 }
250 }
251
252 /**
253 * nextLong(least, bound) returns least <= value < bound;
254 * repeated calls produce at least two distinct results
255 */
256 public void testNextLongBounded2() {
257 SplittableRandom sr = new SplittableRandom();
258 for (long least = -86028121; least < MAX_LONG_BOUND; least += 982451653L) {
259 for (long bound = least + 2; bound > least && bound < MAX_LONG_BOUND; bound += Math.abs(bound * 7919)) {
260 long f = sr.nextLong(least, bound);
261 assertTrue(least <= f && f < bound);
262 int i = 0;
263 long j;
264 while (i < NCALLS &&
265 (j = sr.nextLong(least, bound)) == f) {
266 assertTrue(least <= j && j < bound);
267 ++i;
268 }
269 assertTrue(i < NCALLS);
270 }
271 }
272 }
273
274 /**
275 * nextDouble(non-positive) throws IllegalArgumentException
276 */
277 public void testNextDoubleBoundNonPositive() {
278 SplittableRandom sr = new SplittableRandom();
279 assertThrows(
280 IllegalArgumentException.class,
281 () -> sr.nextDouble(-17.0d),
282 () -> sr.nextDouble(0.0d),
283 () -> sr.nextDouble(-Double.MIN_VALUE),
284 () -> sr.nextDouble(Double.NEGATIVE_INFINITY),
285 () -> sr.nextDouble(Double.NaN));
286 }
287
288 /**
289 * nextDouble(! (least < bound)) throws IllegalArgumentException
290 */
291 public void testNextDoubleBadBounds() {
292 SplittableRandom sr = new SplittableRandom();
293 assertThrows(
294 IllegalArgumentException.class,
295 () -> sr.nextDouble(17.0d, 2.0d),
296 () -> sr.nextDouble(-42.0d, -42.0d),
297 () -> sr.nextDouble(Double.MAX_VALUE, Double.MIN_VALUE),
298 () -> sr.nextDouble(Double.NaN, 0.0d),
299 () -> sr.nextDouble(0.0d, Double.NaN));
300 }
301
302 // TODO: Test infinite bounds!
303 //() -> sr.nextDouble(Double.NEGATIVE_INFINITY, 0.0d),
304 //() -> sr.nextDouble(0.0d, Double.POSITIVE_INFINITY),
305
306 /**
307 * nextDouble(least, bound) returns least <= value < bound;
308 * repeated calls produce at least two distinct results
309 */
310 public void testNextDoubleBounded2() {
311 SplittableRandom sr = new SplittableRandom();
312 for (double least = 0.0001; least < 1.0e20; least *= 8) {
313 for (double bound = least * 1.001; bound < 1.0e20; bound *= 16) {
314 double f = sr.nextDouble(least, bound);
315 assertTrue(least <= f && f < bound);
316 int i = 0;
317 double j;
318 while (i < NCALLS &&
319 (j = sr.nextDouble(least, bound)) == f) {
320 assertTrue(least <= j && j < bound);
321 ++i;
322 }
323 assertTrue(i < NCALLS);
324 }
325 }
326 }
327
328 /**
329 * Invoking sized ints, long, doubles, with negative sizes throws
330 * IllegalArgumentException
331 */
332 public void testBadStreamSize() {
333 SplittableRandom r = new SplittableRandom();
334 assertThrows(
335 IllegalArgumentException.class,
336 () -> { IntStream unused = r.ints(-1L); },
337 () -> { IntStream unused = r.ints(-1L, 2, 3); },
338 () -> { LongStream unused = r.longs(-1L); },
339 () -> { LongStream unused = r.longs(-1L, -1L, 1L); },
340 () -> { DoubleStream unused = r.doubles(-1L); },
341 () -> { DoubleStream unused = r.doubles(-1L, .5, .6); });
342 }
343
344 /**
345 * Invoking bounded ints, long, doubles, with illegal bounds throws
346 * IllegalArgumentException
347 */
348 public void testBadStreamBounds() {
349 SplittableRandom r = new SplittableRandom();
350 assertThrows(
351 IllegalArgumentException.class,
352 () -> { IntStream unused = r.ints(2, 1); },
353 () -> { IntStream unused = r.ints(10, 42, 42); },
354 () -> { LongStream unused = r.longs(-1L, -1L); },
355 () -> { LongStream unused = r.longs(10, 1L, -2L); },
356 () -> { DoubleStream unused = r.doubles(0.0, 0.0); },
357 () -> { DoubleStream unused = r.doubles(10, .5, .4); });
358 }
359
360 /**
361 * A parallel sized stream of ints generates the given number of values
362 */
363 public void testIntsCount() {
364 LongAdder counter = new LongAdder();
365 SplittableRandom r = new SplittableRandom();
366 long size = 0;
367 for (int reps = 0; reps < REPS; ++reps) {
368 counter.reset();
369 r.ints(size).parallel().forEach(x -> counter.increment());
370 assertEquals(size, counter.sum());
371 size += 524959;
372 }
373 }
374
375 /**
376 * A parallel sized stream of longs generates the given number of values
377 */
378 public void testLongsCount() {
379 LongAdder counter = new LongAdder();
380 SplittableRandom r = new SplittableRandom();
381 long size = 0;
382 for (int reps = 0; reps < REPS; ++reps) {
383 counter.reset();
384 r.longs(size).parallel().forEach(x -> counter.increment());
385 assertEquals(size, counter.sum());
386 size += 524959;
387 }
388 }
389
390 /**
391 * A parallel sized stream of doubles generates the given number of values
392 */
393 public void testDoublesCount() {
394 LongAdder counter = new LongAdder();
395 SplittableRandom r = new SplittableRandom();
396 long size = 0;
397 for (int reps = 0; reps < REPS; ++reps) {
398 counter.reset();
399 r.doubles(size).parallel().forEach(x -> counter.increment());
400 assertEquals(size, counter.sum());
401 size += 524959;
402 }
403 }
404
405 /**
406 * Each of a parallel sized stream of bounded ints is within bounds
407 */
408 public void testBoundedInts() {
409 AtomicInteger fails = new AtomicInteger(0);
410 SplittableRandom r = new SplittableRandom();
411 long size = 12345L;
412 for (int least = -15485867; least < MAX_INT_BOUND; least += 524959) {
413 for (int bound = least + 2; bound > least && bound < MAX_INT_BOUND; bound += 67867967) {
414 final int lo = least, hi = bound;
415 r.ints(size, lo, hi).parallel().forEach(
416 x -> {
417 if (x < lo || x >= hi)
418 fails.getAndIncrement(); });
419 }
420 }
421 assertEquals(0, fails.get());
422 }
423
424 /**
425 * Each of a parallel sized stream of bounded longs is within bounds
426 */
427 public void testBoundedLongs() {
428 AtomicInteger fails = new AtomicInteger(0);
429 SplittableRandom r = new SplittableRandom();
430 long size = 123L;
431 for (long least = -86028121; least < MAX_LONG_BOUND; least += 1982451653L) {
432 for (long bound = least + 2; bound > least && bound < MAX_LONG_BOUND; bound += Math.abs(bound * 7919)) {
433 final long lo = least, hi = bound;
434 r.longs(size, lo, hi).parallel().forEach(
435 x -> {
436 if (x < lo || x >= hi)
437 fails.getAndIncrement(); });
438 }
439 }
440 assertEquals(0, fails.get());
441 }
442
443 /**
444 * Each of a parallel sized stream of bounded doubles is within bounds
445 */
446 public void testBoundedDoubles() {
447 AtomicInteger fails = new AtomicInteger(0);
448 SplittableRandom r = new SplittableRandom();
449 long size = 456;
450 for (double least = 0.00011; least < 1.0e20; least *= 9) {
451 for (double bound = least * 1.0011; bound < 1.0e20; bound *= 17) {
452 final double lo = least, hi = bound;
453 r.doubles(size, lo, hi).parallel().forEach(
454 x -> {
455 if (x < lo || x >= hi)
456 fails.getAndIncrement(); });
457 }
458 }
459 assertEquals(0, fails.get());
460 }
461
462 /**
463 * A parallel unsized stream of ints generates at least 100 values
464 */
465 public void testUnsizedIntsCount() {
466 LongAdder counter = new LongAdder();
467 SplittableRandom r = new SplittableRandom();
468 long size = 100;
469 r.ints().limit(size).parallel().forEach(x -> counter.increment());
470 assertEquals(size, counter.sum());
471 }
472
473 /**
474 * A parallel unsized stream of longs generates at least 100 values
475 */
476 public void testUnsizedLongsCount() {
477 LongAdder counter = new LongAdder();
478 SplittableRandom r = new SplittableRandom();
479 long size = 100;
480 r.longs().limit(size).parallel().forEach(x -> counter.increment());
481 assertEquals(size, counter.sum());
482 }
483
484 /**
485 * A parallel unsized stream of doubles generates at least 100 values
486 */
487 public void testUnsizedDoublesCount() {
488 LongAdder counter = new LongAdder();
489 SplittableRandom r = new SplittableRandom();
490 long size = 100;
491 r.doubles().limit(size).parallel().forEach(x -> counter.increment());
492 assertEquals(size, counter.sum());
493 }
494
495 /**
496 * A sequential unsized stream of ints generates at least 100 values
497 */
498 public void testUnsizedIntsCountSeq() {
499 LongAdder counter = new LongAdder();
500 SplittableRandom r = new SplittableRandom();
501 long size = 100;
502 r.ints().limit(size).forEach(x -> counter.increment());
503 assertEquals(size, counter.sum());
504 }
505
506 /**
507 * A sequential unsized stream of longs generates at least 100 values
508 */
509 public void testUnsizedLongsCountSeq() {
510 LongAdder counter = new LongAdder();
511 SplittableRandom r = new SplittableRandom();
512 long size = 100;
513 r.longs().limit(size).forEach(x -> counter.increment());
514 assertEquals(size, counter.sum());
515 }
516
517 /**
518 * A sequential unsized stream of doubles generates at least 100 values
519 */
520 public void testUnsizedDoublesCountSeq() {
521 LongAdder counter = new LongAdder();
522 SplittableRandom r = new SplittableRandom();
523 long size = 100;
524 r.doubles().limit(size).forEach(x -> counter.increment());
525 assertEquals(size, counter.sum());
526 }
527
528 /**
529 * SplittableRandom should implement most of Random's public methods
530 */
531 public void testShouldImplementMostRandomMethods() throws Throwable {
532 Predicate<Method> wasForgotten = method -> {
533 String name = method.getName();
534 // some methods deliberately not implemented
535 if (name.equals("setSeed")) return false;
536 if (name.equals("nextFloat")) return false;
537 if (name.equals("nextGaussian")) return false;
538 try {
539 SplittableRandom.class.getMethod(
540 method.getName(), method.getParameterTypes());
541 } catch (ReflectiveOperationException ex) {
542 return true;
543 }
544 return false;
545 };
546 List<Method> forgotten =
547 Arrays.stream(java.util.Random.class.getMethods())
548 .filter(wasForgotten)
549 .collect(Collectors.toList());
550 if (!forgotten.isEmpty())
551 throw new AssertionError("Please implement: " + forgotten);
552 }
553
554 /**
555 * Repeated calls to nextBytes produce at least values of different signs for every byte
556 */
557 public void testNextBytes() {
558 SplittableRandom sr = new SplittableRandom();
559 int n = sr.nextInt(1, 20);
560 byte[] bytes = new byte[n];
561 outer:
562 for (int i = 0; i < n; i++) {
563 for (int tries = NCALLS; tries-->0; ) {
564 byte before = bytes[i];
565 sr.nextBytes(bytes);
566 byte after = bytes[i];
567 if (after * before < 0)
568 continue outer;
569 }
570 fail("not enough variation in random bytes");
571 }
572 }
573
574 /**
575 * Filling an empty array with random bytes succeeds without effect.
576 */
577 public void testNextBytes_emptyArray() {
578 new SplittableRandom().nextBytes(new byte[0]);
579 }
580
581 public void testNextBytes_nullArray() {
582 try {
583 new SplittableRandom().nextBytes(null);
584 shouldThrow();
585 } catch (NullPointerException success) {}
586 }
587
588 }