diff --git a/src/docs/index.adoc b/src/docs/index.adoc index e2b6dd9..0fc1d34 100644 --- a/src/docs/index.adoc +++ b/src/docs/index.adoc @@ -21,4 +21,7 @@ include::combine.adoc[] include::cardinality.adoc[] +include::output.adoc[] + include::development.adoc[] + diff --git a/src/docs/output.adoc b/src/docs/output.adoc new file mode 100644 index 0000000..334f5e3 --- /dev/null +++ b/src/docs/output.adoc @@ -0,0 +1,41 @@ +== Output +Some times you need to control the output of a generator. + +=== Seeding random generation + +For random generators it can be useful to control the seed for random generation. +This will cause a consistent sequence of values to be generated by an equivalent generator. + +[source,groovy] +---- +include::{testDir}/spock/genesis/SamplesSpec.groovy[tags=seed,indent=0] +---- + +Setting the seed to different values will vary the output but will always produce the same sequence. +[source,groovy] +---- +include::{testDir}/spock/genesis/SamplesSpec.groovy[tags=differentseed,indent=0] +---- + +=== Using `with` + +You can use `with` if you would like to set some property of the +generated value. + +IMPORTANT: `with` is different from the default groovy implementation! It always returns a new generator. + +[source,groovy] +---- +include::{testDir}/spock/genesis/SamplesSpec.groovy[tags=datewith,indent=0] +---- + +=== Transforming with `map` + +Sometimes output needs to be converted to another type. the `map` method works +like groovy's `collect` but will return a new generator that lazily performs the +transformation. An example would be calling the `toString()` method. + +[source,groovy] +---- +include::{testDir}/spock/genesis/SamplesSpec.groovy[tags=transform,indent=0] +---- \ No newline at end of file diff --git a/src/docs/values.adoc b/src/docs/values.adoc index 8839f34..4ecd1e7 100644 --- a/src/docs/values.adoc +++ b/src/docs/values.adoc @@ -112,13 +112,3 @@ include::{testDir}/spock/genesis/SamplesSpec.groovy[tags=fromenum,indent=0] NOTE: `these` in general can generate values taken from a given source, in this case the source is an enum. To know more about `these` check the section `combine`. - -=== Using `with` - -You can use `with` if you would like to set some property of the -generated value. - -[source,groovy] ----- -include::{testDir}/spock/genesis/SamplesSpec.groovy[tags=datewith,indent=0] ----- diff --git a/src/main/groovy/spock/genesis/Gen.groovy b/src/main/groovy/spock/genesis/Gen.groovy index 5228945..188b518 100644 --- a/src/main/groovy/spock/genesis/Gen.groovy +++ b/src/main/groovy/spock/genesis/Gen.groovy @@ -1,5 +1,7 @@ package spock.genesis +import groovy.transform.CompileStatic +import spock.genesis.extension.ExtensionMethods import spock.genesis.generators.CyclicGenerator import spock.genesis.generators.FactoryGenerator import spock.genesis.generators.Generator @@ -25,6 +27,7 @@ import java.util.regex.Pattern * Static factory methods for Generators */ @SuppressWarnings(['MethodCount']) +@CompileStatic class Gen { /** @@ -146,18 +149,6 @@ class Gen { new LongGenerator() } - /** - * Produces a {@link CharacterGenerator} capable of producing - * random values of type {@link Character} - * - * @return an infinite lazy {@link CharacterGenerator} - * @deprecated use {@link Gen#getCharacter} instead - */ - @Deprecated - static CharacterGenerator getChar() { - new CharacterGenerator() - } - /** * Produces a {@link CharacterGenerator} capable of producing * random values of type {@link Character} @@ -198,7 +189,7 @@ class Gen { * @param value value you want to produce over an over again * @return an infinite lazy of type {@link ValueGenerator} */ - static ValueGenerator value(value) { + static ValueGenerator value(T value) { new ValueGenerator(value) } @@ -210,7 +201,7 @@ class Gen { * from * @return a {@link RandomElementGenerator} */ - static RandomElementGenerator any(Collection source) { + static RandomElementGenerator any(Collection source) { new RandomElementGenerator(source) } @@ -222,7 +213,7 @@ class Gen { * from * @return a {@link RandomElementGenerator} */ - static RandomElementGenerator any(Object... source) { + static RandomElementGenerator any(T... source) { new RandomElementGenerator(source.toList()) } @@ -245,7 +236,7 @@ class Gen { * @param target type of the object we would like to generate * @return an instance of {@link PojoGenerator} */ - static PojoGenerator type(Map keysToValueGenerators, Class target) { + static PojoGenerator type(Map keysToValueGenerators, T target) { new PojoGenerator(target, map(keysToValueGenerators)) } @@ -257,7 +248,7 @@ class Gen { * @param argGenerators generators per each field * @return an instance of {@link PojoGenerator} */ - static PojoGenerator type(T target, Iterable... argGenerators) { + static PojoGenerator type(T target, Iterable... argGenerators) { new PojoGenerator(target, tuple(argGenerators)) } @@ -280,8 +271,8 @@ class Gen { * @param valueGenerator generators of map values * @return an instance of {@link RandomMapGenerator} */ - static RandomMapGenerator map(Iterable keyGenerator, Iterable valueGenerator) { - new RandomMapGenerator(keyGenerator, valueGenerator) + static RandomMapGenerator map(Iterable keyGenerator, Iterable valueGenerator) { + new RandomMapGenerator(keyGenerator, valueGenerator) } /** @@ -291,7 +282,7 @@ class Gen { * @param valueGenerator generates values of the produced list * @return an instance of {@link ListGenerator} */ - static ListGenerator list(Generator valueGenerator) { + static ListGenerator list(Generator valueGenerator) { new ListGenerator(valueGenerator) } @@ -304,7 +295,7 @@ class Gen { * @param maxLength maximum length of generated lists * @return an instance of {@link ListGenerator} */ - static ListGenerator list(Generator valueGenerator, int maxLength) { + static ListGenerator list(Generator valueGenerator, int maxLength) { new ListGenerator(valueGenerator, maxLength) } @@ -329,7 +320,7 @@ class Gen { * @param generators generators for each tuple element * @return an instance of {@link TupleGenerator} */ - static TupleGenerator tuple(Iterable... generators) { + static TupleGenerator tuple(Iterable... generators) { new TupleGenerator(generators) } @@ -364,12 +355,12 @@ class Gen { * @param factory the closure that defines the generated value * @return an instance of {@link FactoryGenerator} */ - static FactoryGenerator using(Closure factory) { + static FactoryGenerator using(Closure factory) { new FactoryGenerator(factory) } /** - * Produces a lazy infinite {@link LimitedGenerator}. This + * Produces a lazy infinite {@link Generator}. This * generator will produce the values taken from a given {@link * Iterable} in the order they were defined * @@ -377,54 +368,54 @@ class Gen { * @param finite sets the generator as finite or not * @return an instance of {@link Generator} */ - static Generator these(Iterable iterable, boolean finite = false) { - iterable.toGenerator(finite) + static Generator these(Iterable iterable, boolean finite = false) { + ExtensionMethods.toGenerator(iterable, finite) } /** - * Produces a lazy infinite {@link LimitedGenerator}. This + * Produces a lazy infinite {@link Generator}. This * generator will produce classes of the type passed as parameter * * @param clazz the type of class you want to produce * @return an instance of {@link Generator} */ static Generator these(Class clazz) { - clazz.toGenerator() + ExtensionMethods.toGenerator(clazz) } /** - * Produces a lazy infinite {@link LimitedGenerator}. This + * Produces a lazy infinite {@link Generator}. This * generator will produce the values taken from the values passed * as arguments in the order they were defined * * @param values variable arguments to get values from * @return an instance of {@link Generator} */ - static Generator these(Object... values) { - values.toGenerator() + static Generator these(T... values) { + ExtensionMethods.toGenerator(values) } /** - * Produces a lazy infinite {@link LimitedGenerator}. This + * Produces a lazy infinite {@link Generator}. This * generator will produce the values taken from the values passed * as arguments in the order they were defined * * @param values collection to get values from * @return an instance of {@link Generator} */ - static Generator these(Collection values) { - values.toGenerator() + static Generator these(Collection values) { + ExtensionMethods.toGenerator(values) } /** - * Produces a lazy infinite {@link LimitedGenerator}. This + * Produces a lazy infinite {@link Generator}. This * generator will produce copies of the value passed as parameter * * @param value sample value * @return an instance of {@link Generator} that produces copies * of the sample value */ - static Generator once(Object value) { + static Generator once(T value) { these([value]) } } diff --git a/src/main/groovy/spock/genesis/extension/ExtensionMethods.groovy b/src/main/groovy/spock/genesis/extension/ExtensionMethods.groovy index 9253876..1f96427 100644 --- a/src/main/groovy/spock/genesis/extension/ExtensionMethods.groovy +++ b/src/main/groovy/spock/genesis/extension/ExtensionMethods.groovy @@ -17,14 +17,18 @@ class ExtensionMethods { } static Generator toGenerator(Iterable self, boolean finite = false) { - new IterableGenerator(self, finite) + if (Generator.isInstance(self)) { + (Generator) self + } else { + new IterableGenerator(self, finite) + } } static Generator toGenerator(String self) { new ObjectIteratorGenerator(self) } - static Generator toGenerator(Object self) { + static Generator toGenerator(Object self) { new ObjectIteratorGenerator(self) } diff --git a/src/main/groovy/spock/genesis/generators/Generator.groovy b/src/main/groovy/spock/genesis/generators/Generator.groovy index 2237058..5ce1e30 100644 --- a/src/main/groovy/spock/genesis/generators/Generator.groovy +++ b/src/main/groovy/spock/genesis/generators/Generator.groovy @@ -1,6 +1,7 @@ package spock.genesis.generators import groovy.transform.CompileStatic +import spock.genesis.extension.ExtensionMethods import spock.genesis.generators.values.NullGenerator /** @@ -9,6 +10,7 @@ import spock.genesis.generators.values.NullGenerator */ @CompileStatic abstract class Generator implements Iterable, Closeable { + protected final Random random = new Random() /** * Wraps this generator in a generator that returns values that matches the supplied predicate @@ -19,8 +21,8 @@ abstract class Generator implements Iterable, Closeable { new FilteredGenerator(this, predicate) } - TransformingGenerator map(Closure transform) { - new TransformingGenerator(this, transform) + public TransformingGenerator map(Closure transform) { + new TransformingGenerator(this, transform) } TransformingGenerator with(Closure transform) { @@ -36,10 +38,10 @@ abstract class Generator implements Iterable, Closeable { } SequentialMultisourceGenerator then(Iterable... iterables) { - Iterable[] all = new Iterable[iterables.length + 1] + Generator[] all = new Generator[iterables.length + 1] all[0] = this for (int i = 0; i < iterables.length; i++) { - all[i + 1] = iterables[i] + all[i + 1] = ExtensionMethods.toGenerator(iterables[i]) } new SequentialMultisourceGenerator(all) @@ -95,4 +97,15 @@ abstract class Generator implements Iterable, Closeable { @SuppressWarnings('EmptyMethodInAbstractClass') void close() { } + + /** + * Set the {@link Random} seed for this generator and all contained generators. + * This method mutates the generator! + * @param seed + * @return this generator + */ + Generator seed(Long seed) { + random.setSeed(seed) + this + } } diff --git a/src/main/groovy/spock/genesis/generators/GeneratorDecorator.groovy b/src/main/groovy/spock/genesis/generators/GeneratorDecorator.groovy index 3252af1..ee75550 100644 --- a/src/main/groovy/spock/genesis/generators/GeneratorDecorator.groovy +++ b/src/main/groovy/spock/genesis/generators/GeneratorDecorator.groovy @@ -46,4 +46,10 @@ class GeneratorDecorator extends Generator implements Closeable { void close() { generator.close() } + + GeneratorDecorator seed(Long seed) { + generator.seed(seed) + super.seed(seed) + this + } } diff --git a/src/main/groovy/spock/genesis/generators/IterableGenerator.groovy b/src/main/groovy/spock/genesis/generators/IterableGenerator.groovy index 20795f9..f7ba3c7 100644 --- a/src/main/groovy/spock/genesis/generators/IterableGenerator.groovy +++ b/src/main/groovy/spock/genesis/generators/IterableGenerator.groovy @@ -4,7 +4,7 @@ import groovy.transform.CompileDynamic import groovy.transform.CompileStatic /** - * A generator that wraps an iterator to provide {@link Generator} methods. + * A generator that wraps an {@link Iterable} to provide {@link Generator} methods. * @param < E > the generated type */ @CompileStatic @@ -56,4 +56,13 @@ class IterableGenerator extends Generator implements Closeable { iterable.close() } } + + @CompileDynamic + @Override + IterableGenerator seed(Long seed) { + if (iterable.respondsTo('seed')) { + iterable.seed(seed) + } + this + } } diff --git a/src/main/groovy/spock/genesis/generators/MultiSourceGenerator.groovy b/src/main/groovy/spock/genesis/generators/MultiSourceGenerator.groovy index 8a1cf1c..3a103f8 100644 --- a/src/main/groovy/spock/genesis/generators/MultiSourceGenerator.groovy +++ b/src/main/groovy/spock/genesis/generators/MultiSourceGenerator.groovy @@ -11,7 +11,6 @@ import spock.genesis.extension.ExtensionMethods class MultiSourceGenerator extends Generator implements Closeable { private final List> generators - final Random random = new Random() MultiSourceGenerator(Collection> iterables) { this.generators = iterables.collect { ExtensionMethods.toGenerator(it) } @@ -77,4 +76,11 @@ class MultiSourceGenerator extends Generator implements Closeable { boolean isFinite() { generators.every { it.finite } } + + @Override + MultiSourceGenerator seed(Long seed) { + generators.each { it.seed(seed) } + super.seed(seed) + this + } } diff --git a/src/main/groovy/spock/genesis/generators/SequentialMultisourceGenerator.groovy b/src/main/groovy/spock/genesis/generators/SequentialMultisourceGenerator.groovy index 86055aa..3e7761d 100644 --- a/src/main/groovy/spock/genesis/generators/SequentialMultisourceGenerator.groovy +++ b/src/main/groovy/spock/genesis/generators/SequentialMultisourceGenerator.groovy @@ -1,23 +1,20 @@ package spock.genesis.generators -import groovy.transform.CompileDynamic import groovy.transform.CompileStatic @CompileStatic class SequentialMultisourceGenerator extends Generator implements Closeable { - private final List> iterables - final boolean finite + private final List> generators - SequentialMultisourceGenerator(Iterable... iterables) { - this.iterables = iterables.toList() - finite = GeneratorUtils.allFinite(iterables) + SequentialMultisourceGenerator(Generator... iterables) { + this.generators = iterables.toList() } UnmodifiableIterator iterator() { new UnmodifiableIterator() { - private Iterator current - private final Iterator> iterators = iterables.collect { it.iterator() }.iterator() + private Iterator current + private final Iterator iterators = generators.collect { it.iterator() }.iterator() boolean hasNext() { setupIterator() @@ -38,13 +35,16 @@ class SequentialMultisourceGenerator extends Generator implements Closeabl } void close() { - iterables.each { close(it) } + generators.each { it.close() } } - @CompileDynamic - void close(Iterable generator) { - if (generator.respondsTo('close')) { - generator.close() - } + boolean isFinite() { + generators.every { it.finite } + } + + SequentialMultisourceGenerator seed(Long seed) { + generators.each { it.seed(seed) } + super.seed(seed) + this } } diff --git a/src/main/groovy/spock/genesis/generators/composites/DefinedMapGenerator.groovy b/src/main/groovy/spock/genesis/generators/composites/DefinedMapGenerator.groovy index 0e88fe9..3c2bf80 100644 --- a/src/main/groovy/spock/genesis/generators/composites/DefinedMapGenerator.groovy +++ b/src/main/groovy/spock/genesis/generators/composites/DefinedMapGenerator.groovy @@ -3,7 +3,6 @@ package spock.genesis.generators.composites import groovy.transform.CompileStatic import spock.genesis.extension.ExtensionMethods import spock.genesis.generators.Generator -import spock.genesis.generators.GeneratorUtils import spock.genesis.generators.UnmodifiableIterator @CompileStatic @@ -44,6 +43,13 @@ class DefinedMapGenerator extends Generator> { } boolean isFinite() { - GeneratorUtils.anyFinite(keysToValueGenerators.values()) + keysToValueGenerators.any { k, generator -> generator.finite } + } + + @Override + DefinedMapGenerator seed(Long seed) { + keysToValueGenerators.each { k, generator -> generator.seed(seed) } + super.seed(seed) + this } } diff --git a/src/main/groovy/spock/genesis/generators/composites/ListGenerator.groovy b/src/main/groovy/spock/genesis/generators/composites/ListGenerator.groovy index 99ca97a..f0a791a 100644 --- a/src/main/groovy/spock/genesis/generators/composites/ListGenerator.groovy +++ b/src/main/groovy/spock/genesis/generators/composites/ListGenerator.groovy @@ -1,41 +1,43 @@ package spock.genesis.generators.composites +import groovy.transform.CompileStatic import spock.genesis.generators.Generator -import spock.genesis.generators.GeneratorDecorator import spock.genesis.generators.UnmodifiableIterator import spock.genesis.generators.values.WholeNumberGenerator -class ListGenerator extends GeneratorDecorator> { +@CompileStatic +class ListGenerator extends Generator> { static final int DEFAULT_LENGTH_LIMIT = 1000 - final WholeNumberGenerator lengthSource + private final Generator valueSource + private final WholeNumberGenerator lengthSource ListGenerator(Generator generator) { - super(generator) + this.valueSource = generator this.lengthSource = new WholeNumberGenerator(DEFAULT_LENGTH_LIMIT) } ListGenerator(Generator generator, int maxLength) { - super(generator) + this.valueSource = generator this.lengthSource = new WholeNumberGenerator(maxLength) } ListGenerator(Generator generator, int minLength, int maxLength) { - super(generator) + this.valueSource = generator this.lengthSource = new WholeNumberGenerator(minLength, maxLength) } ListGenerator(Generator generator, IntRange range) { - super(generator) + this.valueSource = generator this.lengthSource = new WholeNumberGenerator(range) } @Override UnmodifiableIterator> iterator() { new UnmodifiableIterator>() { - private final Iterator source = generator.iterator() - private final Iterator length = lengthSource.iterator() + private final Iterator source = valueSource.iterator() + private final Iterator length = lengthSource.iterator() @Override boolean hasNext() { @@ -44,8 +46,17 @@ class ListGenerator extends GeneratorDecorator> { @Override List next() { - source.take(length.next()).toList() + Integer size = length.next() + source.take(size).toList() } } } + + @Override + ListGenerator seed(Long seed) { + super.seed(seed) + lengthSource.seed(seed) + valueSource.seed(seed) + this + } } diff --git a/src/main/groovy/spock/genesis/generators/composites/PojoGenerator.groovy b/src/main/groovy/spock/genesis/generators/composites/PojoGenerator.groovy index 6fa2ed1..c882cd3 100644 --- a/src/main/groovy/spock/genesis/generators/composites/PojoGenerator.groovy +++ b/src/main/groovy/spock/genesis/generators/composites/PojoGenerator.groovy @@ -2,20 +2,20 @@ package spock.genesis.generators.composites import groovy.transform.CompileDynamic import groovy.transform.CompileStatic +import spock.genesis.extension.ExtensionMethods import spock.genesis.generators.Generator -import spock.genesis.generators.GeneratorUtils import spock.genesis.generators.UnmodifiableIterator import java.lang.reflect.Constructor @CompileStatic -class PojoGenerator extends Generator { +class PojoGenerator extends Generator implements Closeable { final Class target - final Iterable generator + final Generator generator - PojoGenerator(E target, Iterable generator) { + PojoGenerator(E target, Iterable generator) { this.target = target - this.generator = generator + this.generator = ExtensionMethods.toGenerator(generator) } UnmodifiableIterator iterator() { @@ -30,7 +30,7 @@ class PojoGenerator extends Generator { @Override @CompileDynamic E next() { - def params = iterator.next() + T params = iterator.next() Class clazz = params.getClass() if (hasConstructorFor(clazz)) { target.metaClass.invokeConstructor(params) @@ -51,6 +51,17 @@ class PojoGenerator extends Generator { } boolean isFinite() { - GeneratorUtils.isFinite(generator) + generator.finite + } + + void close() { + generator.close() + } + + @Override + PojoGenerator seed(Long seed) { + generator.seed(seed) + super.seed(seed) + this } } diff --git a/src/main/groovy/spock/genesis/generators/composites/RandomMapGenerator.groovy b/src/main/groovy/spock/genesis/generators/composites/RandomMapGenerator.groovy index d7f0823..83eef2b 100644 --- a/src/main/groovy/spock/genesis/generators/composites/RandomMapGenerator.groovy +++ b/src/main/groovy/spock/genesis/generators/composites/RandomMapGenerator.groovy @@ -1,9 +1,8 @@ package spock.genesis.generators.composites -import groovy.transform.CompileDynamic import groovy.transform.CompileStatic +import spock.genesis.extension.ExtensionMethods import spock.genesis.generators.Generator -import spock.genesis.generators.GeneratorUtils import spock.genesis.generators.UnmodifiableIterator import spock.genesis.generators.values.WholeNumberGenerator @@ -12,31 +11,29 @@ class RandomMapGenerator extends Generator> implements Closeable static final int DEFAULT_ENTRY_LIMIT = 100 final WholeNumberGenerator sizeSource - final Iterable keyGenerator - final Iterable valueGenerator + final Generator keyGenerator + final Generator valueGenerator RandomMapGenerator(Iterable keyGenerator, Iterable valueGenerator) { - this.sizeSource = new WholeNumberGenerator(DEFAULT_ENTRY_LIMIT) - this.keyGenerator = keyGenerator - this.valueGenerator = valueGenerator + this(keyGenerator, valueGenerator, new WholeNumberGenerator(DEFAULT_ENTRY_LIMIT)) } RandomMapGenerator(Iterable keyGenerator, Iterable valueGenerator, int maxSize) { - this.sizeSource = new WholeNumberGenerator(maxSize) - this.keyGenerator = keyGenerator - this.valueGenerator = valueGenerator + this(keyGenerator, valueGenerator, new WholeNumberGenerator(maxSize)) } RandomMapGenerator(Iterable keyGenerator, Iterable valueGenerator, int minSize, int maxSize) { - this.sizeSource = new WholeNumberGenerator(minSize, maxSize) - this.keyGenerator = keyGenerator - this.valueGenerator = valueGenerator + this(keyGenerator, valueGenerator, new WholeNumberGenerator(minSize, maxSize)) } RandomMapGenerator(Iterable keyGenerator, Iterable valueGenerator, IntRange sizeRange) { - this.sizeSource = new WholeNumberGenerator(sizeRange) - this.keyGenerator = keyGenerator - this.valueGenerator = valueGenerator + this(keyGenerator, valueGenerator, new WholeNumberGenerator(sizeRange)) + } + + RandomMapGenerator(Iterable keyGenerator, Iterable valueGenerator, WholeNumberGenerator sizeSource) { + this.sizeSource = sizeSource + this.keyGenerator = ExtensionMethods.toGenerator(keyGenerator) + this.valueGenerator = ExtensionMethods.toGenerator(valueGenerator) } UnmodifiableIterator> iterator() { @@ -64,16 +61,23 @@ class RandomMapGenerator extends Generator> implements Closeable } } - @CompileDynamic + @Override void close() { - [keyGenerator, valueGenerator].each { - if (it.respondsTo('close')) { - it.close() - } - } + keyGenerator.close() + valueGenerator.close() } + @Override boolean isFinite() { - GeneratorUtils.anyFinite(keyGenerator, valueGenerator) + keyGenerator.finite || valueGenerator.finite + } + + @Override + RandomMapGenerator seed(Long seed) { + keyGenerator.seed(seed) + valueGenerator.seed(seed) + sizeSource.seed(seed) + super.seed(seed) + this } } diff --git a/src/main/groovy/spock/genesis/generators/composites/TupleGenerator.groovy b/src/main/groovy/spock/genesis/generators/composites/TupleGenerator.groovy index 5cd61b8..69de902 100644 --- a/src/main/groovy/spock/genesis/generators/composites/TupleGenerator.groovy +++ b/src/main/groovy/spock/genesis/generators/composites/TupleGenerator.groovy @@ -3,11 +3,10 @@ package spock.genesis.generators.composites import groovy.transform.CompileStatic import spock.genesis.extension.ExtensionMethods import spock.genesis.generators.Generator -import spock.genesis.generators.GeneratorUtils import spock.genesis.generators.UnmodifiableIterator @CompileStatic -class TupleGenerator extends Generator> { +class TupleGenerator extends Generator> implements Closeable { private final List> generators @@ -39,6 +38,18 @@ class TupleGenerator extends Generator> { @Override boolean isFinite() { - GeneratorUtils.anyFinite(generators) + generators.every { it.finite } + } + + @Override + void close() { + generators.each { it.close() } + } + + @Override + TupleGenerator seed(Long seed) { + generators.each { it.seed(seed) } + super.seed(seed) + this } } diff --git a/src/main/groovy/spock/genesis/generators/values/ByteArrayGenerator.groovy b/src/main/groovy/spock/genesis/generators/values/ByteArrayGenerator.groovy index 5b46529..b3e2202 100644 --- a/src/main/groovy/spock/genesis/generators/values/ByteArrayGenerator.groovy +++ b/src/main/groovy/spock/genesis/generators/values/ByteArrayGenerator.groovy @@ -9,7 +9,6 @@ class ByteArrayGenerator extends InfiniteGenerator { static final int DEFAULT_LENGTH_LIMIT = 1024 * 10 final WholeNumberGenerator lengthSource - final Random random = new Random() ByteArrayGenerator() { this.lengthSource = new WholeNumberGenerator(DEFAULT_LENGTH_LIMIT) @@ -40,4 +39,11 @@ class ByteArrayGenerator extends InfiniteGenerator { } } } + + @Override + ByteArrayGenerator seed(Long seed) { + lengthSource.seed(seed) + super.seed(seed) + this + } } diff --git a/src/main/groovy/spock/genesis/generators/values/DateGenerator.groovy b/src/main/groovy/spock/genesis/generators/values/DateGenerator.groovy index 47d352c..e1361a2 100644 --- a/src/main/groovy/spock/genesis/generators/values/DateGenerator.groovy +++ b/src/main/groovy/spock/genesis/generators/values/DateGenerator.groovy @@ -26,4 +26,11 @@ class DateGenerator extends InfiniteGenerator { } } } + + @Override + DateGenerator seed(Long seed) { + super.seed(seed) + millisProvider.seed(seed) + this + } } diff --git a/src/main/groovy/spock/genesis/generators/values/DoubleGenerator.groovy b/src/main/groovy/spock/genesis/generators/values/DoubleGenerator.groovy index fa8da9c..0557085 100644 --- a/src/main/groovy/spock/genesis/generators/values/DoubleGenerator.groovy +++ b/src/main/groovy/spock/genesis/generators/values/DoubleGenerator.groovy @@ -7,8 +7,6 @@ import spock.genesis.generators.InfiniteIterator @CompileStatic class DoubleGenerator extends InfiniteGenerator { - final Random random = new Random() - InfiniteIterator iterator() { new InfiniteIterator() { @Override diff --git a/src/main/groovy/spock/genesis/generators/values/IntegerGenerator.groovy b/src/main/groovy/spock/genesis/generators/values/IntegerGenerator.groovy index b6a8c72..82c7bd4 100644 --- a/src/main/groovy/spock/genesis/generators/values/IntegerGenerator.groovy +++ b/src/main/groovy/spock/genesis/generators/values/IntegerGenerator.groovy @@ -9,7 +9,6 @@ class IntegerGenerator extends InfiniteGenerator { final long min final long max - final Random random = new Random() IntegerGenerator(int min = Integer.MIN_VALUE, int max = Integer.MAX_VALUE) { assert min < max diff --git a/src/main/groovy/spock/genesis/generators/values/LongGenerator.groovy b/src/main/groovy/spock/genesis/generators/values/LongGenerator.groovy index 7cf6224..1cc0817 100644 --- a/src/main/groovy/spock/genesis/generators/values/LongGenerator.groovy +++ b/src/main/groovy/spock/genesis/generators/values/LongGenerator.groovy @@ -1,6 +1,7 @@ package spock.genesis.generators.values import groovy.transform.CompileStatic +import spock.genesis.generators.Generator import spock.genesis.generators.InfiniteGenerator import spock.genesis.generators.InfiniteIterator @@ -9,7 +10,7 @@ class LongGenerator extends InfiniteGenerator { final Long min final Long max - final Random random = new Random() + private final IntegerGenerator integerGenerator LongGenerator() { this.min = Long.MIN_VALUE @@ -20,12 +21,16 @@ class LongGenerator extends InfiniteGenerator { assert min < max this.min = min this.max = max + def magnitude = magnitude(min, max) + if (magnitude <= Integer.MAX_VALUE) { + integerGenerator = new IntegerGenerator(0, magnitude as int) + } } - InfiniteIterator chooseProvider(BigInteger min, BigInteger max) { - BigInteger magnitude = max - min + InfiniteIterator chooseProvider(long min, long max) { + BigInteger magnitude = magnitude(min, max) if (magnitude <= Integer.MAX_VALUE) { - new ShiftedIntegerIterator(magnitude as int, min as long) + new ShiftedIntegerIterator(min as long) } else if (magnitude <= Long.MAX_VALUE) { new ShiftedLongIterator(magnitude as long, min as long) } else { @@ -33,8 +38,12 @@ class LongGenerator extends InfiniteGenerator { } } + private static BigInteger magnitude(long min, long max) { + max.toBigInteger() - min.toBigInteger() + } + InfiniteIterator iterator() { - final InfiniteIterator CANDIDATE_PROVIDER = chooseProvider(min.toBigInteger(), max.toBigInteger()) + final InfiniteIterator CANDIDATE_PROVIDER = chooseProvider(min, max) new InfiniteIterator() { @Override Long next() { @@ -48,13 +57,13 @@ class LongGenerator extends InfiniteGenerator { } } - private class RandomLongIterator extends InfiniteIterator { + class RandomLongIterator extends InfiniteIterator { Long next() { random.nextLong() } } - private class ShiftedLongIterator extends InfiniteIterator { + class ShiftedLongIterator extends InfiniteIterator { final long magnitude final long shift @@ -78,12 +87,12 @@ class LongGenerator extends InfiniteGenerator { } } - private class ShiftedIntegerIterator extends InfiniteIterator { + class ShiftedIntegerIterator extends InfiniteIterator { final InfiniteIterator iterator final long shift - ShiftedIntegerIterator(int magnitude, long shift) { - iterator = new IntegerGenerator(0, magnitude).iterator() + ShiftedIntegerIterator(long shift) { + iterator = integerGenerator.iterator() this.shift = shift } @@ -91,4 +100,11 @@ class LongGenerator extends InfiniteGenerator { shift + iterator.next() } } + + @Override + Generator seed(Long seed) { + super.seed(seed) + integerGenerator?.seed(seed) + this + } } diff --git a/src/main/groovy/spock/genesis/generators/values/RandomElementGenerator.groovy b/src/main/groovy/spock/genesis/generators/values/RandomElementGenerator.groovy index 84b6019..0592ff5 100644 --- a/src/main/groovy/spock/genesis/generators/values/RandomElementGenerator.groovy +++ b/src/main/groovy/spock/genesis/generators/values/RandomElementGenerator.groovy @@ -29,4 +29,11 @@ class RandomElementGenerator extends InfiniteGenerator { } } } + + @Override + RandomElementGenerator seed(Long seed) { + indexSource.seed(seed) + super.seed(seed) + this + } } diff --git a/src/main/groovy/spock/genesis/generators/values/StringGenerator.groovy b/src/main/groovy/spock/genesis/generators/values/StringGenerator.groovy index 0607ca7..3c2351a 100644 --- a/src/main/groovy/spock/genesis/generators/values/StringGenerator.groovy +++ b/src/main/groovy/spock/genesis/generators/values/StringGenerator.groovy @@ -91,4 +91,13 @@ class StringGenerator extends InfiniteGenerator { } } } + + @Override + StringGenerator seed(Long seed) { + super.seed(seed) + charGenerator?.seed(seed) + lengthSource?.seed(seed) + generex?.setSeed(seed) + this + } } diff --git a/src/main/groovy/spock/genesis/generators/values/WholeNumberGenerator.groovy b/src/main/groovy/spock/genesis/generators/values/WholeNumberGenerator.groovy index 581b5be..b1313e5 100644 --- a/src/main/groovy/spock/genesis/generators/values/WholeNumberGenerator.groovy +++ b/src/main/groovy/spock/genesis/generators/values/WholeNumberGenerator.groovy @@ -7,7 +7,6 @@ import spock.genesis.generators.InfiniteIterator @CompileStatic class WholeNumberGenerator extends InfiniteGenerator { - final Random random = new Random() final int min final int magnitude diff --git a/src/test/groovy/spock/genesis/SamplesSpec.groovy b/src/test/groovy/spock/genesis/SamplesSpec.groovy index 127d470..7bb09eb 100644 --- a/src/test/groovy/spock/genesis/SamplesSpec.groovy +++ b/src/test/groovy/spock/genesis/SamplesSpec.groovy @@ -9,10 +9,11 @@ import spock.lang.Specification import spock.lang.Unroll import spock.util.mop.Use +import static spock.genesis.Gen.* + // tag::genimport[] //static import generator factory methods -import static spock.genesis.Gen.* // end::genimport[] class SamplesSpec extends Specification { @@ -254,15 +255,16 @@ class SamplesSpec extends Specification { } // end::typegenerator[] - def 'generate type then call method on instance'() { + // tag::transform[] + @Iterations(10) + def 'transform the output of a generator'() { expect: - result instanceof Data - result.d - result.i - result.s == result.toString() + result instanceof String + result.isInteger() where: - result << type(Data, i: integer, d: date).map { it.s = it.toString(); it }.take(10) + result << integer.map { val -> val.toString() } } + // end::transform[] // tag::tupledata[] static class TupleData { @@ -442,4 +444,25 @@ class SamplesSpec extends Specification { i << these(1,2,3,4,5,6) } //end::iterations[] + + //tag::seed[] + def 'setting seed returns the same values with 2 generators configured the same'() { + given: + def generatedA = string(10).seed(879).take(10).realized + def generatedB = string(10).seed(879).take(10).realized + expect: + generatedA == generatedB + } + //end::seed[] + + //tag::differentseed[] + def 'setting seed to different values produces different sequences'() { + given: + def generatedA = integer.seed(879).take(4).realized + def generatedB = integer.seed(3).take(4).realized + expect: + generatedA == [-1295148427, 2105117961, -922763979, 1733784787] + generatedB == [-1155099828, -1879439976, 304908421, -836442134] + } + //end::differentseed[] } diff --git a/src/test/groovy/spock/genesis/extension/ExtensionMethodsSpec.groovy b/src/test/groovy/spock/genesis/extension/ExtensionMethodsSpec.groovy index 1b2a839..0c4fd6a 100644 --- a/src/test/groovy/spock/genesis/extension/ExtensionMethodsSpec.groovy +++ b/src/test/groovy/spock/genesis/extension/ExtensionMethodsSpec.groovy @@ -1,5 +1,7 @@ package spock.genesis.extension +import groovy.transform.CompileStatic +import spock.genesis.Gen import spock.genesis.generators.Generator import spock.lang.Specification import spock.lang.Unroll @@ -28,4 +30,16 @@ class ExtensionMethodsSpec extends Specification { YES, NO } + def 'to generator on generator returns the original generator through static method' () { + expect: + toGenerator(generator).is(generator) + where: + generator << [Gen.string, Gen.bytes, Gen.once('foo'), Gen.double, Gen.list(Gen.integer)] + } + + @CompileStatic + static Generator toGenerator(Iterable iterable) { + iterable.toGenerator() + } + } diff --git a/src/test/groovy/spock/genesis/generators/MultiSourceGeneratorSpec.groovy b/src/test/groovy/spock/genesis/generators/MultiSourceGeneratorSpec.groovy index 0f77001..7d94f58 100644 --- a/src/test/groovy/spock/genesis/generators/MultiSourceGeneratorSpec.groovy +++ b/src/test/groovy/spock/genesis/generators/MultiSourceGeneratorSpec.groovy @@ -1,12 +1,13 @@ package spock.genesis.generators +import spock.genesis.Gen import spock.lang.Specification class MultiSourceGeneratorSpec extends Specification { def 'multiple iterables run until all are empty'() { setup: - def generator = new MultiSourceGenerator(iterables) + def generator = new MultiSourceGenerator(iterables).seed(9809) def expectedCount = iterables*.size().sum() when: def result = generator.realized @@ -24,4 +25,14 @@ class MultiSourceGeneratorSpec extends Specification { [[null, 'b', 'c', [key: 'value']], [1, 2, 3, new Date()], (1..100).collect()] ] } + + def 'setting seed returns the same values with 2 generators configured the same'() { + given: + def generatorA = new MultiSourceGenerator([Gen.string(10), Gen.integer]).seed(seed).take(10).realized + def generatorB = new MultiSourceGenerator([Gen.string(10), Gen.integer]).seed(seed).take(10).realized + expect: + generatorA == generatorB + where: + seed = 100L + } } diff --git a/src/test/groovy/spock/genesis/generators/SequentialMultisourceGeneratorSpec.groovy b/src/test/groovy/spock/genesis/generators/SequentialMultisourceGeneratorSpec.groovy new file mode 100644 index 0000000..d8cbdf8 --- /dev/null +++ b/src/test/groovy/spock/genesis/generators/SequentialMultisourceGeneratorSpec.groovy @@ -0,0 +1,18 @@ +package spock.genesis.generators + +import spock.genesis.Gen +import spock.lang.Specification + + +class SequentialMultisourceGeneratorSpec extends Specification { + + def 'setting seed returns the same values with 2 generators configured the same'() { + given: + def generatorA = new SequentialMultisourceGenerator(Gen.string(10), Gen.integer).seed(seed).take(10).realized + def generatorB = new SequentialMultisourceGenerator(Gen.string(10), Gen.integer).seed(seed).take(10).realized + expect: + generatorA == generatorB + where: + seed = 100L + } +} diff --git a/src/test/groovy/spock/genesis/generators/composites/DefinedMapGeneratorSpec.groovy b/src/test/groovy/spock/genesis/generators/composites/DefinedMapGeneratorSpec.groovy index cef919b..f035cf1 100644 --- a/src/test/groovy/spock/genesis/generators/composites/DefinedMapGeneratorSpec.groovy +++ b/src/test/groovy/spock/genesis/generators/composites/DefinedMapGeneratorSpec.groovy @@ -1,5 +1,6 @@ package spock.genesis.generators.composites +import spock.genesis.Gen import spock.genesis.generators.values.IntegerGenerator import spock.genesis.generators.values.NullGenerator import spock.genesis.generators.values.StringGenerator @@ -47,4 +48,14 @@ class DefinedMapGeneratorSpec extends Specification { [a: []] || true [a: new IntegerGenerator().take(1)] || true } + + def 'setting seed returns the same values with 2 generators configured the same'() { + given: + def generatorA = new DefinedMapGenerator(a: Gen.string(10), b: Gen.integer).seed(seed).take(10).realized + def generatorB = new DefinedMapGenerator(a: Gen.string(10), b: Gen.integer).seed(seed).take(10).realized + expect: + generatorA == generatorB + where: + seed = 100L + } } diff --git a/src/test/groovy/spock/genesis/generators/composites/ListGeneratorSpec.groovy b/src/test/groovy/spock/genesis/generators/composites/ListGeneratorSpec.groovy index e9da595..9d2f440 100644 --- a/src/test/groovy/spock/genesis/generators/composites/ListGeneratorSpec.groovy +++ b/src/test/groovy/spock/genesis/generators/composites/ListGeneratorSpec.groovy @@ -1,18 +1,19 @@ package spock.genesis.generators.composites +import spock.genesis.Gen import spock.genesis.generators.values.IntegerGenerator import spock.genesis.generators.values.NullGenerator import spock.genesis.generators.values.StringGenerator +import spock.genesis.transform.Iterations import spock.lang.Specification class ListGeneratorSpec extends Specification { - def 'list generator next'() { setup: def generator = new ListGenerator(gen, limit) when: - def result = generator.iterator().next() + List result = generator.iterator().next() then: result.size() <= limit where: @@ -22,4 +23,15 @@ class ListGeneratorSpec extends Specification { new NullGenerator() | 1 new IntegerGenerator() | 0 } + + @Iterations + def 'setting seed returns the same values with 2 generators configured the same'() { + given: + def generatorA = new ListGenerator(Gen.string(10)).seed(seed).take(10).realized + def generatorB = new ListGenerator(Gen.string(10)).seed(seed).take(10).realized + expect: + generatorA == generatorB + where: + seed = 100L + } } diff --git a/src/test/groovy/spock/genesis/generators/composites/PojoGeneratorSpec.groovy b/src/test/groovy/spock/genesis/generators/composites/PojoGeneratorSpec.groovy index 8d67506..253f9c4 100644 --- a/src/test/groovy/spock/genesis/generators/composites/PojoGeneratorSpec.groovy +++ b/src/test/groovy/spock/genesis/generators/composites/PojoGeneratorSpec.groovy @@ -1,5 +1,6 @@ package spock.genesis.generators.composites +import spock.genesis.Gen import spock.genesis.generators.test.Pojo import spock.lang.Specification @@ -129,6 +130,17 @@ class PojoGeneratorSpec extends Specification { result.args == args } + def 'setting seed returns the same values with 2 generators configured the same'() { + setup: + def generatorA = new PojoGenerator(Pojo, Gen.map(a: Gen.string)).seed(seed).take(10).realized + def generatorB = new PojoGenerator(Pojo, Gen.map(a: Gen.string)).seed(seed).take(10).realized + expect: + generatorA == generatorB + where: + seed = 100L + + } + static class TupleConstructorObj { String string Integer integer diff --git a/src/test/groovy/spock/genesis/generators/composites/RandomMapGeneratorSpec.groovy b/src/test/groovy/spock/genesis/generators/composites/RandomMapGeneratorSpec.groovy index 371fc0a..0d9edff 100644 --- a/src/test/groovy/spock/genesis/generators/composites/RandomMapGeneratorSpec.groovy +++ b/src/test/groovy/spock/genesis/generators/composites/RandomMapGeneratorSpec.groovy @@ -1,6 +1,7 @@ package spock.genesis.generators.composites import spock.genesis.Gen +import spock.genesis.generators.Generator import spock.genesis.generators.test.CloseableIterable import spock.genesis.generators.values.IntegerGenerator import spock.genesis.generators.values.StringGenerator @@ -84,4 +85,27 @@ class RandomMapGeneratorSpec extends Specification { where: result << new RandomMapGenerator(Gen.string(10), Gen.integer, 90..100) } + + def 'close closes sources'() { + given: + Generator keys = Mock() + Generator values = Mock() + def generator = new RandomMapGenerator(keys, values, 10) + when: + generator.close() + then: + 1 * keys.close() + 1 * values.close() + 0 * _ + } + + def 'setting seed returns the same values with 2 generators configured the same'() { + given: + def generatorA = new RandomMapGenerator(Gen.string(10), Gen.integer, 10..20).seed(seed).take(10).realized + def generatorB = new RandomMapGenerator(Gen.string(10), Gen.integer, 10..20).seed(seed).take(10).realized + expect: + generatorA == generatorB + where: + seed = 100L + } } diff --git a/src/test/groovy/spock/genesis/generators/composites/TupleGeneratorSpec.groovy b/src/test/groovy/spock/genesis/generators/composites/TupleGeneratorSpec.groovy index 9dde425..7af5077 100644 --- a/src/test/groovy/spock/genesis/generators/composites/TupleGeneratorSpec.groovy +++ b/src/test/groovy/spock/genesis/generators/composites/TupleGeneratorSpec.groovy @@ -1,5 +1,6 @@ package spock.genesis.generators.composites +import spock.genesis.Gen import spock.lang.Specification import spock.lang.Unroll @@ -18,4 +19,14 @@ class TupleGeneratorSpec extends Specification { [['a', 'b'], [1, 2], [5, 6, 7]] || [['a', 1, 5], ['b', 2, 6]] ['hello!'.toGenerator(), [1, 2, 3, 4, 5]] || [['h', 1], ['e', 2], ['l', 3], ['l', 4], ['o', 5]] } + + def 'setting seed returns the same values with 2 generators configured the same'() { + given: + def generatorA = new TupleGenerator(Gen.string(10), Gen.integer).seed(seed).take(10).realized + def generatorB = new TupleGenerator(Gen.string(10), Gen.integer).seed(seed).take(10).realized + expect: + generatorA == generatorB + where: + seed = 100L + } } diff --git a/src/test/groovy/spock/genesis/generators/test/Pojo.java b/src/test/groovy/spock/genesis/generators/test/Pojo.java index b049dc7..4bc3aed 100644 --- a/src/test/groovy/spock/genesis/generators/test/Pojo.java +++ b/src/test/groovy/spock/genesis/generators/test/Pojo.java @@ -1,5 +1,7 @@ package spock.genesis.generators.test; +import java.util.Objects; + public final class Pojo { private String a; @@ -11,4 +13,17 @@ public String getA() { public void setA(String a) { this.a = a; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Pojo pojo = (Pojo) o; + return Objects.equals(getA(), pojo.getA()); + } + + @Override + public int hashCode() { + return Objects.hash(a); + } } diff --git a/src/test/groovy/spock/genesis/generators/values/ByteArrayGeneratorSpec.groovy b/src/test/groovy/spock/genesis/generators/values/ByteArrayGeneratorSpec.groovy new file mode 100644 index 0000000..3c6a121 --- /dev/null +++ b/src/test/groovy/spock/genesis/generators/values/ByteArrayGeneratorSpec.groovy @@ -0,0 +1,16 @@ +package spock.genesis.generators.values + +import spock.lang.Specification + +class ByteArrayGeneratorSpec extends Specification { + + def 'setting seed produces the same sequences for different generators' () { + given: + def a = new ByteArrayGenerator().seed(seed).take(100).realized + def b = new ByteArrayGenerator().seed(seed).take(100).realized + expect: + a == b + where: + seed << [Long.MIN_VALUE, 100, Long.MAX_VALUE] + } +} diff --git a/src/test/groovy/spock/genesis/generators/values/DateGeneratorSpec.groovy b/src/test/groovy/spock/genesis/generators/values/DateGeneratorSpec.groovy index 162a0e7..e621104 100644 --- a/src/test/groovy/spock/genesis/generators/values/DateGeneratorSpec.groovy +++ b/src/test/groovy/spock/genesis/generators/values/DateGeneratorSpec.groovy @@ -18,4 +18,14 @@ class DateGeneratorSpec extends Specification { low | high new Date() | new Date() + 10 } + + def 'setting seed produces the same sequences for different generators' () { + given: + def a = new DateGenerator().seed(seed).take(100).realized + def b = new DateGenerator().seed(seed).take(100).realized + expect: + a == b + where: + seed << [Long.MIN_VALUE, 100, Long.MAX_VALUE] + } } diff --git a/src/test/groovy/spock/genesis/generators/values/DoubleGeneratorSpec.groovy b/src/test/groovy/spock/genesis/generators/values/DoubleGeneratorSpec.groovy new file mode 100644 index 0000000..8e38b2e --- /dev/null +++ b/src/test/groovy/spock/genesis/generators/values/DoubleGeneratorSpec.groovy @@ -0,0 +1,15 @@ +package spock.genesis.generators.values + +import spock.lang.Specification + +class DoubleGeneratorSpec extends Specification { + def 'setting seed produces the same sequences for different generators' () { + given: + def a = new DoubleGenerator().seed(seed).take(100).realized + def b = new DoubleGenerator().seed(seed).take(100).realized + expect: + a == b + where: + seed << [Long.MIN_VALUE, 100, Long.MAX_VALUE] + } +} diff --git a/src/test/groovy/spock/genesis/generators/values/LongGeneratorSpec.groovy b/src/test/groovy/spock/genesis/generators/values/LongGeneratorSpec.groovy index 7ed11d0..6aac96f 100644 --- a/src/test/groovy/spock/genesis/generators/values/LongGeneratorSpec.groovy +++ b/src/test/groovy/spock/genesis/generators/values/LongGeneratorSpec.groovy @@ -1,6 +1,7 @@ package spock.genesis.generators.values import spock.lang.Specification +import spock.lang.Unroll class LongGeneratorSpec extends Specification { @@ -21,4 +22,33 @@ class LongGeneratorSpec extends Specification { Long.MAX_VALUE - 1 | Long.MAX_VALUE -10 | 10 } + + @Unroll + def 'setting seed produces the same sequences for different generators'() { + given: + def generatorA = new LongGenerator(low, high).seed(1).take(100).realized + def generatorB = new LongGenerator(low, high).seed(1).take(100).realized + expect: + generatorA == generatorB + where: + low | high | iterator + Long.MIN_VALUE | Long.MAX_VALUE | LongGenerator.RandomLongIterator + 0 | Long.MAX_VALUE | LongGenerator.RandomLongIterator + -10 | 10 | LongGenerator.RandomLongIterator + -10 | Long.MAX_VALUE | LongGenerator.RandomLongIterator + } + + def 'chose correct iterator'() { + given: + def generator = new LongGenerator(low, high) + expect: + generator.chooseProvider(low, high).getClass() == iterator + where: + low | high | iterator + Long.MIN_VALUE | Long.MAX_VALUE | LongGenerator.RandomLongIterator + 0 | Long.MAX_VALUE | LongGenerator.ShiftedLongIterator + -10 | 10 | LongGenerator.ShiftedIntegerIterator + -10 | Long.MAX_VALUE | LongGenerator.RandomLongIterator + + } } diff --git a/src/test/groovy/spock/genesis/generators/values/RandomElementGeneratorSpec.groovy b/src/test/groovy/spock/genesis/generators/values/RandomElementGeneratorSpec.groovy new file mode 100644 index 0000000..4082636 --- /dev/null +++ b/src/test/groovy/spock/genesis/generators/values/RandomElementGeneratorSpec.groovy @@ -0,0 +1,17 @@ +package spock.genesis.generators.values + +import spock.lang.Specification + + +class RandomElementGeneratorSpec extends Specification { + def'setting seed produces the same sequences for different generators' () { + given: + def elements = ['a', 'b', 'c', 'd'] + def a = new RandomElementGenerator(elements).seed(seed).take(100).realized + def b = new RandomElementGenerator(elements).seed(seed).take(100).realized + expect: + a == b + where: + seed << [Long.MIN_VALUE, 100, Long.MAX_VALUE] + } +} diff --git a/src/test/groovy/spock/genesis/generators/values/StringGeneratorSpec.groovy b/src/test/groovy/spock/genesis/generators/values/StringGeneratorSpec.groovy index bea17c0..ac3f67b 100644 --- a/src/test/groovy/spock/genesis/generators/values/StringGeneratorSpec.groovy +++ b/src/test/groovy/spock/genesis/generators/values/StringGeneratorSpec.groovy @@ -59,4 +59,24 @@ class StringGeneratorSpec extends Specification { /[A-Z][a-z]+( [A-Z][a-z]+)?/ ] } + + def 'setting seed produces the same sequences for different generators' () { + given: + def a = new StringGenerator().seed(seed).take(100).realized + def b = new StringGenerator().seed(seed).take(100).realized + expect: + a == b + where: + seed << [Long.MIN_VALUE, 100, Long.MAX_VALUE] + } + + def 'setting seed produces the same sequences for different generators using generex' () { + given: + def a = new StringGenerator(~/\d{3}-\d{3}-\d{4}\s(x|(ext))\d{3,5}/).seed(seed).take(100).realized + def b = new StringGenerator(~/\d{3}-\d{3}-\d{4}\s(x|(ext))\d{3,5}/).seed(seed).take(100).realized + expect: + a == b + where: + seed << [Long.MIN_VALUE, 100, Long.MAX_VALUE] + } } diff --git a/src/test/groovy/spock/genesis/generators/values/WholeNumberGeneratorSpec.groovy b/src/test/groovy/spock/genesis/generators/values/WholeNumberGeneratorSpec.groovy index 4f45435..b0af3d2 100644 --- a/src/test/groovy/spock/genesis/generators/values/WholeNumberGeneratorSpec.groovy +++ b/src/test/groovy/spock/genesis/generators/values/WholeNumberGeneratorSpec.groovy @@ -36,7 +36,7 @@ class WholeNumberGeneratorSpec extends Specification { } @Unroll - def 'arguments must be possitive and the correct order'() { + def 'arguments must be positive and the correct order'() { when: new WholeNumberGenerator(*args) then: diff --git a/src/test/groovy/spock/genesis/generators/values/WholeNumberGeneratorTest.groovy b/src/test/groovy/spock/genesis/generators/values/WholeNumberGeneratorTest.groovy new file mode 100644 index 0000000..292b3e4 --- /dev/null +++ b/src/test/groovy/spock/genesis/generators/values/WholeNumberGeneratorTest.groovy @@ -0,0 +1,15 @@ +package spock.genesis.generators.values + +import spock.lang.Specification + +class WholeNumberGeneratorTest extends Specification { + def 'setting seed produces the same sequences for different generators' () { + given: + def a = new WholeNumberGenerator().seed(seed).take(100).realized + def b = new WholeNumberGenerator().seed(seed).take(100).realized + expect: + a == b + where: + seed << [Long.MIN_VALUE, 100, Long.MAX_VALUE] + } +}