• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3  *
4  * This code is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License version 2 only, as
6  * published by the Free Software Foundation.
7  *
8  * This code is distributed in the hope that it will be useful, but WITHOUT
9  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
11  * version 2 for more details (a copy is included in the LICENSE file that
12  * accompanied this code).
13  *
14  * You should have received a copy of the GNU General Public License version
15  * 2 along with this work; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
17  *
18  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
19  * or visit www.oracle.com if you need additional information or have any
20  * questions.
21  */
22 
23 /*
24  * This file is available under and governed by the GNU General Public
25  * License version 2 only, as published by the Free Software Foundation.
26  * However, the following notice accompanied the original version of this
27  * file:
28  *
29  * Written by Doug Lea with assistance from members of JCP JSR-166
30  * Expert Group and released to the public domain, as explained at
31  * http://creativecommons.org/publicdomain/zero/1.0/
32  */
33 
34 package test.java.util.concurrent.tck;
35 
36 import static org.junit.Assert.assertEquals;
37 import static org.junit.Assert.assertFalse;
38 import static org.junit.Assert.assertNull;
39 import static org.junit.Assert.assertNotNull;
40 import static org.junit.Assert.assertSame;
41 import static org.junit.Assert.assertNotSame;
42 import static org.junit.Assert.assertTrue;
43 import static org.junit.Assert.fail;
44 
45 import java.lang.reflect.Modifier;
46 import java.util.Arrays;
47 import java.util.List;
48 import java.util.SplittableRandom;
49 import java.util.concurrent.atomic.AtomicInteger;
50 import java.util.concurrent.atomic.LongAdder;
51 import java.lang.reflect.Method;
52 import java.util.function.Predicate;
53 import java.util.stream.Collectors;
54 import java.util.stream.DoubleStream;
55 import java.util.stream.IntStream;
56 import java.util.stream.LongStream;
57 
58 import org.junit.Test;
59 import org.junit.runner.RunWith;
60 import org.junit.runners.JUnit4;
61 
62 // Android-changed: Use JUnit4.
63 @RunWith(JUnit4.class)
64 public class SplittableRandomTest extends JSR166TestCase {
65 
66     // Android-changed: Use JUnitCore.main.
main(String[] args)67     public static void main(String[] args) {
68         // main(suite(), args);
69         org.junit.runner.JUnitCore.main("test.java.util.concurrent.tck.SplittableRandomTest");
70     }
71     // public static Test suite() {
72     //     return new TestSuite(SplittableRandomTest.class);
73     // }
74 
75     /*
76      * Testing coverage notes:
77      *
78      * 1. Many of the test methods are adapted from ThreadLocalRandomTest.
79      *
80      * 2. These tests do not check for random number generator quality.
81      * But we check for minimal API compliance by requiring that
82      * repeated calls to nextX methods, up to NCALLS tries, produce at
83      * least two distinct results. (In some possible universe, a
84      * "correct" implementation might fail, but the odds are vastly
85      * less than that of encountering a hardware failure while running
86      * the test.) For bounded nextX methods, we sample various
87      * intervals across multiples of primes. In other tests, we repeat
88      * under REPS different values.
89      */
90 
91     // max numbers of calls to detect getting stuck on one value
92     static final int NCALLS = 10000;
93 
94     // max sampled int bound
95     static final int MAX_INT_BOUND = (1 << 26);
96 
97     // max sampled long bound
98     static final long MAX_LONG_BOUND = (1L << 40);
99 
100     // Number of replications for other checks
101     static final int REPS =
102         Integer.getInteger("SplittableRandomTest.reps", 4);
103 
104     /**
105      * Repeated calls to nextInt produce at least two distinct results
106      */
107     @Test
testNextInt()108     public void testNextInt() {
109         SplittableRandom sr = new SplittableRandom();
110         int f = sr.nextInt();
111         int i = 0;
112         while (i < NCALLS && sr.nextInt() == f)
113             ++i;
114         assertTrue(i < NCALLS);
115     }
116 
117     /**
118      * Repeated calls to nextLong produce at least two distinct results
119      */
120     @Test
121     public void testNextLong() {
122         SplittableRandom sr = new SplittableRandom();
123         long f = sr.nextLong();
124         int i = 0;
125         while (i < NCALLS && sr.nextLong() == f)
126             ++i;
127         assertTrue(i < NCALLS);
128     }
129 
130     /**
131      * Repeated calls to nextDouble produce at least two distinct results
132      */
133     @Test
134     public void testNextDouble() {
135         SplittableRandom sr = new SplittableRandom();
136         double f = sr.nextDouble();
137         int i = 0;
138         while (i < NCALLS && sr.nextDouble() == f)
139             ++i;
140         assertTrue(i < NCALLS);
141     }
142 
143     /**
144      * Two SplittableRandoms created with the same seed produce the
145      * same values for nextLong.
146      */
147     @Test
148     public void testSeedConstructor() {
149         for (long seed = 2; seed < MAX_LONG_BOUND; seed += 15485863) {
150             SplittableRandom sr1 = new SplittableRandom(seed);
151             SplittableRandom sr2 = new SplittableRandom(seed);
152             for (int i = 0; i < REPS; ++i)
153                 assertEquals(sr1.nextLong(), sr2.nextLong());
154         }
155     }
156 
157     /**
158      * A SplittableRandom produced by split() of a default-constructed
159      * SplittableRandom generates a different sequence
160      */
161     @Test
162     public void testSplit1() {
163         SplittableRandom sr = new SplittableRandom();
164         for (int reps = 0; reps < REPS; ++reps) {
165             SplittableRandom sc = sr.split();
166             int i = 0;
167             while (i < NCALLS && sr.nextLong() == sc.nextLong())
168                 ++i;
169             assertTrue(i < NCALLS);
170         }
171     }
172 
173     /**
174      * A SplittableRandom produced by split() of a seeded-constructed
175      * SplittableRandom generates a different sequence
176      */
177     @Test
178     public void testSplit2() {
179         SplittableRandom sr = new SplittableRandom(12345);
180         for (int reps = 0; reps < REPS; ++reps) {
181             SplittableRandom sc = sr.split();
182             int i = 0;
183             while (i < NCALLS && sr.nextLong() == sc.nextLong())
184                 ++i;
185             assertTrue(i < NCALLS);
186         }
187     }
188 
189     /**
190      * nextInt(non-positive) throws IllegalArgumentException
191      */
192     @Test
193     public void testNextIntBoundNonPositive() {
194         SplittableRandom sr = new SplittableRandom();
195         assertThrows(
196             IllegalArgumentException.class,
197             () -> sr.nextInt(-17),
198             () -> sr.nextInt(0),
199             () -> sr.nextInt(Integer.MIN_VALUE));
200     }
201 
202     /**
203      * nextInt(least >= bound) throws IllegalArgumentException
204      */
205     @Test
206     public void testNextIntBadBounds() {
207         SplittableRandom sr = new SplittableRandom();
208         assertThrows(
209             IllegalArgumentException.class,
210             () -> sr.nextInt(17, 2),
211             () -> sr.nextInt(-42, -42),
212             () -> sr.nextInt(Integer.MAX_VALUE, Integer.MIN_VALUE));
213     }
214 
215     /**
216      * nextInt(bound) returns 0 <= value < bound;
217      * repeated calls produce at least two distinct results
218      */
219     @Test
220     public void testNextIntBounded() {
221         SplittableRandom sr = new SplittableRandom();
222         for (int i = 0; i < 2; i++) assertEquals(0, sr.nextInt(1));
223         // sample bound space across prime number increments
224         for (int bound = 2; bound < MAX_INT_BOUND; bound += 524959) {
225             int f = sr.nextInt(bound);
226             assertTrue(0 <= f && f < bound);
227             int i = 0;
228             int j;
229             while (i < NCALLS &&
230                    (j = sr.nextInt(bound)) == f) {
231                 assertTrue(0 <= j && j < bound);
232                 ++i;
233             }
234             assertTrue(i < NCALLS);
235         }
236     }
237 
238     /**
239      * nextInt(least, bound) returns least <= value < bound;
240      * repeated calls produce at least two distinct results
241      */
242     @Test
243     public void testNextIntBounded2() {
244         SplittableRandom sr = new SplittableRandom();
245         for (int least = -15485863; least < MAX_INT_BOUND; least += 524959) {
246             for (int bound = least + 2; bound > least && bound < MAX_INT_BOUND; bound += 49979687) {
247                 int f = sr.nextInt(least, bound);
248                 assertTrue(least <= f && f < bound);
249                 int i = 0;
250                 int j;
251                 while (i < NCALLS &&
252                        (j = sr.nextInt(least, bound)) == f) {
253                     assertTrue(least <= j && j < bound);
254                     ++i;
255                 }
256                 assertTrue(i < NCALLS);
257             }
258         }
259     }
260 
261     /**
262      * nextLong(non-positive) throws IllegalArgumentException
263      */
264     @Test
265     public void testNextLongBoundNonPositive() {
266         SplittableRandom sr = new SplittableRandom();
267         assertThrows(
268             IllegalArgumentException.class,
269             () -> sr.nextLong(-17L),
270             () -> sr.nextLong(0L),
271             () -> sr.nextLong(Long.MIN_VALUE));
272     }
273 
274     /**
275      * nextLong(least >= bound) throws IllegalArgumentException
276      */
277     @Test
278     public void testNextLongBadBounds() {
279         SplittableRandom sr = new SplittableRandom();
280         assertThrows(
281             IllegalArgumentException.class,
282             () -> sr.nextLong(17L, 2L),
283             () -> sr.nextLong(-42L, -42L),
284             () -> sr.nextLong(Long.MAX_VALUE, Long.MIN_VALUE));
285     }
286 
287     /**
288      * nextLong(bound) returns 0 <= value < bound;
289      * repeated calls produce at least two distinct results
290      */
291     @Test
292     public void testNextLongBounded() {
293         SplittableRandom sr = new SplittableRandom();
294         for (int i = 0; i < 2; i++) assertEquals(0L, sr.nextLong(1L));
295         for (long bound = 2; bound < MAX_LONG_BOUND; bound += 15485863) {
296             long f = sr.nextLong(bound);
297             assertTrue(0 <= f && f < bound);
298             int i = 0;
299             long j;
300             while (i < NCALLS &&
301                    (j = sr.nextLong(bound)) == f) {
302                 assertTrue(0 <= j && j < bound);
303                 ++i;
304             }
305             assertTrue(i < NCALLS);
306         }
307     }
308 
309     /**
310      * nextLong(least, bound) returns least <= value < bound;
311      * repeated calls produce at least two distinct results
312      */
313     @Test
314     public void testNextLongBounded2() {
315         SplittableRandom sr = new SplittableRandom();
316         for (long least = -86028121; least < MAX_LONG_BOUND; least += 982451653L) {
317             for (long bound = least + 2; bound > least && bound < MAX_LONG_BOUND; bound += Math.abs(bound * 7919)) {
318                 long f = sr.nextLong(least, bound);
319                 assertTrue(least <= f && f < bound);
320                 int i = 0;
321                 long j;
322                 while (i < NCALLS &&
323                        (j = sr.nextLong(least, bound)) == f) {
324                     assertTrue(least <= j && j < bound);
325                     ++i;
326                 }
327                 assertTrue(i < NCALLS);
328             }
329         }
330     }
331 
332     /**
333      * nextDouble(non-positive) throws IllegalArgumentException
334      */
335     @Test
336     public void testNextDoubleBoundNonPositive() {
337         SplittableRandom sr = new SplittableRandom();
338         assertThrows(
339             IllegalArgumentException.class,
340             () -> sr.nextDouble(-17.0d),
341             () -> sr.nextDouble(0.0d),
342             () -> sr.nextDouble(-Double.MIN_VALUE),
343             () -> sr.nextDouble(Double.NEGATIVE_INFINITY),
344             () -> sr.nextDouble(Double.NaN));
345     }
346 
347     /**
348      * nextDouble(! (least < bound)) throws IllegalArgumentException
349      */
350     @Test
351     public void testNextDoubleBadBounds() {
352         SplittableRandom sr = new SplittableRandom();
353         assertThrows(
354             IllegalArgumentException.class,
355             () -> sr.nextDouble(17.0d, 2.0d),
356             () -> sr.nextDouble(-42.0d, -42.0d),
357             () -> sr.nextDouble(Double.MAX_VALUE, Double.MIN_VALUE),
358             () -> sr.nextDouble(Double.NaN, 0.0d),
359             () -> sr.nextDouble(0.0d, Double.NaN));
360     }
361 
362     // TODO: Test infinite bounds!
363     //() -> sr.nextDouble(Double.NEGATIVE_INFINITY, 0.0d),
364     //() -> sr.nextDouble(0.0d, Double.POSITIVE_INFINITY),
365 
366     /**
367      * nextDouble(least, bound) returns least <= value < bound;
368      * repeated calls produce at least two distinct results
369      */
370     @Test
371     public void testNextDoubleBounded2() {
372         SplittableRandom sr = new SplittableRandom();
373         for (double least = 0.0001; least < 1.0e20; least *= 8) {
374             for (double bound = least * 1.001; bound < 1.0e20; bound *= 16) {
375                 double f = sr.nextDouble(least, bound);
376                 assertTrue(least <= f && f < bound);
377                 int i = 0;
378                 double j;
379                 while (i < NCALLS &&
380                        (j = sr.nextDouble(least, bound)) == f) {
381                     assertTrue(least <= j && j < bound);
382                     ++i;
383                 }
384                 assertTrue(i < NCALLS);
385             }
386         }
387     }
388 
389     /**
390      * Invoking sized ints, long, doubles, with negative sizes throws
391      * IllegalArgumentException
392      */
393     @Test
394     public void testBadStreamSize() {
395         SplittableRandom r = new SplittableRandom();
396         assertThrows(
397             IllegalArgumentException.class,
398             () -> { IntStream unused = r.ints(-1L); },
399             () -> { IntStream unused = r.ints(-1L, 2, 3); },
400             () -> { LongStream unused = r.longs(-1L); },
401             () -> { LongStream unused = r.longs(-1L, -1L, 1L); },
402             () -> { DoubleStream unused = r.doubles(-1L); },
403             () -> { DoubleStream unused = r.doubles(-1L, .5, .6); });
404     }
405 
406     /**
407      * Invoking bounded ints, long, doubles, with illegal bounds throws
408      * IllegalArgumentException
409      */
410     @Test
411     public void testBadStreamBounds() {
412         SplittableRandom r = new SplittableRandom();
413         assertThrows(
414             IllegalArgumentException.class,
415             () -> { IntStream unused = r.ints(2, 1); },
416             () -> { IntStream unused = r.ints(10, 42, 42); },
417             () -> { LongStream unused = r.longs(-1L, -1L); },
418             () -> { LongStream unused = r.longs(10, 1L, -2L); },
419             () -> { DoubleStream unused = r.doubles(0.0, 0.0); },
420             () -> { DoubleStream unused = r.doubles(10, .5, .4); });
421     }
422 
423     /**
424      * A parallel sized stream of ints generates the given number of values
425      */
426     @Test
427     public void testIntsCount() {
428         LongAdder counter = new LongAdder();
429         SplittableRandom r = new SplittableRandom();
430         long size = 0;
431         for (int reps = 0; reps < REPS; ++reps) {
432             counter.reset();
433             r.ints(size).parallel().forEach(x -> counter.increment());
434             assertEquals(size, counter.sum());
435             size += 524959;
436         }
437     }
438 
439     /**
440      * A parallel sized stream of longs generates the given number of values
441      */
442     @Test
443     public void testLongsCount() {
444         LongAdder counter = new LongAdder();
445         SplittableRandom r = new SplittableRandom();
446         long size = 0;
447         for (int reps = 0; reps < REPS; ++reps) {
448             counter.reset();
449             r.longs(size).parallel().forEach(x -> counter.increment());
450             assertEquals(size, counter.sum());
451             size += 524959;
452         }
453     }
454 
455     /**
456      * A parallel sized stream of doubles generates the given number of values
457      */
458     @Test
459     public void testDoublesCount() {
460         LongAdder counter = new LongAdder();
461         SplittableRandom r = new SplittableRandom();
462         long size = 0;
463         for (int reps = 0; reps < REPS; ++reps) {
464             counter.reset();
465             r.doubles(size).parallel().forEach(x -> counter.increment());
466             assertEquals(size, counter.sum());
467             size += 524959;
468         }
469     }
470 
471     /**
472      * Each of a parallel sized stream of bounded ints is within bounds
473      */
474     @Test
475     public void testBoundedInts() {
476         AtomicInteger fails = new AtomicInteger(0);
477         SplittableRandom r = new SplittableRandom();
478         long size = 12345L;
479         for (int least = -15485867; least < MAX_INT_BOUND; least += 524959) {
480             for (int bound = least + 2; bound > least && bound < MAX_INT_BOUND; bound += 67867967) {
481                 final int lo = least, hi = bound;
482                 r.ints(size, lo, hi).parallel().forEach(
483                     x -> {
484                         if (x < lo || x >= hi)
485                             fails.getAndIncrement(); });
486             }
487         }
488         assertEquals(0, fails.get());
489     }
490 
491     /**
492      * Each of a parallel sized stream of bounded longs is within bounds
493      */
494     @Test
495     public void testBoundedLongs() {
496         AtomicInteger fails = new AtomicInteger(0);
497         SplittableRandom r = new SplittableRandom();
498         long size = 123L;
499         for (long least = -86028121; least < MAX_LONG_BOUND; least += 1982451653L) {
500             for (long bound = least + 2; bound > least && bound < MAX_LONG_BOUND; bound += Math.abs(bound * 7919)) {
501                 final long lo = least, hi = bound;
502                 r.longs(size, lo, hi).parallel().forEach(
503                     x -> {
504                         if (x < lo || x >= hi)
505                             fails.getAndIncrement(); });
506             }
507         }
508         assertEquals(0, fails.get());
509     }
510 
511     /**
512      * Each of a parallel sized stream of bounded doubles is within bounds
513      */
514     @Test
515     public void testBoundedDoubles() {
516         AtomicInteger fails = new AtomicInteger(0);
517         SplittableRandom r = new SplittableRandom();
518         long size = 456;
519         for (double least = 0.00011; least < 1.0e20; least *= 9) {
520             for (double bound = least * 1.0011; bound < 1.0e20; bound *= 17) {
521                 final double lo = least, hi = bound;
522                 r.doubles(size, lo, hi).parallel().forEach(
523                     x -> {
524                         if (x < lo || x >= hi)
525                             fails.getAndIncrement(); });
526             }
527         }
528         assertEquals(0, fails.get());
529     }
530 
531     /**
532      * A parallel unsized stream of ints generates at least 100 values
533      */
534     @Test
535     public void testUnsizedIntsCount() {
536         LongAdder counter = new LongAdder();
537         SplittableRandom r = new SplittableRandom();
538         long size = 100;
539         r.ints().limit(size).parallel().forEach(x -> counter.increment());
540         assertEquals(size, counter.sum());
541     }
542 
543     /**
544      * A parallel unsized stream of longs generates at least 100 values
545      */
546     @Test
547     public void testUnsizedLongsCount() {
548         LongAdder counter = new LongAdder();
549         SplittableRandom r = new SplittableRandom();
550         long size = 100;
551         r.longs().limit(size).parallel().forEach(x -> counter.increment());
552         assertEquals(size, counter.sum());
553     }
554 
555     /**
556      * A parallel unsized stream of doubles generates at least 100 values
557      */
558     @Test
559     public void testUnsizedDoublesCount() {
560         LongAdder counter = new LongAdder();
561         SplittableRandom r = new SplittableRandom();
562         long size = 100;
563         r.doubles().limit(size).parallel().forEach(x -> counter.increment());
564         assertEquals(size, counter.sum());
565     }
566 
567     /**
568      * A sequential unsized stream of ints generates at least 100 values
569      */
570     @Test
571     public void testUnsizedIntsCountSeq() {
572         LongAdder counter = new LongAdder();
573         SplittableRandom r = new SplittableRandom();
574         long size = 100;
575         r.ints().limit(size).forEach(x -> counter.increment());
576         assertEquals(size, counter.sum());
577     }
578 
579     /**
580      * A sequential unsized stream of longs generates at least 100 values
581      */
582     @Test
583     public void testUnsizedLongsCountSeq() {
584         LongAdder counter = new LongAdder();
585         SplittableRandom r = new SplittableRandom();
586         long size = 100;
587         r.longs().limit(size).forEach(x -> counter.increment());
588         assertEquals(size, counter.sum());
589     }
590 
591     /**
592      * A sequential unsized stream of doubles generates at least 100 values
593      */
594     @Test
595     public void testUnsizedDoublesCountSeq() {
596         LongAdder counter = new LongAdder();
597         SplittableRandom r = new SplittableRandom();
598         long size = 100;
599         r.doubles().limit(size).forEach(x -> counter.increment());
600         assertEquals(size, counter.sum());
601     }
602 
603     /**
604      * SplittableRandom should implement most of Random's public methods
605      */
606     @Test
607     public void testShouldImplementMostRandomMethods() throws Throwable {
608         Predicate<Method> wasForgotten = method -> {
609             String name = method.getName();
610             // some methods deliberately not implemented
611             if (name.equals("setSeed")) return false;
612             if (name.equals("nextFloat")) return false;
613             if (name.equals("nextGaussian")) return false;
614 
615             // Android-added: ignore methods added by r8.
616             if (method.isSynthetic()) {
617                 return false;
618             }
619 
620             try {
621                 SplittableRandom.class.getMethod(
622                     method.getName(), method.getParameterTypes());
623             } catch (ReflectiveOperationException ex) {
624                 return true;
625             }
626             return false;
627         };
628         List<Method> forgotten =
629             Arrays.stream(java.util.Random.class.getMethods())
630             .filter(method -> (method.getModifiers() & Modifier.STATIC) == 0)
631             .filter(wasForgotten)
632             .collect(Collectors.toList());
633         if (!forgotten.isEmpty())
634             throw new AssertionError("Please implement: " + forgotten);
635     }
636 
637     /**
638      * Repeated calls to nextBytes produce at least values of different signs for every byte
639      */
640     @Test
641     public void testNextBytes() {
642         SplittableRandom sr = new SplittableRandom();
643         int n = sr.nextInt(1, 20);
644         byte[] bytes = new byte[n];
645         outer:
646         for (int i = 0; i < n; i++) {
647             for (int tries = NCALLS; tries-->0; ) {
648                 byte before = bytes[i];
649                 sr.nextBytes(bytes);
650                 byte after = bytes[i];
651                 if (after * before < 0)
652                     continue outer;
653             }
654             fail("not enough variation in random bytes");
655         }
656     }
657 
658     /**
659      * Filling an empty array with random bytes succeeds without effect.
660      */
661     @Test
662     public void testNextBytes_emptyArray() {
663         new SplittableRandom().nextBytes(new byte[0]);
664     }
665 
666     @Test
667     public void testNextBytes_nullArray() {
668         try {
669             new SplittableRandom().nextBytes(null);
670             shouldThrow();
671         } catch (NullPointerException success) {}
672     }
673 
674 }
675