1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.commons.rng.simple;
18
19 import java.util.Random;
20
21 import org.apache.commons.rng.UniformRandomProvider;
22 import org.apache.commons.rng.core.source64.LongProvider;
23 import org.junit.jupiter.api.Assertions;
24 import org.junit.jupiter.api.Test;
25
26 /**
27 * Tests for the {@link JDKRandomWrapper} class.
28 */
29 class JDKRandomWrapperTest {
30 /**
31 * Test all the methods shared by Random and UniformRandomProvider are equivalent.
32 */
33 @Test
34 void testJDKRandomEquivalence() {
35 // Initialize.
36 final long seed = RandomSource.createLong();
37 final Random rng1 = new Random(seed);
38 final UniformRandomProvider rng2 = new JDKRandomWrapper(new Random(seed));
39 checkSameSequence(rng1, rng2);
40 }
41
42 /**
43 * Ensure that both generators produce the same sequences.
44 *
45 * @param rng1 RNG.
46 * @param rng2 RNG.
47 */
48 private static void checkSameSequence(Random rng1,
49 UniformRandomProvider rng2) {
50 for (int i = 0; i < 4; i++) {
51 Assertions.assertEquals(rng1.nextInt(),
52 rng2.nextInt());
53 }
54 for (int i = 0; i < 7; i++) {
55 Assertions.assertEquals(rng1.nextLong(),
56 rng2.nextLong());
57 }
58 for (int i = 0; i < 9; i++) {
59 Assertions.assertEquals(rng1.nextFloat(),
60 rng2.nextFloat());
61 }
62 for (int i = 0; i < 12; i++) {
63 Assertions.assertEquals(rng1.nextDouble(),
64 rng2.nextDouble());
65 }
66 for (int i = 0; i < 18; i++) {
67 Assertions.assertEquals(rng1.nextBoolean(),
68 rng2.nextBoolean());
69 }
70 for (int i = 0; i < 19; i++) {
71 final int max = i + 123456;
72 Assertions.assertEquals(rng1.nextInt(max),
73 rng2.nextInt(max));
74 }
75
76 final int len = 233;
77 final byte[] store1 = new byte[len];
78 final byte[] store2 = new byte[len];
79 rng1.nextBytes(store1);
80 rng2.nextBytes(store2);
81 for (int i = 0; i < len; i++) {
82 Assertions.assertEquals(store1[i],
83 store2[i]);
84 }
85 }
86
87 /**
88 * Test {@link UniformRandomProvider#nextLong(long)} matches that from the core
89 * BaseProvider implementation.
90 */
91 @Test
92 void testNextLongInRange() {
93 final long seed = RandomSource.createLong();
94 // This will use the RNG core BaseProvider implementation.
95 // Use a LongProvider to directly use the Random::nextLong method
96 // which is different from IntProvider::nextLong.
97 final UniformRandomProvider rng1 = new LongProvider() {
98 private final Random random = new Random(seed);
99
100 @Override
101 public long next() {
102 return random.nextLong();
103 }
104 };
105 final UniformRandomProvider rng2 = new JDKRandomWrapper(new Random(seed));
106
107 // Test cases
108 // 1 : Smallest range
109 // 256 : Integer power of 2
110 // 56757 : Integer range
111 // 1L << 32 : Non-integer power of 2
112 // (1L << 62) + 1 : Worst case for rejection rate for the algorithm.
113 // Reject probability is approximately 0.5 thus the test hits
114 // all code paths.
115 for (final long max : new long[] {1, 256, 56757, 1L << 32, (1L << 62) + 1}) {
116 for (int i = 0; i < 10; i++) {
117 Assertions.assertEquals(rng1.nextLong(max),
118 rng2.nextLong(max));
119 }
120 }
121 }
122
123 @Test
124 void testNextLongInRangeThrows() {
125 final UniformRandomProvider rng1 = new JDKRandomWrapper(new Random(5675767L));
126 Assertions.assertThrows(IllegalArgumentException.class, () -> rng1.nextLong(0));
127 }
128
129 /**
130 * Test the bytes created by {@link UniformRandomProvider#nextBytes(byte[], int, int)} matches
131 * {@link Random#nextBytes(byte[])}.
132 */
133 @Test
134 void testNextByteInRange() {
135 final long seed = RandomSource.createLong();
136 final Random rng1 = new Random(seed);
137 final UniformRandomProvider rng2 = new JDKRandomWrapper(new Random(seed));
138
139 checkSameBytes(rng1, rng2, 1, 0, 1);
140 checkSameBytes(rng1, rng2, 100, 0, 100);
141 checkSameBytes(rng1, rng2, 100, 10, 90);
142 checkSameBytes(rng1, rng2, 245, 67, 34);
143 }
144
145 /**
146 * Ensure that the bytes produced in a sub-range of a byte array by
147 * {@link UniformRandomProvider#nextBytes(byte[], int, int)} match the bytes created
148 * by the JDK {@link Random#nextBytes(byte[])}.
149 *
150 * @param rng1 JDK Random.
151 * @param rng2 RNG.
152 * @param size Size of byte array.
153 * @param start Index at which to start inserting the generated bytes.
154 * @param len Number of bytes to insert.
155 */
156 private static void checkSameBytes(Random rng1,
157 UniformRandomProvider rng2,
158 int size, int start, int length) {
159 final byte[] store1 = new byte[length];
160 final byte[] store2 = new byte[size];
161 rng1.nextBytes(store1);
162 rng2.nextBytes(store2, start, length);
163 for (int i = 0; i < length; i++) {
164 Assertions.assertEquals(store1[i],
165 store2[i + start]);
166 }
167 }
168 }