PHP code example of rasuvaeff / property-testing-core

1. Go to this page and download the library: Download rasuvaeff/property-testing-core library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

rasuvaeff / property-testing-core example snippets


use Rasuvaeff\PropertyTesting\Gen;
use Rasuvaeff\PropertyTesting\Runner\CallableTrialExecutor;
use Rasuvaeff\PropertyTesting\Runner\Falsified;
use Rasuvaeff\PropertyTesting\Runner\PropertyConfig;
use Rasuvaeff\PropertyTesting\Runner\PropertyDefinition;
use Rasuvaeff\PropertyTesting\Runner\PropertyRunner;

$definition = new PropertyDefinition(
    id: 'demo::everyIntStaysBelowHundred',
    name: 'everyIntStaysBelowHundred',
    generators: ['value' => Gen::intBetween(0, 10_000)],
    parameterNames: ['value'],
    config: new PropertyConfig(runs: 200, seed: 42),
);

$result = (new PropertyRunner())->run($definition, new CallableTrialExecutor(
    static function (int $value): void {
        if ($value >= 100) {
            throw new RuntimeException(sprintf('%d is not below 100', $value));
        }
    },
));

if ($result instanceof Falsified) {
    $example = $result->counterExample();
    // $example->seed, $example->originalArguments, $example->shrunkArguments, ...
    fwrite(STDERR, $result->failure()->getMessage());
}

use Rasuvaeff\PropertyTesting\Arbitrary\IntArbitrary;
use Rasuvaeff\PropertyTesting\Generate;

public function delayStaysWithinCap(
    #[Generate(new IntArbitrary(0, 10_000))]
    int $base,
    #[Generate([Generators::class, 'email'])]
    string $to,
): void {}

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

Gen::flatMap(
    Gen::nonEmptyArrayOf(Gen::int()),
    static fn(array $items): ArbitraryInterface => Gen::tuple(
        Gen::constant($items),
        Gen::intBetween(0, count($items) - 1), // always a valid index
    ),
);

$interval = Gen::composite(static fn (Draw $d): Interval => new Interval(
    $min = $d->draw(Gen::datetime()),
    $d->draw(Gen::datetime(min: $min)),   // sees the prior draw
));

static function (int $attempt, \Random\Randomizer $randomizer): void {
    $delay = (new JitteredBackoff($randomizer))->delayMs($attempt);

    Assert::true($delay <= 60_000);
}

static function (int $a, int $b, int $c): void {
    Target::maximize('sum', $a + $b + $c);

    Assert::true($a + $b + $c <= 2_900);   // 0.17% of the space
}

new PropertyConfig(derandomize: true);   // the same id always selects the same inputs

$counterExample->path;                    // 'value:2/value:2/value:4/value:4'

new PropertyConfig(seed: 1, path: 'value:2/value:2/value:4/value:4');

new PropertyConfig(shrink: ShrinkMode::Off);   // report the counterexample as generated
new PropertyConfig(shrinkBudgetMs: 500);       // descend for at most 500 ms, keep the best so far

new PropertyConfig(phases: [Phase::Examples, Phase::Corpus]);  // fast pull-request gate
new PropertyConfig();                                          // every phase (the default)

$corpus = new RedisCorpus(new PhpRedisCorpusClient($redis));

$definition = new PropertyDefinition(
    id: 'demo::stackBehavesLikeItsModel',
    name: 'stackBehavesLikeItsModel',
    generators: ['sequence' => Gen::commands([], [
        Gen::map(Gen::intBetween(0, 99), static fn(int $v): Command => new Push($v)),
        Gen::constant(new Pop()),
    ])],
    parameterNames: ['sequence'],
    config: new PropertyConfig(runs: 200),
);

$result = (new PropertyRunner())->run($definition, new CallableTrialExecutor(
    static function (CommandSequence $sequence): void {
        StateMachine::check($sequence, static fn(): Stack => new Stack());
    },
));

final class QueueMachine
{
    private array $model = [];

    public function __construct(private readonly Queue $sut) {}

    #[Rule]
    public function enqueue(int $value): void
    {
        $this->sut->push($value);
        $this->model[] = $value;
    }

    #[Rule]
    #[Precondition('notEmpty')]
    public function dequeue(): void
    {
        Assert::same($this->sut->pop(), array_shift($this->model));
    }

    public function notEmpty(): bool { return $this->model !== []; }

    #[Invariant]
    public function sizeMatches(): void
    {
        Assert::same($this->sut->size(), count($this->model));
    }
}

// generators: ['sequence' => Gen::rules(QueueMachine::class, maxLength: 50)]
static function (RuleSequence $sequence): void {
    $sequence->run(static fn (): QueueMachine => new QueueMachine(new Queue()));
}
text
PHP 8.3   Suite::{closure}
PHP 8.4+  Suite::{closure:/app/tests/StackTest.php:19}