• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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