1 /* 2 * Copyright (c) 2012, 2013, 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 import org.testng.Assert; 25 import org.testng.annotations.Test; 26 27 import java.util.SplittableRandom; 28 import java.util.concurrent.ThreadLocalRandom; 29 import java.util.concurrent.atomic.AtomicInteger; 30 import java.util.concurrent.atomic.LongAdder; 31 import java.util.function.BiConsumer; 32 33 import static org.testng.Assert.assertEquals; 34 import static org.testng.Assert.assertNotNull; 35 import static org.testng.AssertJUnit.assertTrue; 36 37 /** 38 * @test 39 * @run testng SplittableRandomTest 40 * @run testng/othervm -Djava.util.secureRandomSeed=true SplittableRandomTest 41 * @summary test methods on SplittableRandom 42 */ 43 @Test 44 public class SplittableRandomTest { 45 46 // Note: this test was copied from the 166 TCK SplittableRandomTest test 47 // and modified to be a TestNG test 48 49 /* 50 * Testing coverage notes: 51 * 52 * 1. Many of the test methods are adapted from ThreadLocalRandomTest. 53 * 54 * 2. These tests do not check for random number generator quality. 55 * But we check for minimal API compliance by requiring that 56 * repeated calls to nextX methods, up to NCALLS tries, produce at 57 * least two distinct results. (In some possible universe, a 58 * "correct" implementation might fail, but the odds are vastly 59 * less than that of encountering a hardware failure while running 60 * the test.) For bounded nextX methods, we sample various 61 * intervals across multiples of primes. In other tests, we repeat 62 * under REPS different values. 63 */ 64 65 // max numbers of calls to detect getting stuck on one value 66 static final int NCALLS = 10000; 67 68 // max sampled int bound 69 static final int MAX_INT_BOUND = (1 << 28); 70 71 // max sampled long bound 72 static final long MAX_LONG_BOUND = (1L << 42); 73 74 // Number of replications for other checks 75 static final int REPS = 20; 76 77 /** 78 * Repeated calls to nextInt produce at least two distinct results 79 */ 80 public void testNextInt() { 81 SplittableRandom sr = new SplittableRandom(); 82 int f = sr.nextInt(); 83 int i = 0; 84 while (i < NCALLS && sr.nextInt() == f) 85 ++i; 86 assertTrue(i < NCALLS); 87 } 88 89 /** 90 * Repeated calls to nextLong produce at least two distinct results 91 */ 92 public void testNextLong() { 93 SplittableRandom sr = new SplittableRandom(); 94 long f = sr.nextLong(); 95 int i = 0; 96 while (i < NCALLS && sr.nextLong() == f) 97 ++i; 98 assertTrue(i < NCALLS); 99 } 100 101 /** 102 * Repeated calls to nextDouble produce at least two distinct results 103 */ 104 public void testNextDouble() { 105 SplittableRandom sr = new SplittableRandom(); 106 double f = sr.nextDouble(); 107 int i = 0; 108 while (i < NCALLS && sr.nextDouble() == f) 109 ++i; 110 assertTrue(i < NCALLS); 111 } 112 113 /** 114 * Two SplittableRandoms created with the same seed produce the 115 * same values for nextLong. 116 */ 117 public void testSeedConstructor() { 118 for (long seed = 2; seed < MAX_LONG_BOUND; seed += 15485863) { 119 SplittableRandom sr1 = new SplittableRandom(seed); 120 SplittableRandom sr2 = new SplittableRandom(seed); 121 for (int i = 0; i < REPS; ++i) 122 assertEquals(sr1.nextLong(), sr2.nextLong()); 123 } 124 } 125 126 /** 127 * A SplittableRandom produced by split() of a default-constructed 128 * SplittableRandom generates a different sequence 129 */ 130 public void testSplit1() { 131 SplittableRandom sr = new SplittableRandom(); 132 for (int reps = 0; reps < REPS; ++reps) { 133 SplittableRandom sc = sr.split(); 134 int i = 0; 135 while (i < NCALLS && sr.nextLong() == sc.nextLong()) 136 ++i; 137 assertTrue(i < NCALLS); 138 } 139 } 140 141 /** 142 * A SplittableRandom produced by split() of a seeded-constructed 143 * SplittableRandom generates a different sequence 144 */ 145 public void testSplit2() { 146 SplittableRandom sr = new SplittableRandom(12345); 147 for (int reps = 0; reps < REPS; ++reps) { 148 SplittableRandom sc = sr.split(); 149 int i = 0; 150 while (i < NCALLS && sr.nextLong() == sc.nextLong()) 151 ++i; 152 assertTrue(i < NCALLS); 153 } 154 } 155 156 /** 157 * nextInt(negative) throws IllegalArgumentException 158 */ 159 @Test(expectedExceptions = IllegalArgumentException.class) 160 public void testNextIntBoundedNeg() { 161 SplittableRandom sr = new SplittableRandom(); 162 int f = sr.nextInt(-17); 163 } 164 165 /** 166 * nextInt(least >= bound) throws IllegalArgumentException 167 */ 168 @Test(expectedExceptions = IllegalArgumentException.class) 169 public void testNextIntBadBounds() { 170 SplittableRandom sr = new SplittableRandom(); 171 int f = sr.nextInt(17, 2); 172 } 173 174 /** 175 * nextInt(bound) returns 0 <= value < bound; 176 * repeated calls produce at least two distinct results 177 */ 178 public void testNextIntBounded() { 179 SplittableRandom sr = new SplittableRandom(); 180 // sample bound space across prime number increments 181 for (int bound = 2; bound < MAX_INT_BOUND; bound += 524959) { 182 int f = sr.nextInt(bound); 183 assertTrue(0 <= f && f < bound); 184 int i = 0; 185 int j; 186 while (i < NCALLS && 187 (j = sr.nextInt(bound)) == f) { 188 assertTrue(0 <= j && j < bound); 189 ++i; 190 } 191 assertTrue(i < NCALLS); 192 } 193 } 194 195 /** 196 * nextInt(least, bound) returns least <= value < bound; 197 * repeated calls produce at least two distinct results 198 */ 199 public void testNextIntBounded2() { 200 SplittableRandom sr = new SplittableRandom(); 201 for (int least = -15485863; least < MAX_INT_BOUND; least += 524959) { 202 for (int bound = least + 2; bound > least && bound < MAX_INT_BOUND; bound += 49979687) { 203 int f = sr.nextInt(least, bound); 204 assertTrue(least <= f && f < bound); 205 int i = 0; 206 int j; 207 while (i < NCALLS && 208 (j = sr.nextInt(least, bound)) == f) { 209 assertTrue(least <= j && j < bound); 210 ++i; 211 } 212 assertTrue(i < NCALLS); 213 } 214 } 215 } 216 217 /** 218 * nextLong(negative) throws IllegalArgumentException 219 */ 220 @Test(expectedExceptions = IllegalArgumentException.class) 221 public void testNextLongBoundedNeg() { 222 SplittableRandom sr = new SplittableRandom(); 223 long f = sr.nextLong(-17); 224 } 225 226 /** 227 * nextLong(least >= bound) throws IllegalArgumentException 228 */ 229 @Test(expectedExceptions = IllegalArgumentException.class) 230 public void testNextLongBadBounds() { 231 SplittableRandom sr = new SplittableRandom(); 232 long f = sr.nextLong(17, 2); 233 } 234 235 /** 236 * nextLong(bound) returns 0 <= value < bound; 237 * repeated calls produce at least two distinct results 238 */ 239 public void testNextLongBounded() { 240 SplittableRandom sr = new SplittableRandom(); 241 for (long bound = 2; bound < MAX_LONG_BOUND; bound += 15485863) { 242 long f = sr.nextLong(bound); 243 assertTrue(0 <= f && f < bound); 244 int i = 0; 245 long j; 246 while (i < NCALLS && 247 (j = sr.nextLong(bound)) == f) { 248 assertTrue(0 <= j && j < bound); 249 ++i; 250 } 251 assertTrue(i < NCALLS); 252 } 253 } 254 255 /** 256 * nextLong(least, bound) returns least <= value < bound; 257 * repeated calls produce at least two distinct results 258 */ 259 public void testNextLongBounded2() { 260 SplittableRandom sr = new SplittableRandom(); 261 for (long least = -86028121; least < MAX_LONG_BOUND; least += 982451653L) { 262 for (long bound = least + 2; bound > least && bound < MAX_LONG_BOUND; bound += Math.abs(bound * 7919)) { 263 long f = sr.nextLong(least, bound); 264 assertTrue(least <= f && f < bound); 265 int i = 0; 266 long j; 267 while (i < NCALLS && 268 (j = sr.nextLong(least, bound)) == f) { 269 assertTrue(least <= j && j < bound); 270 ++i; 271 } 272 assertTrue(i < NCALLS); 273 } 274 } 275 } 276 277 /** 278 * nextDouble(bound) throws IllegalArgumentException 279 */ 280 public void testNextDoubleBadBound() { 281 SplittableRandom sr = new SplittableRandom(); 282 executeAndCatchIAE(() -> sr.nextDouble(0.0)); 283 executeAndCatchIAE(() -> sr.nextDouble(-0.0)); 284 executeAndCatchIAE(() -> sr.nextDouble(+0.0)); 285 executeAndCatchIAE(() -> sr.nextDouble(-1.0)); 286 executeAndCatchIAE(() -> sr.nextDouble(Double.NaN)); 287 executeAndCatchIAE(() -> sr.nextDouble(Double.NEGATIVE_INFINITY)); 288 289 // Returns Double.MAX_VALUE 290 // executeAndCatchIAE(() -> r.nextDouble(Double.POSITIVE_INFINITY)); 291 } 292 293 /** 294 * nextDouble(origin, bound) throws IllegalArgumentException 295 */ 296 public void testNextDoubleBadOriginBound() { 297 testDoubleBadOriginBound(new SplittableRandom()::nextDouble); 298 } 299 300 // An arbitrary finite double value 301 static final double FINITE = Math.PI; 302 303 void testDoubleBadOriginBound(BiConsumer<Double, Double> bi) { 304 executeAndCatchIAE(() -> bi.accept(17.0, 2.0)); 305 executeAndCatchIAE(() -> bi.accept(0.0, 0.0)); 306 executeAndCatchIAE(() -> bi.accept(Double.NaN, FINITE)); 307 executeAndCatchIAE(() -> bi.accept(FINITE, Double.NaN)); 308 executeAndCatchIAE(() -> bi.accept(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY)); 309 310 // Returns NaN 311 // executeAndCatchIAE(() -> bi.accept(Double.NEGATIVE_INFINITY, FINITE)); 312 // executeAndCatchIAE(() -> bi.accept(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY)); 313 314 executeAndCatchIAE(() -> bi.accept(FINITE, Double.NEGATIVE_INFINITY)); 315 316 // Returns Double.MAX_VALUE 317 // executeAndCatchIAE(() -> bi.accept(FINITE, Double.POSITIVE_INFINITY)); 318 319 executeAndCatchIAE(() -> bi.accept(Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY)); 320 executeAndCatchIAE(() -> bi.accept(Double.POSITIVE_INFINITY, FINITE)); 321 executeAndCatchIAE(() -> bi.accept(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY)); 322 } 323 324 /** 325 * nextDouble(least, bound) returns least <= value < bound; 326 * repeated calls produce at least two distinct results 327 */ 328 public void testNextDoubleBounded2() { 329 SplittableRandom sr = new SplittableRandom(); 330 for (double least = 0.0001; least < 1.0e20; least *= 8) { 331 for (double bound = least * 1.001; bound < 1.0e20; bound *= 16) { 332 double f = sr.nextDouble(least, bound); 333 assertTrue(least <= f && f < bound); 334 int i = 0; 335 double j; 336 while (i < NCALLS && 337 (j = sr.nextDouble(least, bound)) == f) { 338 assertTrue(least <= j && j < bound); 339 ++i; 340 } 341 assertTrue(i < NCALLS); 342 } 343 } 344 } 345 346 /** 347 * Invoking sized ints, long, doubles, with negative sizes throws 348 * IllegalArgumentException 349 */ 350 public void testBadStreamSize() { 351 SplittableRandom r = new SplittableRandom(); 352 executeAndCatchIAE(() -> r.ints(-1L)); 353 executeAndCatchIAE(() -> r.ints(-1L, 2, 3)); 354 executeAndCatchIAE(() -> r.longs(-1L)); 355 executeAndCatchIAE(() -> r.longs(-1L, -1L, 1L)); 356 executeAndCatchIAE(() -> r.doubles(-1L)); 357 executeAndCatchIAE(() -> r.doubles(-1L, .5, .6)); 358 } 359 360 /** 361 * Invoking bounded ints, long, doubles, with illegal bounds throws 362 * IllegalArgumentException 363 */ 364 public void testBadStreamBounds() { 365 SplittableRandom r = new SplittableRandom(); 366 executeAndCatchIAE(() -> r.ints(2, 1)); 367 executeAndCatchIAE(() -> r.ints(10, 42, 42)); 368 executeAndCatchIAE(() -> r.longs(-1L, -1L)); 369 executeAndCatchIAE(() -> r.longs(10, 1L, -2L)); 370 371 testDoubleBadOriginBound((o, b) -> r.doubles(10, o, b)); 372 } 373 374 private void executeAndCatchIAE(Runnable r) { 375 executeAndCatch(IllegalArgumentException.class, r); 376 } 377 378 private void executeAndCatch(Class<? extends Exception> expected, Runnable r) { 379 Exception caught = null; 380 try { 381 r.run(); 382 } 383 catch (Exception e) { 384 caught = e; 385 } 386 387 assertNotNull(caught, 388 String.format("No Exception was thrown, expected an Exception of %s to be thrown", 389 expected.getName())); 390 Assert.assertTrue(expected.isInstance(caught), 391 String.format("Exception thrown %s not an instance of %s", 392 caught.getClass().getName(), expected.getName())); 393 } 394 395 /** 396 * A parallel sized stream of ints generates the given number of values 397 */ 398 public void testIntsCount() { 399 LongAdder counter = new LongAdder(); 400 SplittableRandom r = new SplittableRandom(); 401 long size = 0; 402 for (int reps = 0; reps < REPS; ++reps) { 403 counter.reset(); 404 r.ints(size).parallel().forEach(x -> {counter.increment();}); 405 assertEquals(counter.sum(), size); 406 size += 524959; 407 } 408 } 409 410 /** 411 * A parallel sized stream of longs generates the given number of values 412 */ 413 public void testLongsCount() { 414 LongAdder counter = new LongAdder(); 415 SplittableRandom r = new SplittableRandom(); 416 long size = 0; 417 for (int reps = 0; reps < REPS; ++reps) { 418 counter.reset(); 419 r.longs(size).parallel().forEach(x -> {counter.increment();}); 420 assertEquals(counter.sum(), size); 421 size += 524959; 422 } 423 } 424 425 /** 426 * A parallel sized stream of doubles generates the given number of values 427 */ 428 public void testDoublesCount() { 429 LongAdder counter = new LongAdder(); 430 SplittableRandom r = new SplittableRandom(); 431 long size = 0; 432 for (int reps = 0; reps < REPS; ++reps) { 433 counter.reset(); 434 r.doubles(size).parallel().forEach(x -> {counter.increment();}); 435 assertEquals(counter.sum(), size); 436 size += 524959; 437 } 438 } 439 440 /** 441 * Each of a parallel sized stream of bounded ints is within bounds 442 */ 443 public void testBoundedInts() { 444 AtomicInteger fails = new AtomicInteger(0); 445 SplittableRandom r = new SplittableRandom(); 446 long size = 12345L; 447 for (int least = -15485867; least < MAX_INT_BOUND; least += 524959) { 448 for (int bound = least + 2; bound > least && bound < MAX_INT_BOUND; bound += 67867967) { 449 final int lo = least, hi = bound; 450 r.ints(size, lo, hi).parallel(). 451 forEach(x -> {if (x < lo || x >= hi) 452 fails.getAndIncrement(); }); 453 } 454 } 455 assertEquals(fails.get(), 0); 456 } 457 458 /** 459 * Each of a parallel sized stream of bounded longs is within bounds 460 */ 461 public void testBoundedLongs() { 462 AtomicInteger fails = new AtomicInteger(0); 463 SplittableRandom r = new SplittableRandom(); 464 long size = 123L; 465 for (long least = -86028121; least < MAX_LONG_BOUND; least += 1982451653L) { 466 for (long bound = least + 2; bound > least && bound < MAX_LONG_BOUND; bound += Math.abs(bound * 7919)) { 467 final long lo = least, hi = bound; 468 r.longs(size, lo, hi).parallel(). 469 forEach(x -> {if (x < lo || x >= hi) 470 fails.getAndIncrement(); }); 471 } 472 } 473 assertEquals(fails.get(), 0); 474 } 475 476 /** 477 * Each of a parallel sized stream of bounded doubles is within bounds 478 */ 479 public void testBoundedDoubles() { 480 AtomicInteger fails = new AtomicInteger(0); 481 SplittableRandom r = new SplittableRandom(); 482 long size = 456; 483 for (double least = 0.00011; least < 1.0e20; least *= 9) { 484 for (double bound = least * 1.0011; bound < 1.0e20; bound *= 17) { 485 final double lo = least, hi = bound; 486 r.doubles(size, lo, hi).parallel(). 487 forEach(x -> {if (x < lo || x >= hi) 488 fails.getAndIncrement(); }); 489 } 490 } 491 assertEquals(fails.get(), 0); 492 } 493 494 /** 495 * A parallel unsized stream of ints generates at least 100 values 496 */ 497 public void testUnsizedIntsCount() { 498 LongAdder counter = new LongAdder(); 499 SplittableRandom r = new SplittableRandom(); 500 long size = 100; 501 r.ints().limit(size).parallel().forEach(x -> {counter.increment();}); 502 assertEquals(counter.sum(), size); 503 } 504 505 /** 506 * A parallel unsized stream of longs generates at least 100 values 507 */ 508 public void testUnsizedLongsCount() { 509 LongAdder counter = new LongAdder(); 510 SplittableRandom r = new SplittableRandom(); 511 long size = 100; 512 r.longs().limit(size).parallel().forEach(x -> {counter.increment();}); 513 assertEquals(counter.sum(), size); 514 } 515 516 /** 517 * A parallel unsized stream of doubles generates at least 100 values 518 */ 519 public void testUnsizedDoublesCount() { 520 LongAdder counter = new LongAdder(); 521 SplittableRandom r = new SplittableRandom(); 522 long size = 100; 523 r.doubles().limit(size).parallel().forEach(x -> {counter.increment();}); 524 assertEquals(counter.sum(), size); 525 } 526 527 /** 528 * A sequential unsized stream of ints generates at least 100 values 529 */ 530 public void testUnsizedIntsCountSeq() { 531 LongAdder counter = new LongAdder(); 532 SplittableRandom r = new SplittableRandom(); 533 long size = 100; 534 r.ints().limit(size).forEach(x -> {counter.increment();}); 535 assertEquals(counter.sum(), size); 536 } 537 538 /** 539 * A sequential unsized stream of longs generates at least 100 values 540 */ 541 public void testUnsizedLongsCountSeq() { 542 LongAdder counter = new LongAdder(); 543 SplittableRandom r = new SplittableRandom(); 544 long size = 100; 545 r.longs().limit(size).forEach(x -> {counter.increment();}); 546 assertEquals(counter.sum(), size); 547 } 548 549 /** 550 * A sequential unsized stream of doubles generates at least 100 values 551 */ 552 public void testUnsizedDoublesCountSeq() { 553 LongAdder counter = new LongAdder(); 554 SplittableRandom r = new SplittableRandom(); 555 long size = 100; 556 r.doubles().limit(size).forEach(x -> {counter.increment();}); 557 assertEquals(counter.sum(), size); 558 } 559 560 }