All commands that are part of the state testing framework reside under the rc::state
namespace. To use them, you must include the rapidcheck/state.h
header. Type signatures are not to be taken literally.
void check(Model initialState, Sut sut, GenFunc f)
void check(MakeModel makeInitialState, Sut sut, GenFunc f)
Generates a valid command sequence for an initial state and then runs that sequence on sut
. Any assertions triggered when running the command sequence will cause the property to fail. For more information about the generation function parameter, see rc::state::gen::commands
.
There are two overloads, one that takes the initial state as an immediate value and and another that takes a callable that returns the initial state.
This function must be used inside a property, it cannot be used standalone.
Represents an operation in the state testing framework. The Model
type parameter is the type of the model that models Sut
which is the actual System Under Test. These can also be accessed through the Model
and Sut
member type alises.
If your command is not valid for all states, you must implement this method to assert preconditions. Preconditions can be asserted using any of the discarding macros such as RC_PRE
or RC_DISCARD
. If the command is discarded, RapidCheck will simply try to generate a new one. This method is intended to be overriden but has a default implementation that does nothing which is what you want if your command has no preconditions.
While the model state is passed as const
, this doesn't prevent modification of the model if it, for example, is a shared_ptr
or similar. Regardless, modifying the model state in this method leads to undefined behavior.
Applies this command to the given state. The effect of this command on the model should be equivalent to this commands effect on the System Under Test. This method is intended to be overriden but has a default implementation that does nothing, something that can be useful for commands that do not modify state.
Applies this command to the given System Under Test. The state before this command has been applied is also passed in. If you need the post state, you can get this using the nextState
convenience method. This is the method in which to place your assertions (RC_ASSERT
et al.). This method is intended to be overriden but has a default implementation that does nothing.
While the model state is passed as const
, this doesn't prevent modification of the model if it, for example, is a shared_ptr
or similar. Regardless, modifying the model state in this method leads to undefined behavior.
Outputs a string representation of the command to the given output stream. The default implementation outputs the type name (via RTTI) but if your command has any sort of parameters, you will likely want to override this with a custom implementation to include those.
Convenience method that calls apply
on a copy of the given state and returns it. Saves some keystrokes occasionally since you don't have to allocate a model on the stack. Cannot be overridden, override apply
instead.
This method does not work for non-copyable models.
Type alias for a std::vector<std::shared_ptr<const CommandType>>
. Useful since command sequences are generally stored in vectors and individual commands are usually passed by shared_ptr
-to-const.
Applies the given commands in sequence to the given model state.
void runAll(Commands commands, Model state, Sut &sut)
void runAll(Commands commands, MakeModel makeState, Sut &sut)
Runs the given commands in sequence on the given System Under Test assuming it is equivalent to the given model state.
There are two overloads, one that takes the state as an immediate value and and another that takes a callable that returns the state.
bool isValidSequence(Commands commands, Model state)
bool isValidSequence(Commands commands, MakeModel makeState)
Returns true
if the given command sequence is valid for the given model state, otherwise false
.
There are two overloads, one that takes the state as an immediate value and and another that takes a callable that returns the state.
Returns a callable that when called returns a generator that randomly constructs one of the commands in Ts
. If the command has a constructor that matches the (zero or more) arguments given to the callable, that constructor will be used. Otherwise, the command is assumed to have a default constructor. The constructor can make use of the *
-operator just like in a property or in gen::exec
.
A common thing to do is to pass the model state as the constructor argument. Here is an example of a command designed for such use:
struct Take : rc::state::Command<MyModel, MySut> {
std::string item;
explicit Take(const MyModel &s0)
: item(*rc::gen::elementOf(s0.items)) {}
// ...
};
Typical usage of execOneOfWithArgs
is to create the generation function argument for rc::state::gen::commands
or rc::state::check
:
MyModel initialState;
MySut sut;
rc::state::check(initialState,
sut,
rc::state::gen::execOneOfWithArgs<Put, Take, Frobnicate>());
If the model is non-copyable, we can still use this to pass some copyable values of the model state:
MySut sut;
rc::state::check(
[] { return MyNonCopyableModel(); },
sut,
[](const MyNonCopyableModel &state) {
return rc::state::gen::execOneOfWithArgs<Put, Take, Frobnicate>()(
state.status(), state.remaining());
});
With the construction shown above, the commands would take the return types of state.status()
and state.remaining()
as parameters to their constructors.
Some notes:
- In the first example, we also have to assert that
item
exists in the model in ourapply
implementation since a generated command might be used for a different state, in particular during shrinking where the state may change because the commands prior in the sequence may be shrunk or removed. For more about this, see the Stateful testing section. - Discarding macros such as
RC_PRE
andRC_DISCARD
can be used in the constructor of a command to immediately discard the command if it is not valid for the given state.
Note: This function is deprecated, use rc::gen::execOneOfWithArgs
instead.
Returns a generator that randomly constructs one of the commands in Ts
. The constructor can make use of the *
-operator just like in a property or in gen::exec
. If the command has a constructor taking a model state, state
will be passed to it on construction. Otherwise, the command is assumed to have a default constructor.
Gen<Commands<Cmd>> gen::commands(Model initialState, GenFunc f)
Gen<Commands<Cmd>> gen::commands(MakeModel makeInitialState, GenFunc f)
Generates a valid sequence of commands for the given model state.
f
should be a function that takes a Model
as an argument and returns a Gen<std::shared_ptr<const Command<Model, Sut>>>
. This type looks complicated but it is essentially a generator of shared_ptr
s to appropriate commands. The generator does not have to yield only valid commands since RapidCheck
will simply try again if a command is not valid. However, performance will be better if fewer commands have to be discarded, of course. The easiest way to create such a function is to use the gen::execOneOfWithArgs
function.
There are two overloads of this function, one that takes the state as an immediate value and and another that takes a callable that returns the state.
Since the System Under Test is not specified, the type of the generated commands must be explicitly specified. It cannot be deduced.
Returns true
if the given command is valid for the given model state, false
otherwise.