Skip to content

CommandSequenceArbitrary ​

Rasuvaeff\PropertyTesting\Arbitrary\CommandSequenceArbitrary

Class — Package: property-testing-core — Source — Version: v1.0.0-1-g88fdee2

Implements: Swarmable, ArbitraryInterface

Generates valid Command sequences for stateful / model-based testing and shrinks them by dropping and simplifying steps.

Generation is model-aware: at each step a command generator is drawn at random, and the produced command is appended only if its StateMachine\Command::preCondition() holds in the running model, which is then advanced via StateMachine\Command::nextState(). The sequence is therefore valid by construction; if no applicable command is found within a bounded number of attempts the sequence stops early.

Shrinking removes whole blocks of commands (most aggressive first, down to a single command so a failing step in the middle can be isolated) and then simplifies individual commands through their own shrink trees. Dropped or simplified sequences are not re-validated here — StateMachine\StateMachine::check() skips any command whose precondition a change invalidated, keeping every candidate sound.

Constructor ​

php
__construct(
    mixed $initialModel,
    array<array-key,\ArbitraryInterface> $commandGenerators,
    int $minLength = 0,
    int $maxLength = 100,
)
ParameterTypeDefaultDescription
$initialModelmixedrequired
$commandGeneratorsarray<array-key,\ArbitraryInterface>requiredEach must produce a StateMachine\Command.
$minLengthint0
$maxLengthint100

Methods ​

generate() ​

php
generate(Random $random): Shrinkable

Produce one random value from this arbitrary's space, together with its shrink tree. Candidates must be ordered most aggressive first (typically toward a zero/empty/identity element) and every branch of the tree must be finite, so shrinking terminates.

Documentation inherited from ArbitraryInterface.

variantCount() ​

php
variantCount(): int

How many variants this generator chooses among. Must be positive: a choice generator with nothing to choose from is not a choice, and Arbitrary\SwarmArbitrary rejects a source that reports otherwise rather than drawing from an empty alphabet. Deliberately typed int and not int<1, max> — the bound is a promise implementations make, and a swarm still checks it at runtime because it cannot analyse the implementations it will be handed.

Documentation inherited from Swarmable.

withVariants() ​

php
withVariants(list<int> $indices): self

The restricted copy keeps the initial model and both length bounds — a swarm narrows the command alphabet and nothing else. That is also where its sharpest edge is: with a $minLength above zero, a subset from which no applicable command reaches that length throws GenerationExhaustedException exactly as the unrestricted generator does when the model starves it. That is the contract, not an accident — a sequence shorter than its minimum has never been a valid result here, and silently returning one would be the worse answer.

  • $indices — Variant positions to keep, each in [0, variantCount() - 1].

Throws:

  • InvalidArgumentException — When an index falls outside the command generators.