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, 5 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

# User Rev Content
1 dl 1.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 jsr166 1.16
7 jsr166 1.22 import java.util.Arrays;
8     import java.util.List;
9 dl 1.1 import java.util.SplittableRandom;
10     import java.util.concurrent.atomic.AtomicInteger;
11     import java.util.concurrent.atomic.LongAdder;
12 jsr166 1.22 import java.lang.reflect.Method;
13     import java.util.function.Predicate;
14     import java.util.stream.Collectors;
15 jsr166 1.26 import java.util.stream.DoubleStream;
16     import java.util.stream.IntStream;
17     import java.util.stream.LongStream;
18 dl 1.1
19 jsr166 1.16 import junit.framework.Test;
20     import junit.framework.TestSuite;
21    
22 dl 1.1 public class SplittableRandomTest extends JSR166TestCase {
23    
24     public static void main(String[] args) {
25 jsr166 1.18 main(suite(), args);
26 dl 1.1 }
27     public static Test suite() {
28     return new TestSuite(SplittableRandomTest.class);
29     }
30    
31     /*
32     * Testing coverage notes:
33     *
34 jsr166 1.4 * 1. Many of the test methods are adapted from ThreadLocalRandomTest.
35 dl 1.1 *
36 jsr166 1.4 * 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 dl 1.1 */
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 jsr166 1.11 static final int MAX_INT_BOUND = (1 << 26);
52 dl 1.1
53 jsr166 1.4 // max sampled long bound
54 jsr166 1.12 static final long MAX_LONG_BOUND = (1L << 40);
55 dl 1.1
56     // Number of replications for other checks
57 jsr166 1.7 static final int REPS =
58     Integer.getInteger("SplittableRandomTest.reps", 4);
59 dl 1.1
60     /**
61 jsr166 1.4 * Repeated calls to nextInt produce at least two distinct results
62 dl 1.1 */
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 jsr166 1.4 * Repeated calls to nextLong produce at least two distinct results
74 dl 1.1 */
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 jsr166 1.4 * Repeated calls to nextDouble produce at least two distinct results
86 dl 1.1 */
87     public void testNextDouble() {
88     SplittableRandom sr = new SplittableRandom();
89     double f = sr.nextDouble();
90 jsr166 1.4 int i = 0;
91 dl 1.1 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 jsr166 1.14 for (long seed = 2; seed < MAX_LONG_BOUND; seed += 15485863) {
102 dl 1.1 SplittableRandom sr1 = new SplittableRandom(seed);
103     SplittableRandom sr2 = new SplittableRandom(seed);
104 jsr166 1.3 for (int i = 0; i < REPS; ++i)
105 dl 1.1 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 jsr166 1.9 * nextInt(non-positive) throws IllegalArgumentException
141 dl 1.1 */
142 jsr166 1.13 public void testNextIntBoundNonPositive() {
143 dl 1.1 SplittableRandom sr = new SplittableRandom();
144 jsr166 1.25 assertThrows(
145     IllegalArgumentException.class,
146 jsr166 1.9 () -> sr.nextInt(-17),
147     () -> sr.nextInt(0),
148 jsr166 1.25 () -> sr.nextInt(Integer.MIN_VALUE));
149 dl 1.1 }
150    
151     /**
152 jsr166 1.4 * nextInt(least >= bound) throws IllegalArgumentException
153 dl 1.1 */
154     public void testNextIntBadBounds() {
155     SplittableRandom sr = new SplittableRandom();
156 jsr166 1.25 assertThrows(
157     IllegalArgumentException.class,
158 jsr166 1.10 () -> sr.nextInt(17, 2),
159     () -> sr.nextInt(-42, -42),
160 jsr166 1.25 () -> sr.nextInt(Integer.MAX_VALUE, Integer.MIN_VALUE));
161 dl 1.1 }
162    
163     /**
164     * nextInt(bound) returns 0 <= value < bound;
165 jsr166 1.4 * repeated calls produce at least two distinct results
166 dl 1.1 */
167     public void testNextIntBounded() {
168     SplittableRandom sr = new SplittableRandom();
169 jsr166 1.19 for (int i = 0; i < 2; i++) assertEquals(0, sr.nextInt(1));
170 dl 1.1 // 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 jsr166 1.4 * repeated calls produce at least two distinct results
188 dl 1.1 */
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 jsr166 1.9 * nextLong(non-positive) throws IllegalArgumentException
209 dl 1.1 */
210 jsr166 1.13 public void testNextLongBoundNonPositive() {
211 dl 1.1 SplittableRandom sr = new SplittableRandom();
212 jsr166 1.25 assertThrows(
213     IllegalArgumentException.class,
214 jsr166 1.9 () -> sr.nextLong(-17L),
215     () -> sr.nextLong(0L),
216 jsr166 1.25 () -> sr.nextLong(Long.MIN_VALUE));
217 dl 1.1 }
218    
219     /**
220 jsr166 1.4 * nextLong(least >= bound) throws IllegalArgumentException
221 dl 1.1 */
222     public void testNextLongBadBounds() {
223     SplittableRandom sr = new SplittableRandom();
224 jsr166 1.25 assertThrows(
225     IllegalArgumentException.class,
226 jsr166 1.10 () -> sr.nextLong(17L, 2L),
227     () -> sr.nextLong(-42L, -42L),
228 jsr166 1.25 () -> sr.nextLong(Long.MAX_VALUE, Long.MIN_VALUE));
229 dl 1.1 }
230    
231     /**
232     * nextLong(bound) returns 0 <= value < bound;
233 jsr166 1.4 * repeated calls produce at least two distinct results
234 dl 1.1 */
235     public void testNextLongBounded() {
236     SplittableRandom sr = new SplittableRandom();
237 jsr166 1.19 for (int i = 0; i < 2; i++) assertEquals(0L, sr.nextLong(1L));
238 dl 1.1 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 jsr166 1.4 * repeated calls produce at least two distinct results
255 dl 1.1 */
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 jsr166 1.9 * nextDouble(non-positive) throws IllegalArgumentException
276     */
277 jsr166 1.13 public void testNextDoubleBoundNonPositive() {
278 jsr166 1.9 SplittableRandom sr = new SplittableRandom();
279 jsr166 1.25 assertThrows(
280     IllegalArgumentException.class,
281 jsr166 1.9 () -> sr.nextDouble(-17.0d),
282     () -> sr.nextDouble(0.0d),
283     () -> sr.nextDouble(-Double.MIN_VALUE),
284     () -> sr.nextDouble(Double.NEGATIVE_INFINITY),
285 jsr166 1.25 () -> sr.nextDouble(Double.NaN));
286 jsr166 1.9 }
287    
288     /**
289 jsr166 1.10 * nextDouble(! (least < bound)) throws IllegalArgumentException
290     */
291     public void testNextDoubleBadBounds() {
292     SplittableRandom sr = new SplittableRandom();
293 jsr166 1.25 assertThrows(
294     IllegalArgumentException.class,
295 jsr166 1.10 () -> 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 jsr166 1.25 () -> sr.nextDouble(0.0d, Double.NaN));
300 jsr166 1.10 }
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 dl 1.1 * nextDouble(least, bound) returns least <= value < bound;
308 jsr166 1.4 * repeated calls produce at least two distinct results
309 dl 1.1 */
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 jsr166 1.25 assertThrows(
335     IllegalArgumentException.class,
336 jsr166 1.26 () -> { 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 dl 1.1 }
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 jsr166 1.25 assertThrows(
351     IllegalArgumentException.class,
352 jsr166 1.26 () -> { 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 dl 1.1 }
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 jsr166 1.6 r.ints(size).parallel().forEach(x -> counter.increment());
370 jsr166 1.4 assertEquals(size, counter.sum());
371 dl 1.1 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 jsr166 1.6 r.longs(size).parallel().forEach(x -> counter.increment());
385 jsr166 1.4 assertEquals(size, counter.sum());
386 dl 1.1 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 jsr166 1.6 r.doubles(size).parallel().forEach(x -> counter.increment());
400 jsr166 1.4 assertEquals(size, counter.sum());
401 dl 1.1 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 jsr166 1.17 r.ints(size, lo, hi).parallel().forEach(
416     x -> {
417     if (x < lo || x >= hi)
418     fails.getAndIncrement(); });
419 dl 1.1 }
420     }
421 jsr166 1.4 assertEquals(0, fails.get());
422 dl 1.1 }
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 jsr166 1.17 r.longs(size, lo, hi).parallel().forEach(
435     x -> {
436     if (x < lo || x >= hi)
437     fails.getAndIncrement(); });
438 dl 1.1 }
439     }
440 jsr166 1.4 assertEquals(0, fails.get());
441 dl 1.1 }
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 jsr166 1.17 r.doubles(size, lo, hi).parallel().forEach(
454     x -> {
455     if (x < lo || x >= hi)
456     fails.getAndIncrement(); });
457 dl 1.1 }
458     }
459 jsr166 1.4 assertEquals(0, fails.get());
460 dl 1.1 }
461    
462 dl 1.2 /**
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 jsr166 1.6 r.ints().limit(size).parallel().forEach(x -> counter.increment());
470 jsr166 1.4 assertEquals(size, counter.sum());
471 dl 1.2 }
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 jsr166 1.6 r.longs().limit(size).parallel().forEach(x -> counter.increment());
481 jsr166 1.4 assertEquals(size, counter.sum());
482 dl 1.2 }
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 jsr166 1.6 r.doubles().limit(size).parallel().forEach(x -> counter.increment());
492 jsr166 1.4 assertEquals(size, counter.sum());
493 dl 1.2 }
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 jsr166 1.6 r.ints().limit(size).forEach(x -> counter.increment());
503 jsr166 1.4 assertEquals(size, counter.sum());
504 dl 1.2 }
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 jsr166 1.6 r.longs().limit(size).forEach(x -> counter.increment());
514 jsr166 1.4 assertEquals(size, counter.sum());
515 dl 1.2 }
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 jsr166 1.6 r.doubles().limit(size).forEach(x -> counter.increment());
525 jsr166 1.4 assertEquals(size, counter.sum());
526 dl 1.2 }
527    
528 jsr166 1.22 /**
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 jsr166 1.23 int n = sr.nextInt(1, 20);
560 jsr166 1.22 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 jsr166 1.23 /**
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 dl 1.1 }