ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/test/tck/SplittableRandomTest.java
Revision: 1.22
Committed: Tue Oct 3 22:27:04 2017 UTC (6 years, 7 months ago) by jsr166
Branch: MAIN
Changes since 1.21: +52 -0 lines
Log Message:
8188047: Add SplittableRandom.nextBytes

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