This is an automated email from the ASF dual-hosted git repository. aherbert pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/commons-rng.git
commit c030d858076cc106213831cb8361d1f342bf26a2 Author: aherbert <[email protected]> AuthorDate: Mon Jun 10 12:46:41 2019 +0100 RNG-97: Move common tests to JumpableProvidersParametricTest. Add test that the default state in IntProvider and LongProvider is reset after a jump. --- .../rng/core/JumpableProvidersParametricTest.java | 209 +++++++++++++++++++++ .../org/apache/commons/rng/core/ProvidersList.java | 29 +++ .../org/apache/commons/rng/core/RandomAssert.java | 43 ----- .../rng/core/source32/XoShiRo128PlusTest.java | 5 - .../rng/core/source32/XoShiRo128StarStarTest.java | 5 - .../rng/core/source64/XoRoShiRo128PlusTest.java | 5 - .../core/source64/XoRoShiRo128StarStarTest.java | 5 - .../rng/core/source64/XoShiRo256PlusTest.java | 5 - .../rng/core/source64/XoShiRo256StarStarTest.java | 5 - .../rng/core/source64/XoShiRo512PlusTest.java | 5 - .../rng/core/source64/XoShiRo512StarStarTest.java | 5 - .../rng/core/source64/XorShift1024StarPhiTest.java | 5 - .../rng/core/source64/XorShift1024StarTest.java | 5 - 13 files changed, 238 insertions(+), 93 deletions(-) diff --git a/commons-rng-core/src/test/java/org/apache/commons/rng/core/JumpableProvidersParametricTest.java b/commons-rng-core/src/test/java/org/apache/commons/rng/core/JumpableProvidersParametricTest.java new file mode 100644 index 0000000..ec517e6 --- /dev/null +++ b/commons-rng-core/src/test/java/org/apache/commons/rng/core/JumpableProvidersParametricTest.java @@ -0,0 +1,209 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.rng.core; + +import org.junit.Assert; +import org.junit.Assume; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +import java.util.Arrays; + +import org.apache.commons.rng.JumpableUniformRandomProvider; +import org.apache.commons.rng.RandomProviderState; +import org.apache.commons.rng.RestorableUniformRandomProvider; +import org.apache.commons.rng.UniformRandomProvider; +import org.apache.commons.rng.core.source32.IntProvider; +import org.apache.commons.rng.core.source64.LongProvider; + +/** + * Tests which all {@link JumpableUniformRandomProvider} generators must pass. + */ +@RunWith(value = Parameterized.class) +public class JumpableProvidersParametricTest { + /** The size of the state for the IntProvider. */ + private static final int intProviderStateSize; + /** The size of the state for the LongProvider. */ + private static final int longProviderStateSize; + + static { + intProviderStateSize = new State32Generator().getStateSize(); + longProviderStateSize = new State64Generator().getStateSize(); + } + + /** RNG under test. */ + private final JumpableUniformRandomProvider generator; + + /** + * Initializes generator instance. + * + * @param rng RNG to be tested. + */ + public JumpableProvidersParametricTest(JumpableUniformRandomProvider rng) { + generator = rng; + } + + /** + * Gets the list of Jumpable generators. + * + * @return the list + */ + @Parameters(name = "{index}: data={0}") + public static Iterable<JumpableUniformRandomProvider[]> getList() { + return ProvidersList.listJumpable(); + } + + /** + * Test that the random generator returned from the jump is a new instance of the same class. + */ + @Test + public void testJumpReturnsACopy() { + final UniformRandomProvider copy = generator.jump(); + Assert.assertNotSame("The copy instance should be a different object", generator, copy); + Assert.assertEquals("The copy instance should be the same class", generator.getClass(), copy.getClass()); + } + + /** + * Test that the random generator state of the copy instance returned from the jump + * function matches the input state. + * + * <p>The generator must be a {@link RestorableUniformRandomProvider} and return an + * instance of {@link RandomProviderDefaultState}.</p> + * + * <p>The input generator is sampled using methods in the + * {@link UniformRandomProvider} interface, the state is saved and a jump is + * performed. The states from the pre-jump generator and the returned copy instance + * must match.</p> + * + * <p>This test targets any cached state of the default implementation of a generator + * in {@link IntProvider} and {@link LongProvider} such as the state cached for the + * nextBoolean() and nextInt() functions.</p> + */ + @Test + public void testJumpCopyMatchesPreJumpState() { + Assume.assumeTrue("Not a restorable RNG", generator instanceof RestorableUniformRandomProvider); + + for (int repeats = 0; repeats < 2; repeats++) { + // Exercise the generator. + // This calls nextInt() once so the default implementation of LongProvider + // should have cached a state for nextInt() in one of the two repeats. + // Calls nextBoolean() to ensure a cached state in one of the two repeats. + generator.nextInt(); + generator.nextBoolean(); + + final RandomProviderState preJumpState = ((RestorableUniformRandomProvider) generator).saveState(); + Assume.assumeTrue("Not a recognised state", preJumpState instanceof RandomProviderDefaultState); + + final UniformRandomProvider copy = generator.jump(); + + final RandomProviderState copyState = ((RestorableUniformRandomProvider) copy).saveState(); + final RandomProviderDefaultState expected = (RandomProviderDefaultState) preJumpState; + final RandomProviderDefaultState actual = (RandomProviderDefaultState) copyState; + Assert.assertArrayEquals("The copy instance state should match the state of the original", + expected.getState(), actual.getState()); + } + } + + /** + * Test that a jump resets the state of the default implementation of a generator in + * {@link IntProvider} and {@link LongProvider}. + */ + @Test + public void testJumpResetsDefaultState() { + if (generator instanceof IntProvider) { + assertJumpResetsDefaultState(intProviderStateSize); + } else if (generator instanceof LongProvider) { + assertJumpResetsDefaultState(longProviderStateSize); + } + } + + /** + * Assert the jump resets the specified number of bytes of the state. The bytes are + * checked from the end of the saved state. + * + * <p>This is intended to check the default state of the base implementation of + * {@link IntProvider} and {@link LongProvider} is reset.</p> + * + * @param stateSize the state size + */ + private void assertJumpResetsDefaultState(int stateSize) { + final byte[] expected = new byte[stateSize]; + for (int repeats = 0; repeats < 2; repeats++) { + // Exercise the generator. + // This calls nextInt() once so the default implementation of LongProvider + // should have cached a state for nextInt() in one of the two repeats. + // Calls nextBoolean() to ensure a cached state in one of the two repeats. + generator.nextInt(); + generator.nextBoolean(); + + generator.jump(); + + // An Int/LongProvider so must be a RestorableUniformRandomProvider + final RandomProviderState postJumpState = ((RestorableUniformRandomProvider) generator).saveState(); + final byte[] actual = ((RandomProviderDefaultState) postJumpState).getState(); + + Assume.assumeTrue("Implementation has removed default state", actual.length >= stateSize); + + // The implementation requires that any sub-class state is prepended to the + // state thus the default state is at the end. + final byte[] defaultState = Arrays.copyOfRange(actual, actual.length - stateSize, actual.length); + Assert.assertArrayEquals("The jump should reset the default state to zero", expected, defaultState); + } + } + + /** + * Dummy class for checking the state size of the IntProvider. + */ + static class State32Generator extends IntProvider { + /** {@inheritDoc} */ + @Override + public int next() { + return 0; + } + + /** + * Gets the state size. This captures the state size of the IntProvider. + * + * @return the state size + */ + int getStateSize() { + return getStateInternal().length; + } + } + + /** + * Dummy class for checking the state size of the LongProvider. + */ + static class State64Generator extends LongProvider { + /** {@inheritDoc} */ + @Override + public long next() { + return 0; + } + + /** + * Gets the state size. This captures the state size of the LongProvider. + * + * @return the state size + */ + int getStateSize() { + return getStateInternal().length; + } + } +} diff --git a/commons-rng-core/src/test/java/org/apache/commons/rng/core/ProvidersList.java b/commons-rng-core/src/test/java/org/apache/commons/rng/core/ProvidersList.java index de58d21..163fd09 100644 --- a/commons-rng-core/src/test/java/org/apache/commons/rng/core/ProvidersList.java +++ b/commons-rng-core/src/test/java/org/apache/commons/rng/core/ProvidersList.java @@ -47,6 +47,7 @@ import org.apache.commons.rng.core.source64.XoShiRo256StarStar; import org.apache.commons.rng.core.source64.XoShiRo512Plus; import org.apache.commons.rng.core.source64.XoShiRo512StarStar; import org.apache.commons.rng.core.source64.MersenneTwister64; +import org.apache.commons.rng.JumpableUniformRandomProvider; import org.apache.commons.rng.RestorableUniformRandomProvider; /** @@ -68,6 +69,9 @@ public class ProvidersList { /** List of 64-bits based RNGs. */ private static final List<RestorableUniformRandomProvider[]> LIST64 = new ArrayList<RestorableUniformRandomProvider[]>(); + /** List of {@link JumpableUniformRandomProvider} RNGs. */ + private static final List<JumpableUniformRandomProvider[]> LIST_JUMP = + new ArrayList<JumpableUniformRandomProvider[]>(); static { // External generator for creating a random seed. @@ -111,6 +115,12 @@ public class ProvidersList { // Complete list. LIST.addAll(LIST32); LIST.addAll(LIST64); + // Dynamically identify the Jumpable RNGs + for (RestorableUniformRandomProvider[] rng : LIST) { + if (rng[0] instanceof JumpableUniformRandomProvider) { + add(LIST_JUMP, (JumpableUniformRandomProvider) rng[0]); + } + } } catch (Exception e) { System.err.println("Unexpected exception while creating the list of generators: " + e); e.printStackTrace(System.err); @@ -133,6 +143,15 @@ public class ProvidersList { } /** + * Helper to statisfy Junit requirement that each parameter set contains + * the same number of objects. + */ + private static void add(List<JumpableUniformRandomProvider[]> list, + JumpableUniformRandomProvider rng) { + list.add(new JumpableUniformRandomProvider[] { rng }); + } + + /** * Subclasses that are "parametric" tests can forward the call to * the "@Parameters"-annotated method to this method. * @@ -161,4 +180,14 @@ public class ProvidersList { public static Iterable<RestorableUniformRandomProvider[]> list64() { return Collections.unmodifiableList(LIST64); } + + /** + * Subclasses that are "parametric" tests can forward the call to + * the "@Parameters"-annotated method to this method. + * + * @return the list of {@link JumpableUniformRandomProvider} generators. + */ + public static Iterable<JumpableUniformRandomProvider[]> listJumpable() { + return Collections.unmodifiableList(LIST_JUMP); + } } diff --git a/commons-rng-core/src/test/java/org/apache/commons/rng/core/RandomAssert.java b/commons-rng-core/src/test/java/org/apache/commons/rng/core/RandomAssert.java index 2eb409f..b3743ce 100644 --- a/commons-rng-core/src/test/java/org/apache/commons/rng/core/RandomAssert.java +++ b/commons-rng-core/src/test/java/org/apache/commons/rng/core/RandomAssert.java @@ -135,49 +135,6 @@ public class RandomAssert { } /** - * Assert that the random generator state of the copy instance returned from the - * jump function matches the input state. - * - * <p>The generator must be a {@link RestorableUniformRandomProvider} and return - * an instance of {@link RandomProviderDefaultState}.</p> - * - * <p>The input generator is sampled using methods in the - * {@link UniformRandomProvider} interface, the state is saved and a jump is - * performed. The states from the pre-jump generator and the returned copy - * instance must match.</p> - * - * <p>This test targets any cached state of the default implementation of a generator - * in {@link org.apache.commons.rng.core.source32.IntProvider IntProvider} and - * {@link org.apache.commons.rng.core.source64.LongProvider LongProvider} - * such as the state cached for the nextBoolean() and nextInt() functions.</p> - * - * @param rng Random generator. - */ - public static void assertJumpUsingState(JumpableUniformRandomProvider rng) { - Assume.assumeTrue("Not a restorable RNG", rng instanceof RestorableUniformRandomProvider); - - // Exercise the generator. - // This calls nextInt() an odd number of times so the default - // implementation of LongProvider should have cached a state for nextInt(). - for (int i = 0; i < 3; i++) { - rng.nextInt(); - rng.nextLong(); - rng.nextBoolean(); - } - - final RandomProviderState preJumpState = ((RestorableUniformRandomProvider) rng).saveState(); - Assume.assumeTrue("Not a recognised state", preJumpState instanceof RandomProviderDefaultState); - - final UniformRandomProvider copy = rng.jump(); - Assert.assertNotSame("The copy instance should be a different object", rng, copy); - - final RandomProviderState copyState = ((RestorableUniformRandomProvider)copy).saveState(); - final RandomProviderDefaultState expected = (RandomProviderDefaultState) preJumpState; - final RandomProviderDefaultState actual = (RandomProviderDefaultState) copyState; - Assert.assertArrayEquals(expected.getState(), actual.getState()); - } - - /** * Assert that the two random generators produce the same output for * {@link UniformRandomProvider#nextInt()} over the given number of cycles. * diff --git a/commons-rng-core/src/test/java/org/apache/commons/rng/core/source32/XoShiRo128PlusTest.java b/commons-rng-core/src/test/java/org/apache/commons/rng/core/source32/XoShiRo128PlusTest.java index 4fad812..80dd21e 100644 --- a/commons-rng-core/src/test/java/org/apache/commons/rng/core/source32/XoShiRo128PlusTest.java +++ b/commons-rng-core/src/test/java/org/apache/commons/rng/core/source32/XoShiRo128PlusTest.java @@ -90,9 +90,4 @@ public class XoShiRo128PlusTest { public void testJump() { RandomAssert.assertJumpEquals(EXPECTED_SEQUENCE, EXPECTED_SEQUENCE_AFTER_JUMP, new XoShiRo128Plus(SEED)); } - - @Test - public void testJumpUsingState() { - RandomAssert.assertJumpUsingState(new XoShiRo128Plus(SEED)); - } } diff --git a/commons-rng-core/src/test/java/org/apache/commons/rng/core/source32/XoShiRo128StarStarTest.java b/commons-rng-core/src/test/java/org/apache/commons/rng/core/source32/XoShiRo128StarStarTest.java index 485bcd3..bd5b6ab 100644 --- a/commons-rng-core/src/test/java/org/apache/commons/rng/core/source32/XoShiRo128StarStarTest.java +++ b/commons-rng-core/src/test/java/org/apache/commons/rng/core/source32/XoShiRo128StarStarTest.java @@ -90,9 +90,4 @@ public class XoShiRo128StarStarTest { public void testJump() { RandomAssert.assertJumpEquals(EXPECTED_SEQUENCE, EXPECTED_SEQUENCE_AFTER_JUMP , new XoShiRo128StarStar(SEED)); } - - @Test - public void testJumpUsingState() { - RandomAssert.assertJumpUsingState(new XoShiRo128StarStar(SEED)); - } } diff --git a/commons-rng-core/src/test/java/org/apache/commons/rng/core/source64/XoRoShiRo128PlusTest.java b/commons-rng-core/src/test/java/org/apache/commons/rng/core/source64/XoRoShiRo128PlusTest.java index 0dc5666..2b27694 100644 --- a/commons-rng-core/src/test/java/org/apache/commons/rng/core/source64/XoRoShiRo128PlusTest.java +++ b/commons-rng-core/src/test/java/org/apache/commons/rng/core/source64/XoRoShiRo128PlusTest.java @@ -90,9 +90,4 @@ public class XoRoShiRo128PlusTest { public void testJump() { RandomAssert.assertJumpEquals(EXPECTED_SEQUENCE, EXPECTED_SEQUENCE_AFTER_JUMP, new XoRoShiRo128Plus(SEED)); } - - @Test - public void testJumpUsingState() { - RandomAssert.assertJumpUsingState(new XoRoShiRo128Plus(SEED)); - } } diff --git a/commons-rng-core/src/test/java/org/apache/commons/rng/core/source64/XoRoShiRo128StarStarTest.java b/commons-rng-core/src/test/java/org/apache/commons/rng/core/source64/XoRoShiRo128StarStarTest.java index 9c6df2c..776e1a6 100644 --- a/commons-rng-core/src/test/java/org/apache/commons/rng/core/source64/XoRoShiRo128StarStarTest.java +++ b/commons-rng-core/src/test/java/org/apache/commons/rng/core/source64/XoRoShiRo128StarStarTest.java @@ -90,9 +90,4 @@ public class XoRoShiRo128StarStarTest { public void testJump() { RandomAssert.assertJumpEquals(EXPECTED_SEQUENCE, EXPECTED_SEQUENCE_AFTER_JUMP, new XoRoShiRo128StarStar(SEED)); } - - @Test - public void testJumpUsingState() { - RandomAssert.assertJumpUsingState(new XoRoShiRo128StarStar(SEED)); - } } diff --git a/commons-rng-core/src/test/java/org/apache/commons/rng/core/source64/XoShiRo256PlusTest.java b/commons-rng-core/src/test/java/org/apache/commons/rng/core/source64/XoShiRo256PlusTest.java index fc99ec2..a61eda9 100644 --- a/commons-rng-core/src/test/java/org/apache/commons/rng/core/source64/XoShiRo256PlusTest.java +++ b/commons-rng-core/src/test/java/org/apache/commons/rng/core/source64/XoShiRo256PlusTest.java @@ -90,9 +90,4 @@ public class XoShiRo256PlusTest { public void testJump() { RandomAssert.assertJumpEquals(EXPECTED_SEQUENCE, EXPECTED_SEQUENCE_AFTER_JUMP, new XoShiRo256Plus(SEED)); } - - @Test - public void testJumpUsingState() { - RandomAssert.assertJumpUsingState(new XoShiRo256Plus(SEED)); - } } diff --git a/commons-rng-core/src/test/java/org/apache/commons/rng/core/source64/XoShiRo256StarStarTest.java b/commons-rng-core/src/test/java/org/apache/commons/rng/core/source64/XoShiRo256StarStarTest.java index 7aaa19a..c4c6e55 100644 --- a/commons-rng-core/src/test/java/org/apache/commons/rng/core/source64/XoShiRo256StarStarTest.java +++ b/commons-rng-core/src/test/java/org/apache/commons/rng/core/source64/XoShiRo256StarStarTest.java @@ -90,9 +90,4 @@ public class XoShiRo256StarStarTest { public void testJump() { RandomAssert.assertJumpEquals(EXPECTED_SEQUENCE, EXPECTED_SEQUENCE_AFTER_JUMP, new XoShiRo256StarStar(SEED)); } - - @Test - public void testJumpUsingState() { - RandomAssert.assertJumpUsingState(new XoShiRo256StarStar(SEED)); - } } diff --git a/commons-rng-core/src/test/java/org/apache/commons/rng/core/source64/XoShiRo512PlusTest.java b/commons-rng-core/src/test/java/org/apache/commons/rng/core/source64/XoShiRo512PlusTest.java index 0e505bf..448065d 100644 --- a/commons-rng-core/src/test/java/org/apache/commons/rng/core/source64/XoShiRo512PlusTest.java +++ b/commons-rng-core/src/test/java/org/apache/commons/rng/core/source64/XoShiRo512PlusTest.java @@ -92,9 +92,4 @@ public class XoShiRo512PlusTest { public void testJump() { RandomAssert.assertJumpEquals(EXPECTED_SEQUENCE, EXPECTED_SEQUENCE_AFTER_JUMP, new XoShiRo512Plus(SEED)); } - - @Test - public void testJumpUsingState() { - RandomAssert.assertJumpUsingState(new XoShiRo512Plus(SEED)); - } } diff --git a/commons-rng-core/src/test/java/org/apache/commons/rng/core/source64/XoShiRo512StarStarTest.java b/commons-rng-core/src/test/java/org/apache/commons/rng/core/source64/XoShiRo512StarStarTest.java index cbc2082..d472312 100644 --- a/commons-rng-core/src/test/java/org/apache/commons/rng/core/source64/XoShiRo512StarStarTest.java +++ b/commons-rng-core/src/test/java/org/apache/commons/rng/core/source64/XoShiRo512StarStarTest.java @@ -92,9 +92,4 @@ public class XoShiRo512StarStarTest { public void testJump() { RandomAssert.assertJumpEquals(EXPECTED_SEQUENCE, EXPECTED_SEQUENCE_AFTER_JUMP, new XoShiRo512StarStar(SEED)); } - - @Test - public void testJumpUsingState() { - RandomAssert.assertJumpUsingState(new XoShiRo512StarStar(SEED)); - } } diff --git a/commons-rng-core/src/test/java/org/apache/commons/rng/core/source64/XorShift1024StarPhiTest.java b/commons-rng-core/src/test/java/org/apache/commons/rng/core/source64/XorShift1024StarPhiTest.java index ba0ce99..f9a1fce 100644 --- a/commons-rng-core/src/test/java/org/apache/commons/rng/core/source64/XorShift1024StarPhiTest.java +++ b/commons-rng-core/src/test/java/org/apache/commons/rng/core/source64/XorShift1024StarPhiTest.java @@ -80,9 +80,4 @@ public class XorShift1024StarPhiTest { public void testJump() { RandomAssert.assertJumpEquals(EXPECTED_SEQUENCE, EXPECTED_SEQUENCE_AFTER_JUMP, new XorShift1024StarPhi(SEED)); } - - @Test - public void testJumpUsingState() { - RandomAssert.assertJumpUsingState(new XorShift1024StarPhi(SEED)); - } } diff --git a/commons-rng-core/src/test/java/org/apache/commons/rng/core/source64/XorShift1024StarTest.java b/commons-rng-core/src/test/java/org/apache/commons/rng/core/source64/XorShift1024StarTest.java index 69367f7..5aa4b04 100644 --- a/commons-rng-core/src/test/java/org/apache/commons/rng/core/source64/XorShift1024StarTest.java +++ b/commons-rng-core/src/test/java/org/apache/commons/rng/core/source64/XorShift1024StarTest.java @@ -80,9 +80,4 @@ public class XorShift1024StarTest { public void testJump() { RandomAssert.assertJumpEquals(EXPECTED_SEQUENCE, EXPECTED_SEQUENCE_AFTER_JUMP, new XorShift1024Star(SEED)); } - - @Test - public void testJumpUsingState() { - RandomAssert.assertJumpUsingState(new XorShift1024Star(SEED)); - } }
