/*
* Licensed to the author 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 net.java.quickcheck.generator;
import static net.java.quickcheck.generator.PrimitiveGenerators.*;
import static net.java.quickcheck.generator.support.ListGenerator.*;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import net.java.quickcheck.ExtendibleGenerator;
import net.java.quickcheck.FrequencyGenerator;
import net.java.quickcheck.Generator;
import net.java.quickcheck.GeneratorException;
import net.java.quickcheck.StatefulGenerator;
import net.java.quickcheck.collection.Pair;
import net.java.quickcheck.collection.Triple;
import net.java.quickcheck.generator.distribution.Distribution;
import net.java.quickcheck.generator.support.ArrayGenerator;
import net.java.quickcheck.generator.support.ByteArrayGenerator;
import net.java.quickcheck.generator.support.DefaultFrequencyGenerator;
import net.java.quickcheck.generator.support.EnsuredValuesGenerator;
import net.java.quickcheck.generator.support.ExcludingGenerator;
import net.java.quickcheck.generator.support.FixedValuesGenerator;
import net.java.quickcheck.generator.support.IntegerArrayGenerator;
import net.java.quickcheck.generator.support.IntegerGenerator;
import net.java.quickcheck.generator.support.IteratorGenerator;
import net.java.quickcheck.generator.support.ListGenerator;
import net.java.quickcheck.generator.support.SetGenerator;
import net.java.quickcheck.generator.support.SortedListGenerator;
import net.java.quickcheck.generator.support.TupleGenerator;
import net.java.quickcheck.generator.support.UniqueValuesGenerator;
import net.java.quickcheck.srcgenerator.Iterables;
import net.java.quickcheck.srcgenerator.Samples;
/**
* {@link CombinedGenerators} can be used to create custom {@link Generator}s.
*/
@Iterables
@Samples
public class CombinedGenerators {
public static final int DEFAULT_COLLECTION_MAX_SIZE = ListGenerator.MAX_SIZE;
/**
* <p>
* Create a frequency generator. The frequency of {@link Generator} usage
* depends on the generator weight.
* </p>
*
* @param generator
* pairs of generators and their weights used to created the
* values
* @param <T>
* type of values generated by the generators.
*/
public static <T> FrequencyGenerator<T> frequency(Generator<T> generator,
int weight) {
return new DefaultFrequencyGenerator<T>(generator, weight);
}
/**
* OneOf is a convenience method for
* {@link CombinedGenerators#frequency(Generator, int)} when all generator
* share the same weight.
*/
public static <T> ExtendibleGenerator<T, T> oneOf(Generator<T> generator) {
return frequency(generator, 1);
}
/**
* Create a generator which will create vectors (here lists) of type T.
*
* @param <T>
* Type of the list values.
* @param size
* Number of element in the vector.
*/
public static <T> Generator<List<T>> vectors(Generator<T> content, int size) {
return new ListGenerator<T>(content, new FixedValuesGenerator<Integer>(size));
}
/**
* Create a generator of pairs of type A for the left value and type B for
* the right value.
*
* @param <A>
* Type of left value.
* @param <B>
* Type of right value.
* @param first
* Generator for left values.
* @param second
* Generator for right values.
*/
public static <A, B> Generator<Pair<A, B>> pairs(Generator<A> first, Generator<B> second) {
final TupleGenerator generator = new TupleGenerator(first, second);
return new Generator<Pair<A, B>>() {
@SuppressWarnings("unchecked")
public Pair<A, B> next() {
Object[] next = generator.next();
return new Pair(next[0], next[1]);
}
};
}
/**
* Create a generator of triples of the types A, B and C for first, second
* and third value.
*
* @param <A>
* Type of first value.
* @param <B>
* Type of second value.
* @param <C>
* Type of third value.
* @param first
* Generator for first values.
* @param second
* Generator for second values.
* @param third
* Generator for third values.
*/
public static <A, B, C> Generator<Triple<A, B, C>> triples(Generator<A> first, Generator<B> second,
Generator<C> third) {
final TupleGenerator generator = new TupleGenerator(first, second, third);
return new Generator<Triple<A, B, C>>() {
@SuppressWarnings("unchecked")
public Triple<A, B, C> next() {
Object[] next = generator.next();
return new Triple<A, B, C>((A) next[0], (B) next[1], (C) next[2]);
}
};
}
/**
* Create a generator as a combination of a null value generator and
* generator of type T.
*
* @param <T>
* Type of the values generated.
*/
public static <T> Generator<T> nullsAnd(Generator<T> generator) {
return nullsAnd(generator, 5);
}
/**
* Create a generator as a combination of a null value generator and
* generator of type T.
*
* @param <T>
* Type of the values generated.
* @param weight
* weight of the provided generator
*/
public static <T> Generator<T> nullsAnd(Generator<T> generator, int weight) {
return new DefaultFrequencyGenerator<T>(PrimitiveGenerators.<T> nulls(), 1).add(generator, weight);
}
/**
* Create a generator of sets with values from the content generator.
*
* @param <T>
* type of set elements generated
* @param content
* generator providing the content of sets generated
*/
public static <T> Generator<Set<T>> sets(Generator<T> content) {
return new SetGenerator<T>(content);
}
/**
* Create a generator of sets with values from the content generator.
*
* @param <T>
* type of set elements generated
* @param content
* generator providing the content of sets generated
* @param size
* size of the sets generated
*/
public static <T> Generator<Set<T>> sets(Generator<T> content,
Generator<Integer> size) {
return new SetGenerator<T>(content, size);
}
/**
* Create a generator of sets with values from the content generator. Length
* is between high and low.
*
* @param <T>
* type of set elements generated
* @param content
* generator providing the content of sets generated
* @param low
* minimal size
* @param high
* max size
*/
public static <T> Generator<Set<T>> sets(Generator<T> content, int low,
int high) {
return new SetGenerator<T>(content, integers(low, high));
}
/**
* Create a generator of sets that are not empty.
*
* @param <T>
* type of set elements generated
* @param content
* generator providing the content of sets generated
*/
public static <T> Generator<Set<T>> nonEmptySets(Generator<T> content) {
return sets(content, 1, SetGenerator.MAX_SIZE);
}
/**
* Create a generator of iterators.
*
* <p>
* Values of the elements will be taken from the content generator.
* </p>
*
* @param <T>
* type of iterator elements generated
* @param content
* generator providing the content of iterators generated
*/
public static <T> Generator<Iterator<T>> iterators(Generator<T> content) {
return new IteratorGenerator<T>(content);
}
/**
* Create a generator of iterators.
*
* <p>
* Values of the elements will be taken from the content generator. The
* generated iterator will have at least one element.
* </p>
*
* @param <T>
* type of iterator elements generated
* @param content
* generator providing the content of iterators generated
*/
public static <T> Generator<Iterator<T>> nonEmptyIterators(
Generator<T> content) {
return new IteratorGenerator<T>(content, 1, IteratorGenerator.MAX_SIZE);
}
/**
* Create a generator of iterators.
*
* <p>
* Values of the elements will be taken from the content generator. The
* length of the iterators will be determined with the size generator.
* </p>
*
* @param <T>
* type of iterator elements generated
* @param content
* generator providing the content of iterators generated
* @param size
* used to determine the number of elements of the iterator
*/
public static <T> Generator<Iterator<T>> iterators(Generator<T> content,
Generator<Integer> size) {
return new IteratorGenerator<T>(content, size);
}
/**
* Create a generator of lists with values from the content generator.
* Length values of lists generated will be created with
* {@link Distribution#UNIFORM}.
*
* @param <T>
* type of list elements generated
* @param content
* generator providing the content of lists generated
*/
public static <T> Generator<List<T>> lists(Generator<T> content) {
return new ListGenerator<T>(content);
}
/**
* Create a generator of non-empty lists with values from the content
* generator. Length values of lists generated will be created with
* {@link Distribution#UNIFORM}.
*
* @param <T>
* type of list elements generated
* @param content
* generator providing the content of lists generated
*/
public static <T> Generator<List<T>> nonEmptyLists(Generator<T> content) {
return lists(content, positiveIntegers(MAX_SIZE));
}
/**
* Create a generator of lists with values from the content generator.
* Length values of lists generated will be created with size generator.
*
* @param <T>
* type of list elements generated
* @param content
* generator providing the content of lists generated
* @param size
* integer used to determine the list size
*/
public static <T> Generator<List<T>> lists(Generator<T> content,
Generator<Integer> size) {
return new ListGenerator<T>(content, size);
}
/**
* Create a generator of lists with values from the content generator.
* Length is between high and low.
*
* @param <T>
* type of list elements generated
* @param content
* generator providing the content of lists generated
* @param low
* minimal size
* @param high
* max size
*/
public static <T> Generator<List<T>> lists(Generator<T> content, int low,
int high) {
return lists(content, new IntegerGenerator(low, high));
}
/**
* Create a generator of lists with values from the content generator.
* Length is at least low.
*
* @param <T>
* type of list elements generated
* @param content
* generator providing the content of lists generated
* @param low
* minimal size
*/
//TODO bug if low is > MAX_SIZE
public static <T> Generator<List<T>> lists(Generator<T> content, int low) {
return lists(content, low, ListGenerator.MAX_SIZE);
}
/**
* Create a generator of sorted lists with values from the content
* generator.
*
* @param <T>
* type of list elements generated
* @param content
* generator providing the content of lists generated
*/
public static <T extends Comparable<T>> Generator<List<T>> sortedLists(
Generator<T> content) {
return new SortedListGenerator<T>(content);
}
/**
* Create a generator of sorted lists with values from the content
* generator. Length is between high and low.
*
* @param <T>
* type of list elements generated
* @param content
* generator providing the content of lists generated
* @param low
* minimal size
* @param high
* max size
*/
public static <T extends Comparable<T>> Generator<List<T>> sortedLists(
Generator<T> content, int low, int high) {
return sortedLists(content, integers(low, high));
}
/**
* Create a generator of sorted lists with values from the content
* generator. Length is between high and low.
*
* @param <T>
* type of list elements generated
* @param content
* generator providing the content of lists generated
* @param size
* integer used to determine the list size
*/
public static <T extends Comparable<T>> Generator<List<T>> sortedLists(
Generator<T> content, Generator<Integer> size) {
return new SortedListGenerator<T>(content, size);
}
/**
* Create a generator of arrays with values from the content generator.
* Length values of array generated will be created with
* {@link Distribution#UNIFORM}.
*
* @param <T>
* type of arrays elements generated
* @param content
* generator providing the content of arrays generated
* @param type
* type of arrays generated
*/
public static <T> Generator<T[]> arrays(Generator<T> content, Class<T> type) {
return new ArrayGenerator<T>(content, type);
}
/**
* Create a generator of arrays that are not empty.
*
* @param <T>
* type of arrays elements generated
* @param content
* generator providing the content of arrays generated
* @param type
* type of arrays generated
*/
public static <T> Generator<T[]> nonEmptyArrays(Generator<T> content,
Class<T> type) {
return arrays(content, positiveIntegers(MAX_SIZE), type);
}
/**
* Create a generator of arrays with values from the content generator.
* Length values of arrays generated will be created with size generator.
*
* @param <T>
* type of arrays elements generated
* @param content
* generator providing the content of arrays generated
* @param size
* integer used to determine the array size
* @param type
* type of arrays generated
*/
public static <T> Generator<T[]> arrays(Generator<T> content,
Generator<Integer> size, Class<T> type) {
return new ArrayGenerator<T>(content, size, type);
}
/**
* Create a generator of byte arrays. The length of arrays generated will be
* determined by the {@link ByteArrayGenerator#MIN_SIZE} and
* {@link ByteArrayGenerator#MAX_SIZE} constants.
*
*/
public static Generator<byte[]> byteArrays() {
return new ByteArrayGenerator();
}
/**
* Create a generator of byte arrays. Length values of arrays generated will
* be created with size generator.
*
* @param size
* integer used to determine the array size
*/
public static Generator<byte[]> byteArrays(Generator<Integer> size) {
return new ByteArrayGenerator(size);
}
/**
* Create a generator of byte arrays. Length values of arrays generated will
* be created with size generator.
*
* @param size
* integer used to determine the array size
* @param content
* generator for the byte array content
*/
public static Generator<byte[]> byteArrays(Generator<Byte> content,
Generator<Integer> size) {
return new ByteArrayGenerator(content, size);
}
/**
* Create a generator of integer arrays.
*
*/
public static Generator<int[]> intArrays() {
return new IntegerArrayGenerator();
}
/**
* Create a generator of integer arrays. Length values of arrays generated
* will be created with size generator.
*
* @param size
* integer used to determine the array size
*/
public static Generator<int[]> intArrays(Generator<Integer> size) {
return new IntegerArrayGenerator(size);
}
/**
* Create a generator of integer arrays. Length values of arrays generated
* will be created with size generator.
*
* @param size
* integer used to determine the array size
* @param content
* generator for the integer array content
*/
public static Generator<int[]> intArrays(Generator<Integer> content,
Generator<Integer> size) {
return new IntegerArrayGenerator(content, size);
}
/**
* Create a deterministic generator which guarantees that all values from
* the ensuredValues collection will be returned if enough calls to
* {@link Generator#next()} are issued (i.e. ensuredValues.size() <= # of
* runs). The order of values is undefined.
*
* @param <T>
* type of values return by the generator
*/
public static <T> StatefulGenerator<T> ensureValues(
Collection<T> ensuredValues) {
return new EnsuredValuesGenerator<T>(ensuredValues);
}
/**
* Create a deterministic generator which guarantees that all values from
* the ensuredValues array will be returned if enough calls to
* {@link Generator#next()} are issued (i.e. ensuredValues.size() <= # of
* runs). The order of values is undefined.
*
* @param <T>
* type of values return by the generator
*/
public static <T> StatefulGenerator<T> ensureValues(T... content) {
return ensureValues(Arrays.asList(content));
}
/**
* <p>
* Create a deterministic generator which guarantees that all values from
* the ensuredValues collection will be returned if enough calls to
* {@link Generator#next()} are issued (i.e. ensuredValues.size() <= # of
* runs). The order of values is undefined.
* </p>
* <p>
* If all values of ensuredValues are generated calls to
* {@link Generator#next()} will return values from the otherValues
* generator.
* </p>
*
* @param <T>
* type of values return by the generator
*/
public static <T> StatefulGenerator<T> ensureValues(
Collection<T> ensuredValues, Generator<T> otherValues) {
return new EnsuredValuesGenerator<T>(ensuredValues, otherValues);
}
/**
* <p>
* Create a generator that ensures unique values.
* </p>
* <p>
* The actual values are created with an arbitrary generator.
* </p>
* <p>
* Note: unique generator depends on valid implementation of equals and
* hashCode method of the content type generated.
* </p>
*
* @param <T>
* type of values return by the generator
* @param generator
* used to create the raw values. This generator can
* create duplicate values
* @param tries
* Number of tries to create a new unique value. After this
* number of tries is exceeded the generation aborts with a
* {@link GeneratorException}.
* @return create generator.
*/
public static <T> StatefulGenerator<T> uniqueValues(Generator<T> generator,
int tries) {
return new UniqueValuesGenerator<T>(generator, tries);
}
/**
* <p>
* Create a generator that ensures unique values
* </p>
* <p>
* The actual values are created with an arbitrary generator.
* </p>
* <p>
* Note: unique generator depends on valid implementation of equals and
* hashCode method of the content type generated.
* </p>
*
* @param <T>
* type of values return by the generator
* @param generator
* used to create the raw values. This generator can
* create duplicate values
* @return create generator.
*/
public static <T> StatefulGenerator<T> uniqueValues(Generator<T> generator) {
return new UniqueValuesGenerator<T>(generator);
}
/**
* Create a generator that omits a given set of values.
*
* @param generator used to create the raw values.
* @param excluded values. These values will not be returned.
*/
public static <T> Generator<T> excludeValues(Generator<T> generator, T... excluded) {
return excludeValues(generator, Arrays.asList(excluded));
}
/**
* Create a generator that omits a given set of values.
*
* @param generator used to create the raw values.
* @param excluded values. These values will not be returned.
*/
public static <T> Generator<T> excludeValues(Generator<T> generator, Collection<T> excluded) {
return new ExcludingGenerator<T>(generator, excluded);
}
}