View Javadoc
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 }