Skip to content

Commit

Permalink
initial classes
Browse files Browse the repository at this point in the history
  • Loading branch information
pholser committed Oct 18, 2010
1 parent cacbbe4 commit 03b912c
Show file tree
Hide file tree
Showing 9 changed files with 349 additions and 0 deletions.
@@ -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);
}
}
13 changes: 13 additions & 0 deletions src/main/java/com/pholser/junit/parameters/ExtractedBy.java
@@ -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();
}
16 changes: 16 additions & 0 deletions src/main/java/com/pholser/junit/parameters/ForAll.java
@@ -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));
}
}
23 changes: 23 additions & 0 deletions src/main/java/com/pholser/junit/parameters/SourceOfRandomness.java
@@ -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.