The following is a reference of all the included generators of RapidCheck. These generators are accessed by factory functions in the rc::gen
namespace. The signatures are not the actual signatures in the source code and should be seen as pseudo C++ for pedagogical purposes. The real signatures are, of course, uglier.
Generates an arbitrary value of type T
. Support for new types can be added by specializing struct rc::Arbitrary<T>
and providing a static method arbitrary()
which returns an appropriate generator. For more information see the documentation on generators. The semantics of the returned generator depends entirely on the implementation of the Arbitrary
specialization.
This generator is also used by RapidCheck whenever it implicitly needs a generator for some type, for example when generating arguments to properties.
// Example:
const auto str_vector = *gen::arbitrary<std::vector<std::string>>();
Constantly generates value
.
// Example:
const auto alwaysLeet = gen::just(1337);
Generates an std::tuple
using the given generators to generate elements.
// Example:
const auto tuple = *gen::tuple(gen::arbitrary<std::string>(),
gen::arbitrary<int>(),
gen::arbitrary<float>());
Similar to tuple
but generates std::pair
instead.
// Example:
const auto pair = *gen::pair(gen::arbitrary<std::string>(),
gen::arbitrary<int>());
Generates a value that satisfies the given predicate. Fails generation if a value that satisfies the predicate cannot be generated after an unspecified number of tries.
// Example:
const auto smallEven = *gen::suchThat(gen::inRange(0, 100), [](int x) {
return (x % 2) == 0;
});
Like suchThat(Gen<T>, Predicate)
but uses gen::arbitrary<T>()
. T
cannot be deduced and must be explicitly specified.
// Example:
const auto even = *gen::suchThat<int>([](int x) {
return (x % 2) == 0;
});
Generates a value using gen
that is not equal to value
.
// Example:
const auto a = *gen::arbitrary<int>();
const auto b = *gen::distinctFrom(gen::inRange(0, 100), a);
Like distinctFrom(Gen<T> gen, T value)
but uses gen::arbitrary<T>()
as the generator.
Generates a value x
using the given generator for x.empty()
is false. Useful with strings, STL containers and other similar types.
// Example:
const auto nonEmptyString = *gen::nonEmpty(gen::string<std::string>());
Same as nonEmpty(Gen<T>)
but uses gen::arbitrary<T>()
.
// Example:
const auto nonEmptyInts = *gen::nonEmpty<std::vector<int>>();
// Example:
const auto str = *gen::string<std::string>();
Returns a generator equivalent to gen
but with its values mapped by mapper
. The value type of the returned generator will be the type returned by mapper
. This is a functor map, in functional terms.
The value is passed as an rvalue to mapper
and can thus be moved from.
// Example:
const auto year = *gen::map(gen::inRange(1900, 2015), [](int y) {
return std::to_string(y);
});
Like map(Gen<T>, Mapper)
but uses gen::arbitrary<T>()
for the input generator. T
cannot be deduced and must be explicitly specified.
// Example:
const auto strNumber = *gen::map<int>([](int x) { return std::to_string(x); });
Monadic bind. Takes a Gen<T>
and a function from a T
to a Gen<U>
and returns a Gen<U>
. This allows you to chain two generators together.
When shrinking, the value generated by the first generator will be shrunk first, then the second.
// Example:
const auto name = *gen::mapcat(gen::arbitrary<bool>(), [](bool isMale) {
return isMale ? gen::element<std::string>("John", "Joe")
: gen::element<std::string>("Jane", "Kate");
});
Flattens a generator of generators of T
into a generator of T
. This is the monadic join operation.
// Example:
std::vector<Gen<int>> gens;
gens.push_back(gen::arbitrary<int>());
gens.push_back(gen::inRange(0, 100));
gens.push_back(gen::element(2, 3, 5, 7));
const auto someNumber = *gen::join(gen::elementOf(gens));
Calls the given callable with values generated by the given generators. Has tuple semantics when shrinking. Can be seen as a more C++ friendly version of applicative functor application.
// Example:
const auto id = *gen::apply([](char c, int x) {
return std::string(1, c) + "-" + std::to_string(x);
}, gen::elementOf(std::string("ABCDEF")), gen::positive<int>());
Returns a generator that casts the generated values to U
using static_cast<U>(...)
.
// Example:
const auto integer = *gen::cast<float>(gen::arbitrary<int>());
Generates text characters. Commonly occurring characters have a higher probability of being generated.
// Example:
const auto c = *gen::character<char>();
Generates strings. Essentially equivalent to gen::container<String>(gen::character<typename String::value_type>())
but a lot faster. If you need to use a custom character generator, use gen::container
.
Generates a value between min
(inclusive) and max
(exclusive). The part of the range that is used grows with size and when size is 0
, only min
is generated. When shrinking, the value will shrink towards min
.
// Example:
const auto age = *gen::inRange<int>(0, 100);
Generates a value that is not equal to 0
.
// Example:
const auto x = *gen::nonZero<int>();
Generates a value which is greater than 0
.
// Example:
const auto x = *gen::positive<int>();
Generates a value which is less than 0
.
// Example:
const auto x = *gen::positive<int>();
Generates a value which is not less than 0
.
// Example:
const auto x = *gen::nonNegative<int>();
Generates an STL container containing elements generated by the given generator(s). For most containers you should only specify one generator but for containers that have both keys and values (i.e. maps), you need to supply two separate generators. The Container
type parameter must be specified explicitly.
// Example:
const auto smallInts = *gen::container<std::vector<int>>(gen::inRange(0, 100));
Like container(Gen<Ts>... gens)
but generates containers of a fixed size count
.
Generates a container of unique T
. The Container
type parameter must be specified explicitly.
// Example:
const auto uniqueInts = *gen::unique<std::vector<int>>(gen::arbitrary<int>());
Like unique(Gen<T> gen)
but generates containers of a fixed size count
.
Generates a container of T
such that for every element e
in the container, f(e)
is unique. The Container
type parameter must be specified explicitly.
// Example:
const auto uniquePeople = *gen::uniqueBy<std::vector<Person>>(
gen::arbitrary<Person>(),
[](const Person &p) {
return std::make_pair(p.firstName, p.lastName);
});
Like uniqueBy(Gen<T> gen, F f)
but generates containers of a fixed size count
.
Randomly generates one of the elements of container
. If container
is empty, generation will fail.
// Example:
std::vector<std::string> names{"John", "Jane", "Bob", "Kate"};
const auto name = *gen::elementOf(names);
Randomly generates on of the given elements.
const auto prime = *gen::element(2, 3, 5, 7, 11, 13);
Takes a sequence of weights paired with elements and generates one of the elements with probabilities according to the weights. For example, if one element has the weight 1
and another one the weight 2
, the second one will be generated twice as often as the first.
// Example:
const auto animal = *gen::weightedElement({
{4, std::string("horse")},
{2, std::string("donkey")},
{1, std::string("zebra")}});
Randomly chooses an element from an initial segment of the given container which is proportional to size. Effectively, elements are interpreted as increasing in size from start to end which reflects both with regards to the size but also when shrinking.
// Example:
const auto digit = *gen::sizedElementOf(std::string("0123456789"));
Like sizedElementOf(Container)
but takes elements directly instead of a container.
// Example:
const auto digit = *gen::sizedElement(
std::string("one"),
std::string("two"),
std::string("three"));
Randomly picks one of the given generators and generates a value using that.
// Example:
const auto name = *gen::oneOf(
gen::element<std::string>("Jane", "Kate", "Ashley"),
gen::element<std::string>("John", "Bob", "Nick"));
Like weightedElement(std::initializer_list<std::pair<std::size_t, T>>)
but specifying generators instead of immediate values.
// Example:
const auto username = *gen::weightedOneOf({
{1, gen::arbitrary<std::string>()},
(4, gen::element<std::string>("foo", "bar", "baz"))});
Like sizedElement(T...)
but specifying generators instead of immediate values.
// Example:
const auto username = *gen::sizedOneOf(
gen::element<std::string>("ant", "cockroach", "fly"),
gen::element<std::string>("cat", "dog", "wolf"),
gen::element<std::string>("elephant", "giraffe", "horse"));
Generates objects of type T
constructed using arguments from the given generators.
// Example:
const auto person = *gen::construct<Person>(
gen::arbitrary<std::string>(), // Name
gen::arbitrary<std::string>(), // Hometown
gen::inRange(0, 100)); // Age
Like construct
but generates std::unique_ptr
s to T
instead.
// Example:
const auto person = *gen::makeUnique<Person>(
gen::arbitrary<std::string>(), // Name
gen::arbitrary<std::string>(), // Hometown
gen::inRange(0, 100)); // Age
Like construct
but generates std::shared_ptr
s to T
instead.
// Example:
const auto person = *gen::makeShared<Person>(
gen::arbitrary<std::string>(), // Name
gen::arbitrary<std::string>(), // Hometown
gen::inRange(0, 100)); // Age
Generates objects of type T
by setting members of the object according to the specified bindings. A binding is created using gen::set(Member member, Gen<T> gen)
. Member
should be a pointer to a member of that object and gen
should be an appropriate generator for the type of the member. The member may be one of:
- A member variable in which case
gen
should be a generator for the type of that variable. - A member function that takes a single argument.
gen
should be a generator for the type of that argument. - A member function that takes multiple arguments.
gen
should be a generator of tuples matching those arguments.
The generator may be omitted in which case gen::arbitrary<T>()
will be used where T
is the appropriate type of the generator.
The initial value is generated by the specified generator after which the bindings are applied.
// Example:
const auto person = *gen::build(gen::construct<Person>(genName()),
gen::set(&Person::age,
gen::inRange(0, 100)),
gen::set(&Person::phoneNumber),
gen::set(&Person::setGender,
gen::element(std::string("Male"),
std::string("Female"))),
gen::set(&Person::setAddress,
gen::tuple(
genCity(),
genStreet(),
genZipCode())));
Like build(Gen<T> gen, Bindings... bindings)
but T
is default constructed. Since no generator is specified, T
cannot be deduced and must be explicitly specified.
Returns a version of the given generator that always uses the specified size.
// Example:
const auto fullRangeInt = *gen::resize(kNominalSize, gen::arbitrary<int>());
Returns a version of the given generator that scales the size by the given factor before passing it to the underlying generator.
// Example:
const auto smallerInt = *gen::scale(0.5, gen::arbitrary<int>());
Creates a generator by taking a callable which gets passed the current size and is expected to return a generator. The type of the returned generator will be the same as the type returned by callable
.
// Example:
const auto sizedInt = *gen::withSize([](int size) {
return gen::inRange(0, size);
});
This allows you to use the same semantics that is used for properties when creating a generator. However, instead of callable
yielding a success or a failure, it should return the generated value.
Inside the specified callable, you can use operator*
of Gen<T>
to pick values. In this way, you can have the values of one generator depend on the other. Just like with properties, if callable
has any arguments, those will be generate with tuple-like semantics using gen::arbitrary<T>()
for the appropriate types.
Note: If there are other combinators you can use instead of gen::exec
, you are encouraged to do so. Because of its implementation, gen::exec
is likely to have both worse compile time performance and runtime performance than any options. In addition, if the picked values do not actually depend on each other, RapidCheck will be unnecessarily restricted in the way that it can shrink them on failure.
// Example:
const auto name = *gen::exec([](const Address &address) {
const auto gender = *gen::element(kMale, kFemale);
const auto name = *genName(gender);
return Person(name, gender, address);
});
Returns a generator which delegates generation to the generator lazily returned by callable
. This is useful when creating generators for recursive data types such as trees. The type of the returned generator is the same as the type of the generator returned by callable
.
// Example:
Gen<LinkedList> genLinkedList() {
// NOTE: gen::lazy is required, otherwise, we'll go into infinite recursion
// that never terminates
return gen::oneOf(gen::just(LinkedList()),
gen::construct<LinkedList>(gen::arbitrary<int>(),
gen::lazy(&genLinkedList)));
}
Generates a Maybe
of the type of the given generator. At small sizes, the frequency of Nothing
is greater than at larger sizes.
// Example:
const auto maybeSmallInt = *gen::maybe(gen::inRange(0, 100));
Returns a generator which generates the same values as gen
but RapidCheck will not try to shrink it when a failing case is found.
// Example:
const auto fixedInt = *gen::noShrink(gen::arbitrary<int>());
Returns a version of the given generator that will try shrinks returned by the given callable after the regular shrinks have been tried. Use this to add further shrinking to an existing generator.
// Examples:
const auto treeNode =
*gen::shrink(gen::arbitrary<TreeNode>(),
[](TreeNode &&node) {
// Shrink by flattening single-child nodes
if (node.children.size() == 1) {
return seq::just(std::move(node.children[0]));
}
return Seq<TreeNode>();
});