Generators#
Generators are a testlib concept. They are programs that produce a testcase for a problem.
In this section, we'll learn how to write a generator. If you already know how to do so, you can take a look at the Testset section to learn how to use them to produce your testset.
Generator call#
In rbx, generators are programs that produce a testplan from a given list of arguments.
Let's say we have an executable generator.exe
. Calling it should produce a testcase into the stdout.
The program + all the arguments passed to it constitute what we call a generator call.
In rbx, every generator should have a name. This name is used to identify the generator
within a generator call for a better readability. These names are defined in the problem.rbx.yml
.
A valid generator call for the generator above would be generator 123
.
Idempotency#
Generators should be idempotent. This means that two equal generator calls should always produce the same output.
testlib rnd
library is designed to be used in an idempotent way. In fact, the seed number
for the rnd
object's random number generator is a hash of the generator call.
This means that using the rnd
object in a generator as the only source of randomness will
guarantee idempotency.
Introducing randomness
If you need to generate a testcase with the same set of parameters, but with a different seed, simply append a few random characters to the generator call.
They will be ignored by your generator, but will be used to compute the seed for rnd
,
potentially producing a different testcase.
The two generator calls above will produce the same testcase for a generator expecting a single
positional argument. The trailing abc
piece is just used to produce a different seed.
Writing a generator#
You can read more about generators in the testlib documentation. It's very thorough and show a bunch of details about the APIs.
#include "testlib.h"
int main(int argc, char* argv[]) {
registerGen(argc, argv, 1);
int N = opt<int>(1);
int MAX = opt<int>("MAX");
for (int i = 0; i < N; i++) {
if (i) cout << " ";
cout << rnd.next(1, MAX);
}
cout << endl;
}
The generator above produces a testcase with N
integers, each one between 1 and MAX
,
separated by spaces.
testlib provides the opt<...>()
function to parse command line arguments, in two variants:
opt<>(int i)
: Parses a positional argument in the i-th position (1-indexed).opt<>(string name)
: Parses argument with the given name.
In the case above, a valid generator call would be:
To generate 10 random integers ranging from 1 to 1000.
Random numbers can be generated using the rnd
object. The rnd.next()
function can be used to generate a random integer between two values, but there are also other overrides available for it.
Take a look at the testlib documentation for more details, and also at the examples on their GitHub repository.
Info
You can always call your generator manually with:
You can also run solutions interactively against a generator call with:
Read more about rbx irun
in the Running solutions section.
Jngen, the jack of all trades#
rbx also has a built-in integration with jngen. This is a test generation library implemented by Ivan Smirnov.
Jngen is a very powerful library that can generate all sorts of random objects: permutations, trees, graphs, strings, and more.
It is a bit less mature and tested than testlib, but it's a great tool to have in your toolbox. Check it at its GitHub repository.
To implement a Jngen-based generator, it suffices to include the jngen.h
header
Under development
This section is under development. If you want to contribute, please send a PR to our repository.