1 /* 2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package libcore.java.util.random; 18 19 import static org.junit.Assert.assertArrayEquals; 20 import static org.junit.Assert.assertEquals; 21 import static org.junit.Assert.assertFalse; 22 import static org.junit.Assert.assertNotNull; 23 import static org.junit.Assert.assertThrows; 24 import static org.junit.Assert.assertTrue; 25 26 import static java.util.stream.Collectors.toSet; 27 28 import libcore.test.annotation.NonCts; 29 30 import org.junit.Test; 31 import org.junit.runner.RunWith; 32 import org.junit.runners.JUnit4; 33 34 import java.math.BigInteger; 35 import java.security.SecureRandom; 36 import java.util.Arrays; 37 import java.util.Set; 38 import java.util.random.RandomGenerator; 39 import java.util.random.RandomGeneratorFactory; 40 import jdk.internal.util.random.RandomSupport; 41 42 43 @RunWith(JUnit4.class) 44 public class RandomGeneratorFactoryTest { 45 46 @Test defaultFactoryInstance()47 public void defaultFactoryInstance() { 48 RandomGeneratorFactory<RandomGenerator> defaultFactory = RandomGeneratorFactory.getDefault(); 49 50 assertNotNull(defaultFactory); 51 52 int stateBits = defaultFactory.stateBits(); 53 assertTrue("stateBits() for default was " + stateBits, stateBits >= 64); 54 } 55 56 @Test 57 @NonCts(reason = "Algorithm might not be available in the future") createsL64X256MixRandomInstance()58 public void createsL64X256MixRandomInstance() { 59 RandomGeneratorFactory<RandomGenerator> specificAlgoFactory = 60 RandomGeneratorFactory.of("L64X256MixRandom"); 61 62 assertNotNull(specificAlgoFactory); 63 // These are coming from package-summary page. 64 assertEquals( "L64X256MixRandom", specificAlgoFactory.name()); 65 assertEquals("LXM", specificAlgoFactory.group()); 66 assertEquals(4, specificAlgoFactory.equidistribution()); 67 BigInteger expectedPeriod = 68 BigInteger.ONE.shiftLeft(256).subtract(BigInteger.ONE).shiftLeft(64); 69 assertEquals(expectedPeriod, specificAlgoFactory.period()); 70 assertTrue(specificAlgoFactory.isSplittable()); 71 assertTrue(specificAlgoFactory.isStreamable()); 72 } 73 74 @Test throwsOnUnsupported()75 public void throwsOnUnsupported() { 76 assertThrows( 77 IllegalArgumentException.class, 78 () -> RandomGeneratorFactory.of("something something")); 79 assertThrows(NullPointerException.class, () -> RandomGeneratorFactory.of(null)); 80 } 81 82 /** 83 * Goal is to ensure that META-INF/services/java.util.random.RandomGenerator is present and 84 * is read. 85 */ 86 @Test 87 @NonCts(reason = "No guarantees are provided around available implementations") checkCurrentlyAvailableImplementations()88 public void checkCurrentlyAvailableImplementations() { 89 Set<String> actual = RandomGeneratorFactory.all() 90 .map(RandomGeneratorFactory::name) 91 .collect(toSet()); 92 93 Set<String> expected = Set.of( 94 "L32X64MixRandom", 95 "L64X128MixRandom", 96 "L64X128StarStarRandom", 97 "L64X256MixRandom", 98 "L64X1024MixRandom", 99 "L128X128MixRandom", 100 "L128X256MixRandom", 101 "L128X1024MixRandom", 102 "Xoroshiro128PlusPlus", 103 "Xoshiro256PlusPlus"); 104 105 assertEquals(expected, actual); 106 } 107 108 @Test checkConsistency_initializeWithLongSeed()109 public void checkConsistency_initializeWithLongSeed() { 110 RandomGeneratorFactory.all() 111 .forEach(RandomGeneratorFactoryTest::checkConsistencyWithLongSeed); 112 } 113 114 @Test checkConsistency_initializeWithBytesSeed()115 public void checkConsistency_initializeWithBytesSeed() { 116 RandomGeneratorFactory.all() 117 .forEach(RandomGeneratorFactoryTest::checkConsistencyWithBytesSeed); 118 } 119 120 @Test isDeprecated_consistency()121 public void isDeprecated_consistency() { 122 RandomGeneratorFactory.all().forEach(factory -> { 123 RandomGenerator rng = factory.create(); 124 var msg = factory.name() + " created deprecated RandomGenerator"; 125 126 assertFalse(msg, rng.isDeprecated()); 127 assertFalse(msg, factory.isDeprecated()); 128 }); 129 } 130 checkConsistencyWithLongSeed(RandomGeneratorFactory rngFactory)131 private static void checkConsistencyWithLongSeed(RandomGeneratorFactory rngFactory) { 132 long seed = RandomSupport.initialSeed(); 133 134 System.out.println("Testing with seed=" + seed); 135 136 checkNextBoolean(rngFactory.create(seed), rngFactory.create(seed)); 137 checkNextInt(rngFactory.create(seed), rngFactory.create(seed)); 138 checkInts(rngFactory.create(seed), rngFactory.create(seed)); 139 checkNextLong(rngFactory.create(seed), rngFactory.create(seed)); 140 checkLongs(rngFactory.create(seed), rngFactory.create(seed)); 141 checkNextDouble(rngFactory.create(seed), rngFactory.create(seed)); 142 checkDoubles(rngFactory.create(seed), rngFactory.create(seed)); 143 } 144 checkConsistencyWithBytesSeed(RandomGeneratorFactory rngFactory)145 private static void checkConsistencyWithBytesSeed(RandomGeneratorFactory rngFactory) { 146 byte[] seedBytes = new SecureRandom().generateSeed(256); 147 148 System.out.println("Testing with seed=" + Arrays.toString(seedBytes)); 149 150 checkNextBoolean(rngFactory.create(seedBytes), rngFactory.create(seedBytes)); 151 checkNextInt(rngFactory.create(seedBytes), rngFactory.create(seedBytes)); 152 checkInts(rngFactory.create(seedBytes), rngFactory.create(seedBytes)); 153 checkNextLong(rngFactory.create(seedBytes), rngFactory.create(seedBytes)); 154 checkLongs(rngFactory.create(seedBytes), rngFactory.create(seedBytes)); 155 checkNextDouble(rngFactory.create(seedBytes), rngFactory.create(seedBytes)); 156 checkDoubles(rngFactory.create(seedBytes), rngFactory.create(seedBytes)); 157 } 158 checkNextBoolean(RandomGenerator first, RandomGenerator second)159 private static void checkNextBoolean(RandomGenerator first, RandomGenerator second) { 160 for (int i = 0; i < 1_000; ++i) { 161 boolean firstResult = first.nextBoolean(); 162 boolean secondResult = second.nextBoolean(); 163 String errorMsg = String.format("At iteration %d %s returned %b, but %s returned %b", 164 i, first, firstResult, second, secondResult); 165 assertEquals(errorMsg, firstResult, secondResult); 166 } 167 } 168 checkNextInt(RandomGenerator first, RandomGenerator second)169 private static void checkNextInt(RandomGenerator first, RandomGenerator second) { 170 for (int i = 0; i < 1_000; ++i) { 171 int firstResult = first.nextInt(); 172 int secondResult = second.nextInt(); 173 String errorMsg = String.format("At iteration %d %s returned %d, but %s returned %d", 174 i, first, firstResult, second, secondResult); 175 assertEquals(errorMsg, firstResult, secondResult); 176 } 177 } 178 checkNextLong(RandomGenerator first, RandomGenerator second)179 private static void checkNextLong(RandomGenerator first, RandomGenerator second) { 180 for (int i = 0; i < 1_000; ++i) { 181 long firstResult = first.nextLong(); 182 long secondResult = second.nextLong(); 183 String errorMsg = String.format("At iteration %d %s returned %d, but %s returned %d", 184 i, first, firstResult, second, secondResult); 185 assertEquals(errorMsg, firstResult, secondResult); 186 } 187 } 188 checkNextDouble(RandomGenerator first, RandomGenerator second)189 private static void checkNextDouble(RandomGenerator first, RandomGenerator second) { 190 for (int i = 0; i < 1_000; ++i) { 191 double firstResult = first.nextDouble(); 192 double secondResult = second.nextDouble(); 193 String errorMsg = String.format("At iteration %d %s returned %f, but %s returned %f", 194 i, first, firstResult, second, secondResult); 195 assertEquals(errorMsg, firstResult, secondResult, 0.0d); 196 } 197 } 198 checkInts(RandomGenerator first, RandomGenerator second)199 private static void checkInts(RandomGenerator first, RandomGenerator second) { 200 int[] firstResult = first.ints().limit(1_000).toArray(); 201 int[] secondResult = second.ints().limit(1_000).toArray(); 202 203 String errorMsg = String.format("%s.ints() and %s.ints() generated different sequences", 204 first, second); 205 assertArrayEquals(errorMsg, firstResult, secondResult); 206 } 207 checkLongs(RandomGenerator first, RandomGenerator second)208 private static void checkLongs(RandomGenerator first, RandomGenerator second) { 209 long[] firstResult = first.longs().limit(1_000).toArray(); 210 long[] secondResult = second.longs().limit(1_000).toArray(); 211 212 String errorMsg = String.format("%s.longs() and %s.longs() generated different sequences", 213 first, second); 214 assertArrayEquals(errorMsg, firstResult, secondResult); 215 } 216 checkDoubles(RandomGenerator first, RandomGenerator second)217 private static void checkDoubles(RandomGenerator first, RandomGenerator second) { 218 double[] firstResult = first.doubles().limit(1_000).toArray(); 219 double[] secondResult = second.doubles().limit(1_000).toArray(); 220 221 String errorMsg = String.format("%s.doubles() and %s.doubles() generated different sequences", 222 first, second); 223 assertArrayEquals(errorMsg, firstResult, secondResult, 0.0d); 224 } 225 } 226