| /* | |
| * Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved. | |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| * | |
| * This code is free software; you can redistribute it and/or modify it | |
| * under the terms of the GNU General Public License version 2 only, as | |
| * published by the Free Software Foundation. | |
| * | |
| * This code is distributed in the hope that it will be useful, but WITHOUT | |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| * version 2 for more details (a copy is included in the LICENSE file that | |
| * accompanied this code). | |
| * | |
| * You should have received a copy of the GNU General Public License version | |
| * 2 along with this work; if not, write to the Free Software Foundation, | |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| * | |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| * or visit www.oracle.com if you need additional information or have any | |
| * questions. | |
| */ | |
| import java.util.Random; | |
| import java.util.concurrent.atomic.AtomicInteger; | |
| import java.util.concurrent.atomic.LongAdder; | |
| import java.util.function.BiConsumer; | |
| import java.util.random.RandomGenerator; | |
| import java.util.ArrayList; | |
| import java.util.Collections; | |
| import org.testng.annotations.Test; | |
| import static org.testng.Assert.*; | |
| /** | |
| * @test | |
| * @run testng RandomTest | |
| * @summary test methods on Random | |
| * @bug 8288596 | |
| * @key randomness | |
| */ | |
| @Test | |
| public class RandomTest { | |
| // Note: this test was adapted from the 166 TCK ThreadLocalRandomTest test | |
| // and modified to be a TestNG test | |
| /* | |
| * Testing coverage notes: | |
| * | |
| * We don't test randomness properties, but only that repeated | |
| * calls, up to NCALLS tries, produce at least one different | |
| * result. For bounded versions, we sample various intervals | |
| * across multiples of primes. | |
| */ | |
| // max numbers of calls to detect getting stuck on one value | |
| static final int NCALLS = 10000; | |
| // max sampled int bound | |
| static final int MAX_INT_BOUND = (1 << 28); | |
| // max sampled long bound | |
| static final long MAX_LONG_BOUND = (1L << 42); | |
| // Number of replications for other checks | |
| static final int REPS = 20; | |
| /** | |
| * Repeated calls to nextInt produce at least two distinct results | |
| */ | |
| public void testNextInt() { | |
| Random r = new Random(); | |
| int f = r.nextInt(); | |
| int i = 0; | |
| while (i < NCALLS && r.nextInt() == f) | |
| ++i; | |
| assertTrue(i < NCALLS); | |
| } | |
| /** | |
| * Repeated calls to nextLong produce at least two distinct results | |
| */ | |
| public void testNextLong() { | |
| Random r = new Random(); | |
| long f = r.nextLong(); | |
| int i = 0; | |
| while (i < NCALLS && r.nextLong() == f) | |
| ++i; | |
| assertTrue(i < NCALLS); | |
| } | |
| /** | |
| * Repeated calls to nextBoolean produce at least two distinct results | |
| */ | |
| public void testNextBoolean() { | |
| Random r = new Random(); | |
| boolean f = r.nextBoolean(); | |
| int i = 0; | |
| while (i < NCALLS && r.nextBoolean() == f) | |
| ++i; | |
| assertTrue(i < NCALLS); | |
| } | |
| /** | |
| * Repeated calls to nextFloat produce at least two distinct results | |
| */ | |
| public void testNextFloat() { | |
| Random r = new Random(); | |
| float f = r.nextFloat(); | |
| int i = 0; | |
| while (i < NCALLS && r.nextFloat() == f) | |
| ++i; | |
| assertTrue(i < NCALLS); | |
| } | |
| /** | |
| * Repeated calls to nextDouble produce at least two distinct results | |
| */ | |
| public void testNextDouble() { | |
| Random r = new Random(); | |
| double f = r.nextDouble(); | |
| int i = 0; | |
| while (i < NCALLS && r.nextDouble() == f) | |
| ++i; | |
| assertTrue(i < NCALLS); | |
| } | |
| /** | |
| * Repeated calls to nextGaussian produce at least two distinct results | |
| */ | |
| public void testNextGaussian() { | |
| Random r = new Random(); | |
| double f = r.nextGaussian(); | |
| int i = 0; | |
| while (i < NCALLS && r.nextGaussian() == f) | |
| ++i; | |
| assertTrue(i < NCALLS); | |
| } | |
| /** | |
| * nextInt(negative) throws IllegalArgumentException | |
| */ | |
| @Test(expectedExceptions = IllegalArgumentException.class) | |
| public void testNextIntBoundedNeg() { | |
| Random r = new Random(); | |
| int f = r.nextInt(-17); | |
| } | |
| /** | |
| * nextInt(bound) returns 0 <= value < bound; repeated calls produce at | |
| * least two distinct results | |
| */ | |
| public void testNextIntBounded() { | |
| Random r = new Random(); | |
| // sample bound space across prime number increments | |
| for (int bound = 2; bound < MAX_INT_BOUND; bound += 524959) { | |
| int f = r.nextInt(bound); | |
| assertTrue(0 <= f && f < bound); | |
| int i = 0; | |
| int j; | |
| while (i < NCALLS && | |
| (j = r.nextInt(bound)) == f) { | |
| assertTrue(0 <= j && j < bound); | |
| ++i; | |
| } | |
| assertTrue(i < NCALLS); | |
| } | |
| } | |
| /** | |
| * Invoking sized ints, long, doubles, with negative sizes throws | |
| * IllegalArgumentException | |
| */ | |
| public void testBadStreamSize() { | |
| Random r = new Random(); | |
| assertThrowsIAE(() -> r.ints(-1L)); | |
| assertThrowsIAE(() -> r.ints(-1L, 2, 3)); | |
| assertThrowsIAE(() -> r.longs(-1L)); | |
| assertThrowsIAE(() -> r.longs(-1L, -1L, 1L)); | |
| assertThrowsIAE(() -> r.doubles(-1L)); | |
| assertThrowsIAE(() -> r.doubles(-1L, .5, .6)); | |
| } | |
| /** | |
| * Invoking bounded ints, long, doubles, with illegal bounds throws | |
| * IllegalArgumentException | |
| */ | |
| public void testBadStreamBounds() { | |
| Random r = new Random(); | |
| assertThrowsIAE(() -> r.ints(2, 1)); | |
| assertThrowsIAE(() -> r.ints(10, 42, 42)); | |
| assertThrowsIAE(() -> r.longs(-1L, -1L)); | |
| assertThrowsIAE(() -> r.longs(10, 1L, -2L)); | |
| testDoubleBadOriginBound((o, b) -> r.doubles(10, o, b)); | |
| } | |
| // An arbitrary finite double value | |
| static final double FINITE = Math.PI; | |
| void testDoubleBadOriginBound(BiConsumer<Double, Double> bi) { | |
| assertThrowsIAE(() -> bi.accept(17.0, 2.0)); | |
| assertThrowsIAE(() -> bi.accept(0.0, 0.0)); | |
| assertThrowsIAE(() -> bi.accept(Double.NaN, FINITE)); | |
| assertThrowsIAE(() -> bi.accept(FINITE, Double.NaN)); | |
| assertThrowsIAE(() -> bi.accept(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY)); | |
| // Returns NaN | |
| // assertThrowsIAE(() -> bi.accept(Double.NEGATIVE_INFINITY, FINITE)); | |
| // assertThrowsIAE(() -> bi.accept(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY)); | |
| assertThrowsIAE(() -> bi.accept(FINITE, Double.NEGATIVE_INFINITY)); | |
| // Returns Double.MAX_VALUE | |
| // assertThrowsIAE(() -> bi.accept(FINITE, Double.POSITIVE_INFINITY)); | |
| assertThrowsIAE(() -> bi.accept(Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY)); | |
| assertThrowsIAE(() -> bi.accept(Double.POSITIVE_INFINITY, FINITE)); | |
| assertThrowsIAE(() -> bi.accept(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY)); | |
| } | |
| private void assertThrowsIAE(ThrowingRunnable r) { | |
| assertThrows(IllegalArgumentException.class, r); | |
| } | |
| /** | |
| * A sequential sized stream of ints generates the given number of values | |
| */ | |
| public void testIntsCount() { | |
| LongAdder counter = new LongAdder(); | |
| Random r = new Random(); | |
| long size = 0; | |
| for (int reps = 0; reps < REPS; ++reps) { | |
| counter.reset(); | |
| r.ints(size).forEach(x -> { | |
| counter.increment(); | |
| }); | |
| assertEquals(counter.sum(), size); | |
| size += 524959; | |
| } | |
| } | |
| /** | |
| * A sequential sized stream of longs generates the given number of values | |
| */ | |
| public void testLongsCount() { | |
| LongAdder counter = new LongAdder(); | |
| Random r = new Random(); | |
| long size = 0; | |
| for (int reps = 0; reps < REPS; ++reps) { | |
| counter.reset(); | |
| r.longs(size).forEach(x -> { | |
| counter.increment(); | |
| }); | |
| assertEquals(counter.sum(), size); | |
| size += 524959; | |
| } | |
| } | |
| /** | |
| * A sequential sized stream of doubles generates the given number of values | |
| */ | |
| public void testDoublesCount() { | |
| LongAdder counter = new LongAdder(); | |
| Random r = new Random(); | |
| long size = 0; | |
| for (int reps = 0; reps < REPS; ++reps) { | |
| counter.reset(); | |
| r.doubles(size).forEach(x -> { | |
| counter.increment(); | |
| }); | |
| assertEquals(counter.sum(), size); | |
| size += 524959; | |
| } | |
| } | |
| /** | |
| * Each of a sequential sized stream of bounded ints is within bounds | |
| */ | |
| public void testBoundedInts() { | |
| AtomicInteger fails = new AtomicInteger(0); | |
| Random r = new Random(); | |
| long size = 12345L; | |
| for (int least = -15485867; least < MAX_INT_BOUND; least += 524959) { | |
| for (int bound = least + 2; bound > least && bound < MAX_INT_BOUND; bound += 67867967) { | |
| final int lo = least, hi = bound; | |
| r.ints(size, lo, hi). | |
| forEach(x -> { | |
| if (x < lo || x >= hi) | |
| fails.getAndIncrement(); | |
| }); | |
| } | |
| } | |
| assertEquals(fails.get(), 0); | |
| } | |
| /** | |
| * Each of a sequential sized stream of bounded longs is within bounds | |
| */ | |
| public void testBoundedLongs() { | |
| AtomicInteger fails = new AtomicInteger(0); | |
| Random r = new Random(); | |
| long size = 123L; | |
| for (long least = -86028121; least < MAX_LONG_BOUND; least += 1982451653L) { | |
| for (long bound = least + 2; bound > least && bound < MAX_LONG_BOUND; bound += Math.abs(bound * 7919)) { | |
| final long lo = least, hi = bound; | |
| r.longs(size, lo, hi). | |
| forEach(x -> { | |
| if (x < lo || x >= hi) | |
| fails.getAndIncrement(); | |
| }); | |
| } | |
| } | |
| assertEquals(fails.get(), 0); | |
| } | |
| /** | |
| * Each of a sequential sized stream of bounded doubles is within bounds | |
| */ | |
| public void testBoundedDoubles() { | |
| AtomicInteger fails = new AtomicInteger(0); | |
| Random r = new Random(); | |
| long size = 456; | |
| for (double least = 0.00011; least < 1.0e20; least *= 9) { | |
| for (double bound = least * 1.0011; bound < 1.0e20; bound *= 17) { | |
| final double lo = least, hi = bound; | |
| r.doubles(size, lo, hi). | |
| forEach(x -> { | |
| if (x < lo || x >= hi) | |
| fails.getAndIncrement(); | |
| }); | |
| } | |
| } | |
| assertEquals(fails.get(), 0); | |
| } | |
| /** | |
| * A parallel unsized stream of ints generates at least 100 values | |
| */ | |
| public void testUnsizedIntsCount() { | |
| LongAdder counter = new LongAdder(); | |
| Random r = new Random(); | |
| long size = 100; | |
| r.ints().limit(size).parallel().forEach(x -> { | |
| counter.increment(); | |
| }); | |
| assertEquals(counter.sum(), size); | |
| } | |
| /** | |
| * A parallel unsized stream of longs generates at least 100 values | |
| */ | |
| public void testUnsizedLongsCount() { | |
| LongAdder counter = new LongAdder(); | |
| Random r = new Random(); | |
| long size = 100; | |
| r.longs().limit(size).parallel().forEach(x -> { | |
| counter.increment(); | |
| }); | |
| assertEquals(counter.sum(), size); | |
| } | |
| /** | |
| * A parallel unsized stream of doubles generates at least 100 values | |
| */ | |
| public void testUnsizedDoublesCount() { | |
| LongAdder counter = new LongAdder(); | |
| Random r = new Random(); | |
| long size = 100; | |
| r.doubles().limit(size).parallel().forEach(x -> { | |
| counter.increment(); | |
| }); | |
| assertEquals(counter.sum(), size); | |
| } | |
| /** | |
| * A sequential unsized stream of ints generates at least 100 values | |
| */ | |
| public void testUnsizedIntsCountSeq() { | |
| LongAdder counter = new LongAdder(); | |
| Random r = new Random(); | |
| long size = 100; | |
| r.ints().limit(size).forEach(x -> { | |
| counter.increment(); | |
| }); | |
| assertEquals(counter.sum(), size); | |
| } | |
| /** | |
| * A sequential unsized stream of longs generates at least 100 values | |
| */ | |
| public void testUnsizedLongsCountSeq() { | |
| LongAdder counter = new LongAdder(); | |
| Random r = new Random(); | |
| long size = 100; | |
| r.longs().limit(size).forEach(x -> { | |
| counter.increment(); | |
| }); | |
| assertEquals(counter.sum(), size); | |
| } | |
| /** | |
| * A sequential unsized stream of doubles generates at least 100 values | |
| */ | |
| public void testUnsizedDoublesCountSeq() { | |
| LongAdder counter = new LongAdder(); | |
| Random r = new Random(); | |
| long size = 100; | |
| r.doubles().limit(size).forEach(x -> { | |
| counter.increment(); | |
| }); | |
| assertEquals(counter.sum(), size); | |
| } | |
| /** | |
| * Test shuffling a list with Random.from() | |
| */ | |
| public void testShufflingList() { | |
| final var listTest = new ArrayList<Integer>(); | |
| final RandomGenerator randomGenerator = RandomGenerator.getDefault(); | |
| final Random random = Random.from(randomGenerator); | |
| for (int i = 0; i < 100; i++) { | |
| listTest.add(i * 2); | |
| } | |
| final var listCopy = new ArrayList<Integer>(listTest); | |
| Collections.shuffle(listCopy, random); | |
| assertFalse(listCopy.equals(listTest)); | |
| } | |
| /** | |
| * Test if Random.from returns this | |
| */ | |
| public void testRandomFromInstance() { | |
| final RandomGenerator randomGenerator = RandomGenerator.getDefault(); | |
| final Random randomInstance = Random.from(randomGenerator); | |
| // we wrap the same instance again | |
| final Random randomInstanceCopy = Random.from(randomInstance); | |
| assertSame(randomInstance, randomInstanceCopy); | |
| } | |
| private int delegationCount; | |
| private class RandomGen implements RandomGenerator { | |
| @Override | |
| public boolean isDeprecated() { | |
| delegationCount += 1; | |
| return RandomGenerator.super.isDeprecated(); | |
| } | |
| @Override | |
| public float nextFloat(float bound) { | |
| delegationCount += 1; | |
| return RandomGenerator.super.nextFloat(bound); | |
| } | |
| @Override | |
| public double nextDouble(double bound) { | |
| delegationCount += 1; | |
| return RandomGenerator.super.nextDouble(bound); | |
| } | |
| @Override | |
| public long nextLong() { | |
| return 0; | |
| } | |
| } | |
| /* | |
| * Test whether calls to methods inherited from RandomGenerator | |
| * are delegated to the instance returned by from(). | |
| * This is not a complete coverage, but simulates the reproducer | |
| * in issue JDK-8288596 | |
| */ | |
| public void testRandomFrom() { | |
| delegationCount = 0; | |
| var r = Random.from(new RandomGen()); | |
| r.isDeprecated(); | |
| r.nextFloat(1_000.0f); | |
| r.nextFloat(); // not implemented in RandomGen, does not count | |
| r.nextDouble(1_000.0); | |
| r.nextDouble(); // not implemented in RandomGen, does not count | |
| assertEquals(delegationCount, 3); | |
| } | |
| } |