Permalink
Browse files

initial classes

  • Loading branch information...
pholser committed Oct 18, 2010
1 parent cacbbe4 commit 03b912cb7460724f95002957e39ef97c43d0e2e0
@@ -0,0 +1,63 @@
+package com.pholser.junit.parameters;
+
+import java.util.Random;
+
+public abstract class AbstractJDKSourceOfRandomness implements SourceOfRandomness {
+ private final Random random;
+
+ protected AbstractJDKSourceOfRandomness(Random random) {
+ this.random = random;
+ }
+
+ @Override
+ public boolean nextBoolean() {
+ return random.nextBoolean();
+ }
+
+ @Override
+ public void nextBytes(byte[] bytes) {
+ random.nextBytes(bytes);
+ }
+
+ @Override
+ public byte[] nextBytes(int length) {
+ byte[] bytes = new byte[length];
+ nextBytes(bytes);
+ return bytes;
+ }
+
+ @Override
+ public double nextDouble() {
+ return random.nextDouble();
+ }
+
+ @Override
+ public float nextFloat() {
+ return random.nextFloat();
+ }
+
+ @Override
+ public double nextGaussian() {
+ return random.nextGaussian();
+ }
+
+ @Override
+ public int nextInt() {
+ return random.nextInt();
+ }
+
+ @Override
+ public int nextInt(int n) {
+ return random.nextInt(n);
+ }
+
+ @Override
+ public long nextLong() {
+ return random.nextLong();
+ }
+
+ @Override
+ public void setSeed(long seed) {
+ random.setSeed(seed);
+ }
+}
@@ -0,0 +1,13 @@
+package com.pholser.junit.parameters;
+
+import static java.lang.annotation.ElementType.*;
+import static java.lang.annotation.RetentionPolicy.*;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+@Target(PARAMETER)
+@Retention(RUNTIME)
+public @interface ExtractedBy {
+ Class<? extends RandomValueExtractor> value();
+}
@@ -0,0 +1,16 @@
+package com.pholser.junit.parameters;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.*;
+import static java.lang.annotation.RetentionPolicy.*;
+
+import org.junit.experimental.theories.ParametersSuppliedBy;
+
+@Target(PARAMETER)
+@Retention(RUNTIME)
+@ParametersSuppliedBy(GeneratingParameterSupplier.class)
+public @interface ForAll {
+ int sampleSize() default 100;
+}
@@ -0,0 +1,84 @@
+package com.pholser.junit.parameters;
+
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.junit.experimental.theories.ParameterSignature;
+import org.junit.experimental.theories.ParameterSupplier;
+import org.junit.experimental.theories.PotentialAssignment;
+
+public class GeneratingParameterSupplier extends ParameterSupplier {
+ private static final Map<Class<?>, RandomValueExtractor> extractors =
+ new HashMap<Class<?>, RandomValueExtractor>();
+
+ static {
+ extractors.put(int.class, new RandomValueExtractor() {
+ @Override
+ public Object randomValue(SourceOfRandomness random) {
+ return random.nextInt();
+ }
+ });
+ extractors.put(Integer.class, extractors.get(int.class));
+ extractors.put(double.class, new RandomValueExtractor() {
+ @Override
+ public Object randomValue(SourceOfRandomness random) {
+ return random.nextDouble();
+ }
+ });
+ extractors.put(Double.class, extractors.get(double.class));
+ extractors.put(String.class, new RandomValueExtractor() {
+ @Override
+ public Object randomValue(SourceOfRandomness random) {
+ try {
+ return new String(random.nextBytes(16), "US-ASCII");
+ } catch (UnsupportedEncodingException ex) {
+ throw new AssertionError(ex);
+ }
+ }
+ });
+ }
+
+ private final SourceOfRandomness random;
+
+ public GeneratingParameterSupplier() {
+ this(new SecureJDKSourceOfRandomness());
+ }
+
+ public GeneratingParameterSupplier(SourceOfRandomness random) {
+ this.random = random;
+ }
+
+ @Override
+ public List<PotentialAssignment> getValueSources(ParameterSignature sig) {
+ List<PotentialAssignment> potentials = new ArrayList<PotentialAssignment>();
+ ForAll generationParms = sig.getAnnotation(ForAll.class);
+ RandomValueExtractor extractor = extractor(sig);
+
+ for (int i = 0; i < generationParms.sampleSize(); ++i) {
+ Object generated = extractor.randomValue(random);
+ potentials.add(PotentialAssignment.forValue(String.valueOf(generated), generated));
+ }
+ return potentials;
+ }
+
+ private RandomValueExtractor extractor(ParameterSignature sig) {
+ ExtractedBy extractedBy = sig.getAnnotation(ExtractedBy.class);
+
+ if (extractedBy != null)
+ return instantiate(extractedBy.value());
+ return extractors.get(sig.getType());
+ }
+
+ private RandomValueExtractor instantiate(Class<? extends RandomValueExtractor> type) {
+ try {
+ return type.newInstance();
+ } catch (InstantiationException ex) {
+ throw new IllegalStateException(ex);
+ } catch (IllegalAccessException ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+}
@@ -0,0 +1,9 @@
+package com.pholser.junit.parameters;
+
+import java.util.Random;
+
+public class JDKSourceOfRandomness extends AbstractJDKSourceOfRandomness {
+ public JDKSourceOfRandomness() {
+ super(new Random());
+ }
+}
@@ -0,0 +1,5 @@
+package com.pholser.junit.parameters;
+
+interface RandomValueExtractor {
+ Object randomValue(SourceOfRandomness random);
+}
@@ -0,0 +1,13 @@
+package com.pholser.junit.parameters;
+
+import java.security.SecureRandom;
+
+public class SecureJDKSourceOfRandomness extends AbstractJDKSourceOfRandomness {
+ public SecureJDKSourceOfRandomness() {
+ super(new SecureRandom());
+ }
+
+ public SecureJDKSourceOfRandomness(byte[] seed) {
+ super(new SecureRandom(seed));
+ }
+}
@@ -0,0 +1,23 @@
+package com.pholser.junit.parameters;
+
+public interface SourceOfRandomness {
+ boolean nextBoolean();
+
+ void nextBytes(byte[] bytes);
+
+ byte[] nextBytes(int length);
+
+ double nextDouble();
+
+ float nextFloat();
+
+ double nextGaussian();
+
+ int nextInt();
+
+ int nextInt(int n);
+
+ long nextLong();
+
+ void setSeed(long seed);
+}
@@ -0,0 +1,123 @@
+package com.pholser.junit.parameters;
+
+import static org.junit.Assert.*;
+
+import java.util.Date;
+
+import org.junit.Test;
+import org.junit.experimental.theories.Theories;
+import org.junit.experimental.theories.Theory;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.RunWith;
+
+public class WhenMarkingTheoryParametersAsForAll {
+ @Test
+ public void shouldFeedDefaultNumberOfRandomIntsToAMarkedIntParameter() throws Exception {
+ JUnitCore.runClasses(ForDefaultNumberOfInts.class);
+
+ assertEquals(ForAll.class.getMethod("sampleSize").getDefaultValue(), ForDefaultNumberOfInts.iterations);
+ }
+
+ @RunWith(Theories.class)
+ public static class ForDefaultNumberOfInts {
+ static int iterations;
+
+ @Theory
+ public void shouldHold(@ForAll int i) {
+ ++iterations;
+ }
+ }
+
+ @Test
+ public void shouldFeedDefaultNumberOfRandomDoublesToAMarkedDoubleParameter() throws Exception {
+ JUnitCore.runClasses(ForDefaultNumberOfDoubles.class);
+
+ assertEquals(ForAll.class.getMethod("sampleSize").getDefaultValue(), ForDefaultNumberOfDoubles.iterations);
+ }
+
+ @RunWith(Theories.class)
+ public static class ForDefaultNumberOfDoubles {
+ static int iterations;
+
+ @Theory
+ public void shouldHold(@ForAll double d) {
+ ++iterations;
+ }
+ }
+
+ @Test
+ public void shouldFeedDefaultNumberOfRandomStringsToAMarkedStringParameter() throws Exception {
+ JUnitCore.runClasses(ForDefaultNumberOfStrings.class);
+
+ assertEquals(ForAll.class.getMethod("sampleSize").getDefaultValue(), ForDefaultNumberOfStrings.iterations);
+ }
+
+ @RunWith(Theories.class)
+ public static class ForDefaultNumberOfStrings {
+ static int iterations;
+
+ @Theory
+ public void shouldHold(@ForAll String s) {
+ ++iterations;
+ }
+ }
+
+ @Test
+ public void shouldAllowDifferentNumberOfRandomValuesOnAMarkedParameter() {
+ JUnitCore.runClasses(ForDefaultNumberOfStrings.class);
+
+ assertEquals(200, ForDefaultNumberOfStrings.iterations);
+ }
+
+ @RunWith(Theories.class)
+ public static class ForSpecifiedNumberOfStrings {
+ static int iterations;
+
+ @Theory
+ public void shouldHold(@ForAll(sampleSize = 200) String s) {
+ ++iterations;
+ }
+ }
+
+ @Test
+ public void shouldAllowMultipleForAllParmsOnATheoryMethod() {
+ JUnitCore.runClasses(MultipleForAlls.class);
+
+ assertEquals(15, MultipleForAlls.iterations);
+ }
+
+ @RunWith(Theories.class)
+ public static class MultipleForAlls {
+ static int iterations;
+
+ @Theory
+ public void shouldHold(@ForAll(sampleSize = 3) int i, @ForAll(sampleSize = 5) int j) {
+ ++iterations;
+ }
+ }
+
+ @Test
+ public void shouldAllowNonPrimitiveTypesToBeRandomlyGenerated() {
+ JUnitCore.runClasses(NonPrimitiveParameter.class);
+
+ assertEquals(100, RandomDateExtractor.numberOfCalls);
+ }
+
+ @RunWith(Theories.class)
+ public static class NonPrimitiveParameter {
+ @Theory
+ public void shouldHold(@ForAll @ExtractedBy(RandomDateExtractor.class) Date d) {
+ assertNotNull(d);
+ }
+ }
+
+ static class RandomDateExtractor implements RandomValueExtractor {
+ static int numberOfCalls;
+
+ @Override
+ public Object randomValue(SourceOfRandomness random) {
+ ++numberOfCalls;
+ return new Date(random.nextLong());
+ }
+ }
+}

0 comments on commit 03b912c

Please sign in to comment.