Skip to content

SwarmArbitrary ​

Rasuvaeff\PropertyTesting\Arbitrary\SwarmArbitrary

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

Implements: ArbitraryInterface

Type parameters:

  • TValue of mixed = mixed

Swarm testing over a choice generator: every generated case may only use some of the variants, drawn afresh and never empty.

Drawing uniformly from the whole alphabet, every case looks like every other one — a long run of oneOf('push', 'pop', 'flush') almost always contains all three. The bugs that need an operation to be absent ("the bag breaks when no flush ever arrives") are then astronomically rare, because avoiding one variant for a hundred draws is a coin flipped a hundred times. Restricting the alphabet per case makes those runs ordinary instead. This is Groce et al., Swarm Testing (ISSTA 2012), and it costs one extra draw per case.

php
Gen::swarm(Gen::oneOf('push', 'pop', 'flush'));   // one case sees, say, only 'pop' and 'flush'
Gen::swarm(Gen::commands($model, $commands));   // one sequence uses a subset of the commands

Shrinking stays inside the subset the case was generated from: the tree returned here is the restricted generator's own, so a counterexample found without flush cannot shrink to one containing it — which is what makes the finding reproducible at all. The alphabet widens again on the next case, not during a descent.

Two consequences worth knowing before reaching for it:

  • the subset is drawn once per generated value, so it covers exactly the scope of the generator it wraps. swarm(commands(...)) restricts a whole sequence, which is the useful one; arrayOf(swarm(oneOf(...))) redraws per element, which is not swarm testing but noise. Wrap the generator whose scope you mean;
  • the counterexample reports the value, not the subset it came from. Seed replay reproduces both; a counterexample read on its own does not say which variants were available. Deliberate — the report describes the input, and the subset is a property of how it was drawn.

Constructor ​

php
__construct(
    \ArbitraryInterface<\Arbitrary\TValue> $source,
)
ParameterTypeDefaultDescription
$source\ArbitraryInterface<\Arbitrary\TValue>requiredA choice generator — Gen::oneOf(), Gen::elements(), Gen::frequency(), Gen::commands(), or any Swarmable of your own.

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.

  • $random — The run's source of randomness — one draw for the subset, then the restricted generator's own draws.