Skip to content

Commit

Permalink
Add Gen.make()
Browse files Browse the repository at this point in the history
  • Loading branch information
pholser committed Sep 11, 2016
1 parent f4855cb commit a9f7527
Show file tree
Hide file tree
Showing 5 changed files with 226 additions and 78 deletions.
Expand Up @@ -67,6 +67,15 @@ protected ComponentizedGenerator(Class<T> type) {
}

@Override public void addComponentGenerators(List<Generator<?>> newComponents) {
if (newComponents.size() != numberOfNeededComponents()) {
throw new IllegalArgumentException(
String.format(
"Needed %d components for %s, but got %d",
numberOfNeededComponents(),
getClass(),
newComponents.size()));
}

components.clear();
components.addAll(newComponents);
}
Expand Down
Expand Up @@ -148,4 +148,20 @@ <T> Generator<T> oneOf(
* @return generator that can produce values of the field's type
*/
Generator<?> field(Field field);

/**
* <p>Makes a new generator of the given type, provides it with access to
* other available generators,
* {@linkplain Generator#configure(java.lang.reflect.AnnotatedType)
* configures} it with any configuration annotations present on the
* generator type, and supplies it any
* {@linkplain Generator#hasComponents() component generators} it needs.
*
* @param <T> type of objects produced by the resulting generator
* @param genType type of generator to create
* @return a generator for producing values
*/
<T extends Generator<?>> T make(
Class<T> genType,
Generator<?>... componentGenerators);
}
Expand Up @@ -52,6 +52,7 @@ a copy of this software and associated documentation files (the
import org.javaruntype.type.TypeParameter;
import org.javaruntype.type.Types;

import static java.util.Arrays.*;
import static java.util.Collections.*;

import static com.pholser.junit.quickcheck.internal.Items.*;
Expand Down Expand Up @@ -121,7 +122,7 @@ private void registerGeneratorForType(Class<?> type, Generator<?> generator) {
if (constructor == null) {
throw new IllegalArgumentException(
"No constructor found for " + type
+ " with argument types " + Arrays.asList(argumentTypes));
+ " with argument types " + asList(argumentTypes));
}

Ctor<U> ctor = new Ctor<>(constructor);
Expand Down Expand Up @@ -193,7 +194,20 @@ private void registerGeneratorForType(Class<?> type, Generator<?> generator) {
return (Generator<T>) new CompositeGenerator(weightings);
}

public Generator<?> produceGenerator(ParameterTypeContext parameter) {
@SafeVarargs
@Override public final <T extends Generator<?>> T make(
Class<T> genType,
Generator<?>... components) {

T generator = instantiate(genType);
generator.provide(this);
generator.configure(genType);
generator.addComponentGenerators(asList(components));

return generator;
}

Generator<?> produceGenerator(ParameterTypeContext parameter) {
Generator<?> generator = generatorFor(parameter);
generator.provide(this);
generator.configure(parameter.annotatedType());
Expand Down Expand Up @@ -342,7 +356,7 @@ private static Generator<?> copyOf(Generator<?> generator) {
return instantiate(generator.getClass());
}

public static org.javaruntype.type.Type<?> token(Type type) {
private static org.javaruntype.type.Type<?> token(Type type) {
return Types.forJavaLangReflectType(type);
}
}
166 changes: 137 additions & 29 deletions core/src/test/java/com/pholser/junit/quickcheck/ComposedObjectsTest.java
Expand Up @@ -44,11 +44,11 @@ a copy of this software and associated documentation files (the

public class ComposedObjectsTest {
@Test public void askingForGeneratorsByType() {
assertThat(testResult(AskingForGeneratorsByType.class), isSuccessful());
assertThat(testResult(GeneratorsByType.class), isSuccessful());
}

@RunWith(JUnitQuickcheck.class)
public static class AskingForGeneratorsByType {
public static class GeneratorsByType {
static class A {
Foo foo;
}
Expand All @@ -58,7 +58,10 @@ public MakeA() {
super(A.class);
}

@Override public A generate(SourceOfRandomness random, GenerationStatus status) {
@Override public A generate(
SourceOfRandomness random,
GenerationStatus status) {

A a = new A();
a.foo = gen().type(Foo.class).generate(random, status);
return a;
Expand All @@ -70,11 +73,11 @@ public MakeA() {
}

@Test public void askingForGeneratorsForIndividualFields() {
assertThat(testResult(AskingForIndividualFields.class), isSuccessful());
assertThat(testResult(IndividualFields.class), isSuccessful());
}

@RunWith(JUnitQuickcheck.class)
public static class AskingForIndividualFields {
public static class IndividualFields {
static class A {
@X Foo foo;
@X Box<@Same(3) Foo> boxOfFoo;
Expand All @@ -86,10 +89,15 @@ public MakeA() {
}

@SuppressWarnings("unchecked")
@Override public A generate(SourceOfRandomness random, GenerationStatus status) {
@Override public A generate(
SourceOfRandomness random,
GenerationStatus status) {

A a = new A();
a.foo = (Foo) gen().field(A.class, "foo").generate(random, status);
a.boxOfFoo = (Box<Foo>) gen().field(A.class, "boxOfFoo").generate(random, status);
a.foo = (Foo) gen().field(A.class, "foo")
.generate(random, status);
a.boxOfFoo = (Box<Foo>) gen().field(A.class, "boxOfFoo")
.generate(random, status);
return a;
}
}
Expand All @@ -103,11 +111,11 @@ public MakeA() {
}

@Test public void askingForGeneratorsForAllFieldsOfClassAtOnce() {
assertThat(testResult(AskingForAllFieldsAtOnce.class), isSuccessful());
assertThat(testResult(AllFieldsAtOnce.class), isSuccessful());
}

@RunWith(JUnitQuickcheck.class)
public static class AskingForAllFieldsAtOnce {
public static class AllFieldsAtOnce {
public static class B {
Foo foo;
@From(ABox.class) Box<@X @From(AnotherBox.class) Box<@X Foo>> boxOfBoxOfFoo;
Expand All @@ -122,7 +130,10 @@ public MakeA() {
super(A.class);
}

@Override public A generate(SourceOfRandomness random, GenerationStatus status) {
@Override public A generate(
SourceOfRandomness random,
GenerationStatus status) {

A a = new A();
a.b = gen().fieldsOf(B.class).generate(random, status);
return a;
Expand All @@ -138,16 +149,19 @@ public MakeA() {
}

@Test public void askingForGeneratorsByConstructor() {
assertThat(testResult(AskingByConstructor.class), isSuccessful());
assertThat(testResult(ByConstructor.class), isSuccessful());
}

@RunWith(JUnitQuickcheck.class)
public static class AskingByConstructor {
public static class ByConstructor {
public static class B {
final Foo foo;
final Box<@X Box<@X Foo>> boxOfBoxOfFoo;

public B(@Same(6) Foo foo, Box<@X Box<@X @Same(7) Foo>> boxOfBoxOfFoo) {
public B(
@Same(6) Foo foo,
Box<@X Box<@X @Same(7) Foo>> boxOfBoxOfFoo) {

this.foo = foo;
this.boxOfBoxOfFoo = boxOfBoxOfFoo;
}
Expand All @@ -162,9 +176,13 @@ public MakeA() {
super(A.class);
}

@Override public A generate(SourceOfRandomness random, GenerationStatus status) {
@Override public A generate(
SourceOfRandomness random,
GenerationStatus status) {

A a = new A();
a.b = gen().constructor(B.class, Foo.class, Box.class).generate(random, status);
a.b = gen().constructor(B.class, Foo.class, Box.class)
.generate(random, status);
return a;
}
}
Expand All @@ -179,17 +197,21 @@ public MakeA() {

@Test public void askingForGeneratorsByUnrecognizedConstructor() {
assertThat(
testResult(AskingByUnrecognizedConstructor.class),
hasSingleFailureContaining("java.lang.IllegalArgumentException: No constructor found for class"));
testResult(UnrecognizedConstructor.class),
hasSingleFailureContaining(
"java.lang.IllegalArgumentException: No constructor found for class"));
}

@RunWith(JUnitQuickcheck.class)
public static class AskingByUnrecognizedConstructor {
public static class UnrecognizedConstructor {
public static class B {
final Foo foo;
final Box<@X Box<@X Foo>> boxOfBoxOfFoo;

public B(@Same(6) Foo foo, Box<@X Box<@X @Same(7) Foo>> boxOfBoxOfFoo) {
public B(
@Same(6) Foo foo,
Box<@X Box<@X @Same(7) Foo>> boxOfBoxOfFoo) {

this.foo = foo;
this.boxOfBoxOfFoo = boxOfBoxOfFoo;
}
Expand All @@ -204,9 +226,13 @@ public MakeA() {
super(A.class);
}

@Override public A generate(SourceOfRandomness random, GenerationStatus status) {
@Override public A generate(
SourceOfRandomness random,
GenerationStatus status) {

A a = new A();
a.b = gen().constructor(B.class, int.class).generate(random, status);
a.b = gen().constructor(B.class, int.class)
.generate(random, status);
return a;
}
}
Expand All @@ -231,7 +257,10 @@ public MakeA() {
super(A.class);
}

@Override public A generate(SourceOfRandomness random, GenerationStatus status) {
@Override public A generate(
SourceOfRandomness random,
GenerationStatus status) {

A a = new A();
a.foos = gen().type(Foo[][].class).generate(random, status);
return a;
Expand All @@ -244,11 +273,11 @@ public MakeA() {

@Test
public void askingForRawComponentizedType() {
assertThat(testResult(AskingForRawComponentizedType.class), isSuccessful());
assertThat(testResult(RawComponentizedType.class), isSuccessful());
}

@RunWith(JUnitQuickcheck.class)
public static class AskingForRawComponentizedType {
public static class RawComponentizedType {
static class A {
Box b;
}
Expand All @@ -258,7 +287,10 @@ public MakeA() {
super(A.class);
}

@Override public A generate(SourceOfRandomness random, GenerationStatus status) {
@Override public A generate(
SourceOfRandomness random,
GenerationStatus status) {

A a = new A();
a.b = gen().type(Box.class).generate(random, status);
return a;
Expand All @@ -271,11 +303,13 @@ public MakeA() {

@Test
public void askingForArrayOfRawComponentizedType() {
assertThat(testResult(AskingForArrayOfRawComponentizedType.class), isSuccessful());
assertThat(
testResult(ArrayOfRawComponentizedType.class),
isSuccessful());
}

@RunWith(JUnitQuickcheck.class)
public static class AskingForArrayOfRawComponentizedType {
public static class ArrayOfRawComponentizedType {
static class A {
Box[] b;
}
Expand All @@ -285,7 +319,10 @@ public MakeA() {
super(A.class);
}

@Override public A generate(SourceOfRandomness random, GenerationStatus status) {
@Override public A generate(
SourceOfRandomness random,
GenerationStatus status) {

A a = new A();
a.b = gen().type(Box[].class).generate(random, status);
return a;
Expand All @@ -295,4 +332,75 @@ public MakeA() {
@Property public void holds(@From(MakeA.class) A a) {
}
}

@Test public void askingToMakeASpecificKindOfGenerator() {
assertThat(testResult(SpecificGenerator.class), isSuccessful());
}

@RunWith(JUnitQuickcheck.class)
public static class SpecificGenerator {
@X public static class AnXBox extends ABox {
}

static class A {
Box<Foo> boxOfFoos;
}

public static class MakeA extends Generator<A> {
public MakeA() {
super(A.class);
}

@Override public A generate(
SourceOfRandomness random,
GenerationStatus status) {

A a = new A();
AnXBox make = gen().make(AnXBox.class, gen().type(Foo.class));
a.boxOfFoos = (Box<Foo>) make.generate(random, status);
return a;
}
}

@Property public void holds(@From(MakeA.class) A a) {
assertTrue(a.boxOfFoos.marked());
}
}

@Test public void specificKindOfGeneratorWithMissingComponents() {
assertThat(
testResult(SpecificGeneratorWithMissingComponents.class),
hasSingleFailureContaining(
"IllegalArgumentException: Needed 1 components"));
}

@RunWith(JUnitQuickcheck.class)
public static class SpecificGeneratorWithMissingComponents {
@X public static class AnXBox extends ABox {
}

static class A {
Box<Foo> boxOfFoos;
}

public static class MakeA extends Generator<A> {
public MakeA() {
super(A.class);
}

@Override public A generate(
SourceOfRandomness random,
GenerationStatus status) {

A a = new A();
AnXBox make = gen().make(AnXBox.class);
a.boxOfFoos = (Box<Foo>) make.generate(random, status);
return a;
}
}

@Property public void holds(@From(MakeA.class) A a) {
assertTrue(a.boxOfFoos.marked());
}
}
}

0 comments on commit a9f7527

Please sign in to comment.