1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.rng.core;
18
19 import org.junit.jupiter.api.Assertions;
20 import org.junit.jupiter.api.Assumptions;
21 import org.junit.jupiter.params.ParameterizedTest;
22 import org.junit.jupiter.params.provider.MethodSource;
23
24 import java.util.Arrays;
25
26 import org.apache.commons.rng.JumpableUniformRandomProvider;
27 import org.apache.commons.rng.LongJumpableUniformRandomProvider;
28 import org.apache.commons.rng.RandomProviderState;
29 import org.apache.commons.rng.RestorableUniformRandomProvider;
30 import org.apache.commons.rng.UniformRandomProvider;
31 import org.apache.commons.rng.core.source32.IntProvider;
32 import org.apache.commons.rng.core.source64.LongProvider;
33
34
35
36
37 class JumpableProvidersParametricTest {
38
39 private static final byte[] INT_PROVIDER_STATE;
40
41 private static final byte[] LONG_PROVIDER_STATE;
42
43 static {
44 INT_PROVIDER_STATE = new State32Generator().getState();
45 LONG_PROVIDER_STATE = new State64Generator().getState();
46 }
47
48
49
50
51
52
53 private static Iterable<JumpableUniformRandomProvider> getJumpableProviders() {
54 return ProvidersList.listJumpable();
55 }
56
57
58
59
60
61
62
63
64 private static TestJumpFunction getLongJumpFunction(JumpableUniformRandomProvider generator) {
65 Assumptions.assumeTrue(generator instanceof LongJumpableUniformRandomProvider, "No long jump function");
66 final LongJumpableUniformRandomProvider rng2 = (LongJumpableUniformRandomProvider) generator;
67 return rng2::jump;
68 }
69
70
71
72
73 @ParameterizedTest
74 @MethodSource("getJumpableProviders")
75 void testJumpReturnsACopy(JumpableUniformRandomProvider generator) {
76 assertJumpReturnsACopy(generator::jump, generator);
77 }
78
79
80
81
82 @ParameterizedTest
83 @MethodSource("getJumpableProviders")
84 void testLongJumpReturnsACopy(JumpableUniformRandomProvider generator) {
85 assertJumpReturnsACopy(getLongJumpFunction(generator), generator);
86 }
87
88
89
90
91
92
93
94 private static void assertJumpReturnsACopy(TestJumpFunction jumpFunction,
95 JumpableUniformRandomProvider generator) {
96 final UniformRandomProvider copy = jumpFunction.jump();
97 Assertions.assertNotSame(generator, copy, "The copy instance should be a different object");
98 Assertions.assertEquals(generator.getClass(), copy.getClass(), "The copy instance should be the same class");
99 }
100
101
102
103
104
105 @ParameterizedTest
106 @MethodSource("getJumpableProviders")
107 void testJumpCopyMatchesPreJumpState(JumpableUniformRandomProvider generator) {
108 assertCopyMatchesPreJumpState(generator::jump, generator);
109 }
110
111
112
113
114
115 @ParameterizedTest
116 @MethodSource("getJumpableProviders")
117 void testLongJumpCopyMatchesPreJumpState(JumpableUniformRandomProvider generator) {
118 assertCopyMatchesPreJumpState(getLongJumpFunction(generator), generator);
119 }
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140 private static void assertCopyMatchesPreJumpState(TestJumpFunction jumpFunction,
141 JumpableUniformRandomProvider generator) {
142 Assumptions.assumeTrue(generator instanceof RestorableUniformRandomProvider, "Not a restorable RNG");
143
144 for (int repeats = 0; repeats < 2; repeats++) {
145
146
147
148
149 generator.nextInt();
150 generator.nextBoolean();
151
152 final RandomProviderState preJumpState = ((RestorableUniformRandomProvider) generator).saveState();
153 Assumptions.assumeTrue(preJumpState instanceof RandomProviderDefaultState, "Not a recognised state");
154
155 final UniformRandomProvider copy = jumpFunction.jump();
156
157 final RandomProviderState copyState = ((RestorableUniformRandomProvider) copy).saveState();
158 final RandomProviderDefaultState expected = (RandomProviderDefaultState) preJumpState;
159 final RandomProviderDefaultState actual = (RandomProviderDefaultState) copyState;
160 Assertions.assertArrayEquals(expected.getState(), actual.getState(),
161 "The copy instance state should match the state of the original");
162 }
163 }
164
165
166
167
168
169 @ParameterizedTest
170 @MethodSource("getJumpableProviders")
171 void testJumpResetsDefaultState(JumpableUniformRandomProvider generator) {
172 assertJumpResetsDefaultState(generator::jump, generator);
173 }
174
175
176
177
178
179 @ParameterizedTest
180 @MethodSource("getJumpableProviders")
181 void testLongJumpResetsDefaultState(JumpableUniformRandomProvider generator) {
182 assertJumpResetsDefaultState(getLongJumpFunction(generator), generator);
183 }
184
185
186
187
188
189
190
191
192
193
194
195 private static void assertJumpResetsDefaultState(TestJumpFunction jumpFunction,
196 JumpableUniformRandomProvider generator) {
197 byte[] expected;
198 if (generator instanceof IntProvider) {
199 expected = INT_PROVIDER_STATE;
200 } else if (generator instanceof LongProvider) {
201 expected = LONG_PROVIDER_STATE;
202 } else {
203 throw new AssertionError("Unsupported RNG");
204 }
205 final int stateSize = expected.length;
206 for (int repeats = 0; repeats < 2; repeats++) {
207
208
209
210
211 generator.nextInt();
212 generator.nextBoolean();
213
214 jumpFunction.jump();
215
216
217 final RandomProviderState postJumpState = ((RestorableUniformRandomProvider) generator).saveState();
218 final byte[] actual = ((RandomProviderDefaultState) postJumpState).getState();
219
220 Assumptions.assumeTrue(actual.length >= stateSize, "Implementation has removed default state");
221
222
223
224 final byte[] defaultState = Arrays.copyOfRange(actual, actual.length - stateSize, actual.length);
225 Assertions.assertArrayEquals(expected, defaultState,
226 "The jump should reset the default state to zero");
227 }
228 }
229
230
231
232
233 static class State32Generator extends IntProvider {
234
235 @Override
236 public int next() {
237 return 0;
238 }
239
240
241
242
243
244
245
246 byte[] getState() {
247 return getStateInternal();
248 }
249 }
250
251
252
253
254 static class State64Generator extends LongProvider {
255
256 @Override
257 public long next() {
258 return 0;
259 }
260
261
262
263
264
265
266
267 byte[] getState() {
268 return getStateInternal();
269 }
270 }
271
272
273
274
275
276
277
278 interface TestJumpFunction {
279
280
281
282
283
284 UniformRandomProvider jump();
285 }
286 }