1 /* 2 * Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 package test.java.util.Random; 25 26 import java.util.Random; 27 import java.util.concurrent.atomic.AtomicInteger; 28 import java.util.concurrent.atomic.LongAdder; 29 import java.util.function.BiConsumer; 30 import java.util.random.RandomGenerator; 31 import java.util.ArrayList; 32 import java.util.Collections; 33 34 import org.testng.annotations.Test; 35 36 import static org.testng.Assert.*; 37 38 /** 39 * @test 40 * @run testng RandomTest 41 * @summary test methods on Random 42 * @bug 8288596 43 * @key randomness 44 */ 45 @Test 46 public class RandomTest { 47 48 // Note: this test was adapted from the 166 TCK ThreadLocalRandomTest test 49 // and modified to be a TestNG test 50 51 /* 52 * Testing coverage notes: 53 * 54 * We don't test randomness properties, but only that repeated 55 * calls, up to NCALLS tries, produce at least one different 56 * result. For bounded versions, we sample various intervals 57 * across multiples of primes. 58 */ 59 60 // max numbers of calls to detect getting stuck on one value 61 static final int NCALLS = 10000; 62 63 // max sampled int bound 64 static final int MAX_INT_BOUND = (1 << 28); 65 66 // max sampled long bound 67 static final long MAX_LONG_BOUND = (1L << 42); 68 69 // Number of replications for other checks 70 // Android-changed: takes too much time to run on certain targets. 71 // static final int REPS = 20; 72 static final int REPS = 5; 73 74 /** 75 * Repeated calls to nextInt produce at least two distinct results 76 */ testNextInt()77 public void testNextInt() { 78 Random r = new Random(); 79 int f = r.nextInt(); 80 int i = 0; 81 while (i < NCALLS && r.nextInt() == f) 82 ++i; 83 assertTrue(i < NCALLS); 84 } 85 86 /** 87 * Repeated calls to nextLong produce at least two distinct results 88 */ 89 public void testNextLong() { 90 Random r = new Random(); 91 long f = r.nextLong(); 92 int i = 0; 93 while (i < NCALLS && r.nextLong() == f) 94 ++i; 95 assertTrue(i < NCALLS); 96 } 97 98 /** 99 * Repeated calls to nextBoolean produce at least two distinct results 100 */ 101 public void testNextBoolean() { 102 Random r = new Random(); 103 boolean f = r.nextBoolean(); 104 int i = 0; 105 while (i < NCALLS && r.nextBoolean() == f) 106 ++i; 107 assertTrue(i < NCALLS); 108 } 109 110 /** 111 * Repeated calls to nextFloat produce at least two distinct results 112 */ 113 public void testNextFloat() { 114 Random r = new Random(); 115 float f = r.nextFloat(); 116 int i = 0; 117 while (i < NCALLS && r.nextFloat() == f) 118 ++i; 119 assertTrue(i < NCALLS); 120 } 121 122 /** 123 * Repeated calls to nextDouble produce at least two distinct results 124 */ 125 public void testNextDouble() { 126 Random r = new Random(); 127 double f = r.nextDouble(); 128 int i = 0; 129 while (i < NCALLS && r.nextDouble() == f) 130 ++i; 131 assertTrue(i < NCALLS); 132 } 133 134 /** 135 * Repeated calls to nextGaussian produce at least two distinct results 136 */ 137 public void testNextGaussian() { 138 Random r = new Random(); 139 double f = r.nextGaussian(); 140 int i = 0; 141 while (i < NCALLS && r.nextGaussian() == f) 142 ++i; 143 assertTrue(i < NCALLS); 144 } 145 146 /** 147 * nextInt(negative) throws IllegalArgumentException 148 */ 149 @Test(expectedExceptions = IllegalArgumentException.class) 150 public void testNextIntBoundedNeg() { 151 Random r = new Random(); 152 int f = r.nextInt(-17); 153 } 154 155 /** 156 * nextInt(bound) returns 0 <= value < bound; repeated calls produce at 157 * least two distinct results 158 */ 159 public void testNextIntBounded() { 160 Random r = new Random(); 161 // sample bound space across prime number increments 162 for (int bound = 2; bound < MAX_INT_BOUND; bound += 524959) { 163 int f = r.nextInt(bound); 164 assertTrue(0 <= f && f < bound); 165 int i = 0; 166 int j; 167 while (i < NCALLS && 168 (j = r.nextInt(bound)) == f) { 169 assertTrue(0 <= j && j < bound); 170 ++i; 171 } 172 assertTrue(i < NCALLS); 173 } 174 } 175 176 /** 177 * Invoking sized ints, long, doubles, with negative sizes throws 178 * IllegalArgumentException 179 */ 180 public void testBadStreamSize() { 181 Random r = new Random(); 182 assertThrowsIAE(() -> r.ints(-1L)); 183 assertThrowsIAE(() -> r.ints(-1L, 2, 3)); 184 assertThrowsIAE(() -> r.longs(-1L)); 185 assertThrowsIAE(() -> r.longs(-1L, -1L, 1L)); 186 assertThrowsIAE(() -> r.doubles(-1L)); 187 assertThrowsIAE(() -> r.doubles(-1L, .5, .6)); 188 } 189 190 /** 191 * Invoking bounded ints, long, doubles, with illegal bounds throws 192 * IllegalArgumentException 193 */ 194 public void testBadStreamBounds() { 195 Random r = new Random(); 196 assertThrowsIAE(() -> r.ints(2, 1)); 197 assertThrowsIAE(() -> r.ints(10, 42, 42)); 198 assertThrowsIAE(() -> r.longs(-1L, -1L)); 199 assertThrowsIAE(() -> r.longs(10, 1L, -2L)); 200 201 testDoubleBadOriginBound((o, b) -> r.doubles(10, o, b)); 202 } 203 204 // An arbitrary finite double value 205 static final double FINITE = Math.PI; 206 207 void testDoubleBadOriginBound(BiConsumer<Double, Double> bi) { 208 assertThrowsIAE(() -> bi.accept(17.0, 2.0)); 209 assertThrowsIAE(() -> bi.accept(0.0, 0.0)); 210 assertThrowsIAE(() -> bi.accept(Double.NaN, FINITE)); 211 assertThrowsIAE(() -> bi.accept(FINITE, Double.NaN)); 212 assertThrowsIAE(() -> bi.accept(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY)); 213 214 // Returns NaN 215 // assertThrowsIAE(() -> bi.accept(Double.NEGATIVE_INFINITY, FINITE)); 216 // assertThrowsIAE(() -> bi.accept(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY)); 217 218 assertThrowsIAE(() -> bi.accept(FINITE, Double.NEGATIVE_INFINITY)); 219 220 // Returns Double.MAX_VALUE 221 // assertThrowsIAE(() -> bi.accept(FINITE, Double.POSITIVE_INFINITY)); 222 223 assertThrowsIAE(() -> bi.accept(Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY)); 224 assertThrowsIAE(() -> bi.accept(Double.POSITIVE_INFINITY, FINITE)); 225 assertThrowsIAE(() -> bi.accept(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY)); 226 } 227 assertThrowsIAE(ThrowingRunnable r)228 private void assertThrowsIAE(ThrowingRunnable r) { 229 assertThrows(IllegalArgumentException.class, r); 230 } 231 232 /** 233 * A sequential sized stream of ints generates the given number of values 234 */ testIntsCount()235 public void testIntsCount() { 236 LongAdder counter = new LongAdder(); 237 Random r = new Random(); 238 long size = 0; 239 for (int reps = 0; reps < REPS; ++reps) { 240 counter.reset(); 241 r.ints(size).forEach(x -> { 242 counter.increment(); 243 }); 244 assertEquals(counter.sum(), size); 245 size += 524959; 246 } 247 } 248 249 /** 250 * A sequential sized stream of longs generates the given number of values 251 */ testLongsCount()252 public void testLongsCount() { 253 LongAdder counter = new LongAdder(); 254 Random r = new Random(); 255 long size = 0; 256 for (int reps = 0; reps < REPS; ++reps) { 257 counter.reset(); 258 r.longs(size).forEach(x -> { 259 counter.increment(); 260 }); 261 assertEquals(counter.sum(), size); 262 size += 524959; 263 } 264 } 265 266 /** 267 * A sequential sized stream of doubles generates the given number of values 268 */ testDoublesCount()269 public void testDoublesCount() { 270 LongAdder counter = new LongAdder(); 271 Random r = new Random(); 272 long size = 0; 273 for (int reps = 0; reps < REPS; ++reps) { 274 counter.reset(); 275 r.doubles(size).forEach(x -> { 276 counter.increment(); 277 }); 278 assertEquals(counter.sum(), size); 279 size += 524959; 280 } 281 } 282 283 /** 284 * Each of a sequential sized stream of bounded ints is within bounds 285 */ testBoundedInts()286 public void testBoundedInts() { 287 AtomicInteger fails = new AtomicInteger(0); 288 Random r = new Random(); 289 long size = 12345L; 290 for (int least = -15485867; least < MAX_INT_BOUND; least += 524959) { 291 for (int bound = least + 2; bound > least && bound < MAX_INT_BOUND; bound += 67867967) { 292 final int lo = least, hi = bound; 293 r.ints(size, lo, hi). 294 forEach(x -> { 295 if (x < lo || x >= hi) 296 fails.getAndIncrement(); 297 }); 298 } 299 } 300 assertEquals(fails.get(), 0); 301 } 302 303 /** 304 * Each of a sequential sized stream of bounded longs is within bounds 305 */ testBoundedLongs()306 public void testBoundedLongs() { 307 AtomicInteger fails = new AtomicInteger(0); 308 Random r = new Random(); 309 long size = 123L; 310 for (long least = -86028121; least < MAX_LONG_BOUND; least += 1982451653L) { 311 for (long bound = least + 2; bound > least && bound < MAX_LONG_BOUND; bound += Math.abs(bound * 7919)) { 312 final long lo = least, hi = bound; 313 r.longs(size, lo, hi). 314 forEach(x -> { 315 if (x < lo || x >= hi) 316 fails.getAndIncrement(); 317 }); 318 } 319 } 320 assertEquals(fails.get(), 0); 321 } 322 323 /** 324 * Each of a sequential sized stream of bounded doubles is within bounds 325 */ testBoundedDoubles()326 public void testBoundedDoubles() { 327 AtomicInteger fails = new AtomicInteger(0); 328 Random r = new Random(); 329 long size = 456; 330 for (double least = 0.00011; least < 1.0e20; least *= 9) { 331 for (double bound = least * 1.0011; bound < 1.0e20; bound *= 17) { 332 final double lo = least, hi = bound; 333 r.doubles(size, lo, hi). 334 forEach(x -> { 335 if (x < lo || x >= hi) 336 fails.getAndIncrement(); 337 }); 338 } 339 } 340 assertEquals(fails.get(), 0); 341 } 342 343 /** 344 * A parallel unsized stream of ints generates at least 100 values 345 */ testUnsizedIntsCount()346 public void testUnsizedIntsCount() { 347 LongAdder counter = new LongAdder(); 348 Random r = new Random(); 349 long size = 100; 350 r.ints().limit(size).parallel().forEach(x -> { 351 counter.increment(); 352 }); 353 assertEquals(counter.sum(), size); 354 } 355 356 /** 357 * A parallel unsized stream of longs generates at least 100 values 358 */ testUnsizedLongsCount()359 public void testUnsizedLongsCount() { 360 LongAdder counter = new LongAdder(); 361 Random r = new Random(); 362 long size = 100; 363 r.longs().limit(size).parallel().forEach(x -> { 364 counter.increment(); 365 }); 366 assertEquals(counter.sum(), size); 367 } 368 369 /** 370 * A parallel unsized stream of doubles generates at least 100 values 371 */ testUnsizedDoublesCount()372 public void testUnsizedDoublesCount() { 373 LongAdder counter = new LongAdder(); 374 Random r = new Random(); 375 long size = 100; 376 r.doubles().limit(size).parallel().forEach(x -> { 377 counter.increment(); 378 }); 379 assertEquals(counter.sum(), size); 380 } 381 382 /** 383 * A sequential unsized stream of ints generates at least 100 values 384 */ testUnsizedIntsCountSeq()385 public void testUnsizedIntsCountSeq() { 386 LongAdder counter = new LongAdder(); 387 Random r = new Random(); 388 long size = 100; 389 r.ints().limit(size).forEach(x -> { 390 counter.increment(); 391 }); 392 assertEquals(counter.sum(), size); 393 } 394 395 /** 396 * A sequential unsized stream of longs generates at least 100 values 397 */ testUnsizedLongsCountSeq()398 public void testUnsizedLongsCountSeq() { 399 LongAdder counter = new LongAdder(); 400 Random r = new Random(); 401 long size = 100; 402 r.longs().limit(size).forEach(x -> { 403 counter.increment(); 404 }); 405 assertEquals(counter.sum(), size); 406 } 407 408 /** 409 * A sequential unsized stream of doubles generates at least 100 values 410 */ testUnsizedDoublesCountSeq()411 public void testUnsizedDoublesCountSeq() { 412 LongAdder counter = new LongAdder(); 413 Random r = new Random(); 414 long size = 100; 415 r.doubles().limit(size).forEach(x -> { 416 counter.increment(); 417 }); 418 assertEquals(counter.sum(), size); 419 } 420 421 /** 422 * Test shuffling a list with Random.from() 423 */ testShufflingList()424 public void testShufflingList() { 425 final var listTest = new ArrayList<Integer>(); 426 final RandomGenerator randomGenerator = RandomGenerator.getDefault(); 427 final Random random = Random.from(randomGenerator); 428 429 for (int i = 0; i < 100; i++) { 430 listTest.add(i * 2); 431 } 432 final var listCopy = new ArrayList<Integer>(listTest); 433 434 Collections.shuffle(listCopy, random); 435 436 assertFalse(listCopy.equals(listTest)); 437 } 438 439 /** 440 * Test if Random.from returns this 441 */ testRandomFromInstance()442 public void testRandomFromInstance() { 443 final RandomGenerator randomGenerator = RandomGenerator.getDefault(); 444 445 final Random randomInstance = Random.from(randomGenerator); 446 447 // we wrap the same instance again 448 final Random randomInstanceCopy = Random.from(randomInstance); 449 450 assertSame(randomInstance, randomInstanceCopy); 451 } 452 453 private int delegationCount; 454 455 private class RandomGen implements RandomGenerator { 456 457 @Override isDeprecated()458 public boolean isDeprecated() { 459 delegationCount += 1; 460 return RandomGenerator.super.isDeprecated(); 461 } 462 463 @Override nextFloat(float bound)464 public float nextFloat(float bound) { 465 delegationCount += 1; 466 return RandomGenerator.super.nextFloat(bound); 467 } 468 469 @Override nextDouble(double bound)470 public double nextDouble(double bound) { 471 delegationCount += 1; 472 return RandomGenerator.super.nextDouble(bound); 473 } 474 475 @Override nextLong()476 public long nextLong() { 477 return 0; 478 } 479 480 } 481 482 /* 483 * Test whether calls to methods inherited from RandomGenerator 484 * are delegated to the instance returned by from(). 485 * This is not a complete coverage, but simulates the reproducer 486 * in issue JDK-8288596 487 */ testRandomFrom()488 public void testRandomFrom() { 489 delegationCount = 0; 490 var r = Random.from(new RandomGen()); 491 r.isDeprecated(); 492 r.nextFloat(1_000.0f); 493 r.nextFloat(); // not implemented in RandomGen, does not count 494 r.nextDouble(1_000.0); 495 r.nextDouble(); // not implemented in RandomGen, does not count 496 assertEquals(delegationCount, 3); 497 } 498 499 } 500