diff --git a/CHANGELOG.md b/CHANGELOG.md index 99d51fd9..a1a9e204 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased] +### Added + +- `Innmind\BlackBox\Runner\Assert::debug()` + ### Changed - Requires PHP `8.4` diff --git a/proofs/application.php b/proofs/application.php index 88575f2d..151397e8 100644 --- a/proofs/application.php +++ b/proofs/application.php @@ -524,4 +524,70 @@ static function($assert) { }, ) ->tag(Tag::ci, Tag::local); + + yield $prove + ->test( + 'Debug variables are resetted between proofs', + static function($assert) { + $io = Collect::new(); + + $result = Application::new([]) + ->displayOutputVia($io) + ->displayErrorVia($io) + ->usePrinter(Standard::withoutColors()) + ->tryToProve(static function($prove) { + yield $prove->test( + 'example', + static fn($assert) => $assert + ->debug('foo', true) + ->true(false), + ); + + yield $prove->test( + 'example', + static fn($assert) => $assert + ->debug('foo', false) + ->true(false), + ); + }); + + $assert->false($result->successful()); + $assert + ->string($io->toString()) + ->contains('$foo = true') + ->contains('$foo = false'); + }, + ) + ->tag(Tag::ci, Tag::local); + + yield $prove + ->test( + 'Debug variables are resetted when shrinking', + static function($assert) { + $io = Collect::new(); + + $result = Application::new([]) + ->displayOutputVia($io) + ->displayErrorVia($io) + ->usePrinter(Standard::withoutColors()) + ->tryToProve(static function($prove) { + yield $prove + ->proof('example') + ->given(Set::integers()->between(0, 100)) + ->test( + static fn($assert, $i) => $assert + ->debug('i'.$i, $i) + ->true(false), + ); + }); + + $assert->false($result->successful()); + $assert + ->string($io->toString()) + ->contains('$i0 = 0') + ->not() + ->contains('$i1 = 1'); + }, + ) + ->tag(Tag::ci, Tag::local); }; diff --git a/proofs/runner/assert.php b/proofs/runner/assert.php index b6b30ca0..812e793e 100644 --- a/proofs/runner/assert.php +++ b/proofs/runner/assert.php @@ -5,6 +5,7 @@ use Innmind\BlackBox\{ Runner\Assert, Runner\Assert\Failure, + Runner\Assert\Debug, Runner\Stats, Set, Tag, @@ -15,7 +16,10 @@ ->proof('Assert->fail()') ->given(Set::strings()) ->test(static function($assert, $message) { - $sut = Assert::of($stats = Stats::new()); + $sut = Assert::of( + $stats = Stats::new(), + Debug::new(), + ); try { $sut->fail($message); @@ -38,7 +42,10 @@ ->proof('Assert->that()') ->given(Set::strings()) ->test(static function($assert, $message) { - $sut = Assert::of($stats = Stats::new()); + $sut = Assert::of( + $stats = Stats::new(), + Debug::new(), + ); try { $sut->that(static fn() => true); @@ -68,7 +75,10 @@ Set::strings(), ) ->test(static function($assert, $kind, $message) { - $sut = Assert::of($stats = Stats::new()); + $sut = Assert::of( + $stats = Stats::new(), + Debug::new(), + ); $sut->throws( static fn() => throw new $kind($message), @@ -96,7 +106,10 @@ Set::strings(), ) ->test(static function($assert, $kind, $message) { - $sut = Assert::of($stats = Stats::new()); + $sut = Assert::of( + $stats = Stats::new(), + Debug::new(), + ); $sut->not()->throws( static fn() => null, @@ -126,7 +139,10 @@ ) ->exclude(static fn($values, $count) => \count($values) === $count) ->test(static function($assert, $values, $count, $message) { - $sut = Assert::of($stats = Stats::new()); + $sut = Assert::of( + $stats = Stats::new(), + Debug::new(), + ); $sut->count(\count($values), $values); $sut->count(\count($values), new ArrayObject($values)); @@ -159,7 +175,10 @@ ) ->exclude(static fn($values, $count) => \count($values) === $count) ->test(static function($assert, $values, $count, $message) { - $sut = Assert::of($stats = Stats::new()); + $sut = Assert::of( + $stats = Stats::new(), + Debug::new(), + ); $sut->not()->count($count, $values); $sut->not()->count($count, new ArrayObject($values)); @@ -190,7 +209,10 @@ Set::strings(), ) ->test(static function($assert, $value, $message) { - $sut = Assert::of($stats = Stats::new()); + $sut = Assert::of( + $stats = Stats::new(), + Debug::new(), + ); $sut->true(true); @@ -220,7 +242,10 @@ Set::strings(), ) ->test(static function($assert, $value, $message) { - $sut = Assert::of($stats = Stats::new()); + $sut = Assert::of( + $stats = Stats::new(), + Debug::new(), + ); $sut->not()->true($value); @@ -250,7 +275,10 @@ Set::strings(), ) ->test(static function($assert, $value, $message) { - $sut = Assert::of($stats = Stats::new()); + $sut = Assert::of( + $stats = Stats::new(), + Debug::new(), + ); $sut->false(false); @@ -280,7 +308,10 @@ Set::strings(), ) ->test(static function($assert, $value, $message) { - $sut = Assert::of($stats = Stats::new()); + $sut = Assert::of( + $stats = Stats::new(), + Debug::new(), + ); $sut->not()->false($value); @@ -310,7 +341,10 @@ Set::strings(), ) ->test(static function($assert, $value, $message) { - $sut = Assert::of($stats = Stats::new()); + $sut = Assert::of( + $stats = Stats::new(), + Debug::new(), + ); $sut->bool(true); $sut->bool(false); @@ -342,7 +376,10 @@ Set::strings(), ) ->test(static function($assert, $bool, $value, $message) { - $sut = Assert::of($stats = Stats::new()); + $sut = Assert::of( + $stats = Stats::new(), + Debug::new(), + ); $sut->not()->bool($value); @@ -372,7 +409,10 @@ Set::strings(), ) ->test(static function($assert, $value, $message) { - $sut = Assert::of($stats = Stats::new()); + $sut = Assert::of( + $stats = Stats::new(), + Debug::new(), + ); $sut->null(null); @@ -402,7 +442,10 @@ Set::strings(), ) ->test(static function($assert, $value, $message) { - $sut = Assert::of($stats = Stats::new()); + $sut = Assert::of( + $stats = Stats::new(), + Debug::new(), + ); $sut->not()->null($value); @@ -432,7 +475,10 @@ Set::strings(), ) ->test(static function($assert, $value, $message) { - $sut = Assert::of($stats = Stats::new()); + $sut = Assert::of( + $stats = Stats::new(), + Debug::new(), + ); $sut->resource(\tmpfile()); @@ -464,7 +510,10 @@ ) ->filter(static fn($a, $b) => $a !== $b) ->test(static function($assert, $a, $b, $message) { - $sut = Assert::of($stats = Stats::new()); + $sut = Assert::of( + $stats = Stats::new(), + Debug::new(), + ); $sut->expected($a)->same($a); @@ -496,7 +545,10 @@ ) ->filter(static fn($a, $b) => $a !== $b) ->test(static function($assert, $a, $b, $message) { - $sut = Assert::of($stats = Stats::new()); + $sut = Assert::of( + $stats = Stats::new(), + Debug::new(), + ); $sut->expected($a)->not()->same($b); @@ -523,7 +575,10 @@ ->proof('Assert->expected()->equals()') ->given(Set::strings()) ->test(static function($assert, $message) { - $sut = Assert::of($stats = Stats::new()); + $sut = Assert::of( + $stats = Stats::new(), + Debug::new(), + ); $sut->expected(42)->equals('42'); @@ -550,7 +605,10 @@ ->proof('Assert->expected()->not()->equals()') ->given(Set::strings()) ->test(static function($assert, $message) { - $sut = Assert::of($stats = Stats::new()); + $sut = Assert::of( + $stats = Stats::new(), + Debug::new(), + ); $sut->expected(42)->not()->equals(41); @@ -583,7 +641,10 @@ ) ->filter(static fn($prefix, $value, $suffix) => !\in_array($value, $prefix, true) && !\in_array($value, $suffix, true)) ->test(static function($assert, $prefix, $value, $suffix, $message) { - $sut = Assert::of($stats = Stats::new()); + $sut = Assert::of( + $stats = Stats::new(), + Debug::new(), + ); $sut->expected($value)->in([...$prefix, $value, ...$suffix]); @@ -616,7 +677,10 @@ ) ->filter(static fn($prefix, $value, $suffix) => !\in_array($value, $prefix, true) && !\in_array($value, $suffix, true)) ->test(static function($assert, $prefix, $value, $suffix, $message) { - $sut = Assert::of($stats = Stats::new()); + $sut = Assert::of( + $stats = Stats::new(), + Debug::new(), + ); $sut->expected($value)->not()->in([...$prefix, ...$suffix]); @@ -647,7 +711,10 @@ ) ->filter(static fn($value) => !\is_object($value)) ->test(static function($assert, $value, $message) { - $sut = Assert::of($stats = Stats::new()); + $sut = Assert::of( + $stats = Stats::new(), + Debug::new(), + ); $sut->object(new class { }); @@ -675,7 +742,10 @@ ->proof('Assert->object()->instance()') ->given(Set::strings()) ->test(static function($assert, $message) { - $sut = Assert::of($stats = Stats::new()); + $sut = Assert::of( + $stats = Stats::new(), + Debug::new(), + ); $sut->object(new stdClass)->instance(stdClass::class); $sut->object(new LogicException)->instance(LogicException::class); @@ -703,7 +773,10 @@ ->proof('Assert->object()->not()->instance()') ->given(Set::strings()) ->test(static function($assert, $message) { - $sut = Assert::of($stats = Stats::new()); + $sut = Assert::of( + $stats = Stats::new(), + Debug::new(), + ); $sut->object(new stdClass)->not()->instance(LogicException::class); @@ -737,7 +810,10 @@ Set::strings(), ) ->test(static function($assert, $value, $number, $message) { - $sut = Assert::of($stats = Stats::new()); + $sut = Assert::of( + $stats = Stats::new(), + Debug::new(), + ); $sut->number($number); @@ -767,7 +843,10 @@ Set::strings(), ) ->test(static function($assert, $int, $message) { - $sut = Assert::of($stats = Stats::new()); + $sut = Assert::of( + $stats = Stats::new(), + Debug::new(), + ); $sut->number($int)->int(); @@ -802,7 +881,10 @@ Set::strings(), ) ->test(static function($assert, $int, $float, $message) { - $sut = Assert::of($stats = Stats::new()); + $sut = Assert::of( + $stats = Stats::new(), + Debug::new(), + ); $sut->number($float)->float(); @@ -833,7 +915,10 @@ Set::strings(), ) ->test(static function($assert, $int, $diff, $message) { - $sut = Assert::of($stats = Stats::new()); + $sut = Assert::of( + $stats = Stats::new(), + Debug::new(), + ); $sut->number($int)->greaterThan($int - $diff); @@ -864,7 +949,10 @@ Set::strings(), ) ->test(static function($assert, $int, $diff, $message) { - $sut = Assert::of($stats = Stats::new()); + $sut = Assert::of( + $stats = Stats::new(), + Debug::new(), + ); $sut->number($int)->greaterThanOrEqual($int - $diff); @@ -895,7 +983,10 @@ Set::strings(), ) ->test(static function($assert, $int, $diff, $message) { - $sut = Assert::of($stats = Stats::new()); + $sut = Assert::of( + $stats = Stats::new(), + Debug::new(), + ); $sut->number($int)->lessThan($int + $diff); @@ -926,7 +1017,10 @@ Set::strings(), ) ->test(static function($assert, $int, $diff, $message) { - $sut = Assert::of($stats = Stats::new()); + $sut = Assert::of( + $stats = Stats::new(), + Debug::new(), + ); $sut->number($int)->lessThanOrEqual($int + $diff); @@ -957,7 +1051,10 @@ Set::strings(), ) ->test(static function($assert, $string, $value, $message) { - $sut = Assert::of($stats = Stats::new()); + $sut = Assert::of( + $stats = Stats::new(), + Debug::new(), + ); $sut->string($string); @@ -987,7 +1084,10 @@ Set::strings(), ) ->test(static function($assert, $string, $message) { - $sut = Assert::of($stats = Stats::new()); + $sut = Assert::of( + $stats = Stats::new(), + Debug::new(), + ); $sut->string('')->empty(); @@ -1017,7 +1117,10 @@ Set::strings(), ) ->test(static function($assert, $string, $message) { - $sut = Assert::of($stats = Stats::new()); + $sut = Assert::of( + $stats = Stats::new(), + Debug::new(), + ); $sut->string($string)->not()->empty(); @@ -1050,7 +1153,10 @@ ) ->filter(static fn($prefix, $string, $suffix) => !\str_contains($prefix, $string) && !\str_contains($suffix, $string)) ->test(static function($assert, $prefix, $string, $suffix, $message) { - $sut = Assert::of($stats = Stats::new()); + $sut = Assert::of( + $stats = Stats::new(), + Debug::new(), + ); $sut->string($prefix.$string.$suffix)->contains($string); @@ -1083,7 +1189,10 @@ ) ->filter(static fn($prefix, $string, $suffix) => !\str_contains($prefix, $string) && !\str_contains($suffix, $string)) ->test(static function($assert, $prefix, $string, $suffix, $message) { - $sut = Assert::of($stats = Stats::new()); + $sut = Assert::of( + $stats = Stats::new(), + Debug::new(), + ); $sut->string($prefix.$suffix)->not()->contains($string); @@ -1110,7 +1219,10 @@ ->proof('Assert->string()->matches()') ->given(Set::strings()) ->test(static function($assert, $message) { - $sut = Assert::of($stats = Stats::new()); + $sut = Assert::of( + $stats = Stats::new(), + Debug::new(), + ); $sut->string('2023-05-24')->matches('~^\d{4}-\d{2}-\d{2}$~'); @@ -1137,7 +1249,10 @@ ->proof('Assert->string()->not()->matches()') ->given(Set::strings()) ->test(static function($assert, $message) { - $sut = Assert::of($stats = Stats::new()); + $sut = Assert::of( + $stats = Stats::new(), + Debug::new(), + ); $sut->string('2023-05-24')->not()->matches('~^\d{2}-\d{2}-\d{2}$~'); @@ -1169,7 +1284,10 @@ ) ->filter(static fn($string, $suffix) => !\str_contains($suffix, $string)) ->test(static function($assert, $string, $suffix, $message) { - $sut = Assert::of($stats = Stats::new()); + $sut = Assert::of( + $stats = Stats::new(), + Debug::new(), + ); $sut->string($string.$suffix)->startsWith($string); @@ -1201,7 +1319,10 @@ ) ->filter(static fn($string, $suffix) => !\str_contains($suffix, $string)) ->test(static function($assert, $string, $suffix, $message) { - $sut = Assert::of($stats = Stats::new()); + $sut = Assert::of( + $stats = Stats::new(), + Debug::new(), + ); $sut->string($suffix)->not()->startsWith($string); @@ -1233,7 +1354,10 @@ ) ->filter(static fn($prefix, $string) => !\str_contains($prefix, $string)) ->test(static function($assert, $prefix, $string, $message) { - $sut = Assert::of($stats = Stats::new()); + $sut = Assert::of( + $stats = Stats::new(), + Debug::new(), + ); $sut->string($prefix.$string)->endsWith($string); @@ -1265,7 +1389,10 @@ ) ->filter(static fn($prefix, $string) => !\str_contains($prefix, $string)) ->test(static function($assert, $prefix, $string, $message) { - $sut = Assert::of($stats = Stats::new()); + $sut = Assert::of( + $stats = Stats::new(), + Debug::new(), + ); $sut->string($prefix)->not()->endsWith($string); @@ -1296,7 +1423,10 @@ Set::strings(), ) ->test(static function($assert, $array, $value, $message) { - $sut = Assert::of($stats = Stats::new()); + $sut = Assert::of( + $stats = Stats::new(), + Debug::new(), + ); $sut->array($array); @@ -1323,7 +1453,10 @@ ->proof('Assert->array()->hasKey') ->given(Set::strings()) ->test(static function($assert, $message) { - $sut = Assert::of($stats = Stats::new()); + $sut = Assert::of( + $stats = Stats::new(), + Debug::new(), + ); $sut->array([42])->hasKey(0); $sut->array(['foo' => 42])->hasKey('foo'); @@ -1351,7 +1484,10 @@ ->proof('Assert->array()->not()->hasKey') ->given(Set::strings()) ->test(static function($assert, $message) { - $sut = Assert::of($stats = Stats::new()); + $sut = Assert::of( + $stats = Stats::new(), + Debug::new(), + ); $sut->array([42])->not()->hasKey(1); $sut->array(['foo' => 42])->not()->hasKey('bar'); @@ -1388,7 +1524,10 @@ !\in_array($expected, $suffix, true), ) ->test(static function($assert, $expected, $prefix, $suffix, $message) { - $sut = Assert::of($stats = Stats::new()); + $sut = Assert::of( + $stats = Stats::new(), + Debug::new(), + ); $array = [...$prefix, ...[$expected], ...$suffix]; @@ -1427,7 +1566,10 @@ !\in_array($expected, $suffix, true), ) ->test(static function($assert, $expected, $prefix, $suffix, $message) { - $sut = Assert::of($stats = Stats::new()); + $sut = Assert::of( + $stats = Stats::new(), + Debug::new(), + ); $array = [...$prefix, ...[$expected], ...$suffix]; @@ -1460,7 +1602,10 @@ Set::strings(), ) ->test(static function($assert, $value, $message) { - $sut = Assert::of($stats = Stats::new()); + $sut = Assert::of( + $stats = Stats::new(), + Debug::new(), + ); $assert->same( $value, @@ -1497,7 +1642,10 @@ Set::strings(), ) ->test(static function($assert, $microseconds, $message) { - $sut = Assert::of($stats = Stats::new()); + $sut = Assert::of( + $stats = Stats::new(), + Debug::new(), + ); $sut ->time(static fn() => \usleep($microseconds)) @@ -1533,7 +1681,10 @@ Set::strings(), ) ->test(static function($assert, $microseconds, $message) { - $sut = Assert::of($stats = Stats::new()); + $sut = Assert::of( + $stats = Stats::new(), + Debug::new(), + ); $sut ->time(static fn() => \usleep($microseconds)) @@ -1569,7 +1720,10 @@ Set::strings(), ) ->test(static function($assert, $microseconds, $message) { - $sut = Assert::of($stats = Stats::new()); + $sut = Assert::of( + $stats = Stats::new(), + Debug::new(), + ); $sut ->time(static fn() => \usleep($microseconds + 1_000)) @@ -1605,7 +1759,10 @@ Set::strings(), ) ->test(static function($assert, $microseconds, $message) { - $sut = Assert::of($stats = Stats::new()); + $sut = Assert::of( + $stats = Stats::new(), + Debug::new(), + ); $sut ->time(static fn() => \usleep($microseconds + 1_000_000)) @@ -1638,7 +1795,10 @@ ->proof('Assert->memory()->inLessThan()->bytes()') ->given(Set::strings()) ->test(static function($assert, $message) { - $sut = Assert::of($stats = Stats::new()); + $sut = Assert::of( + $stats = Stats::new(), + Debug::new(), + ); $sut ->memory(static fn() => null) @@ -1672,7 +1832,10 @@ ->proof('Assert->memory()->inLessThan()->kiloBytes()') ->given(Set::strings()) ->test(static function($assert, $message) { - $sut = Assert::of($stats = Stats::new()); + $sut = Assert::of( + $stats = Stats::new(), + Debug::new(), + ); $sut ->memory(static fn() => null) @@ -1706,7 +1869,10 @@ ->proof('Assert->memory()->inLessThan()->megaBytes()') ->given(Set::strings()) ->test(static function($assert, $message) { - $sut = Assert::of($stats = Stats::new()); + $sut = Assert::of( + $stats = Stats::new(), + Debug::new(), + ); $sut ->memory(static fn() => null) @@ -1740,7 +1906,10 @@ ->proof('Assert->memory()->inMoreThan()->bytes()') ->given(Set::strings()) ->test(static function($assert, $message) { - $sut = Assert::of($stats = Stats::new()); + $sut = Assert::of( + $stats = Stats::new(), + Debug::new(), + ); $sut ->memory(static function() { @@ -1774,7 +1943,10 @@ ->proof('Assert->memory()->inMoreThan()->kiloBytes()') ->given(Set::strings()) ->test(static function($assert, $message) { - $sut = Assert::of($stats = Stats::new()); + $sut = Assert::of( + $stats = Stats::new(), + Debug::new(), + ); $sut ->memory(static function() { @@ -1808,7 +1980,10 @@ ->proof('Assert->memory()->inMoreThan()->megaBytes()') ->given(Set::strings()) ->test(static function($assert, $message) { - $sut = Assert::of($stats = Stats::new()); + $sut = Assert::of( + $stats = Stats::new(), + Debug::new(), + ); $sut ->memory(static function() { diff --git a/proofs/runner/printer.php b/proofs/runner/printer.php index 6c0f4076..210e1ef7 100644 --- a/proofs/runner/printer.php +++ b/proofs/runner/printer.php @@ -12,6 +12,7 @@ Runner\Assert\Failure\Truth, Runner\Assert\Failure\Property, Runner\Assert\Failure\Comparison, + Runner\Assert\Debug, Set, Set\Value, Properties, @@ -288,13 +289,18 @@ static function($assert) { $printer ->proof($io, $io, Name::of($name), []) - ->failed($io, $io, Failure::of( - Assert\Failure::of(Truth::of($truth)), - Value::of(Scenario\Inline::of( - [$val], - static fn($assert, $foo) => null, - )), - )); + ->failed( + $io, + $io, + Failure::of( + Assert\Failure::of(Truth::of($truth)), + Value::of(Scenario\Inline::of( + [$val], + static fn($assert, $foo) => null, + )), + ), + Debug::new(), + ); $written = $io->toString(); @@ -320,13 +326,18 @@ static function($assert) { $printer ->proof($io, $io, Name::of($name), []) - ->failed($io, $io, Failure::of( - Assert\Failure::of(Truth::of($truth)), - Value::of(Scenario\Inline::of( - [$val], - static fn($assert, $foo) => null, - )), - )); + ->failed( + $io, + $io, + Failure::of( + Assert\Failure::of(Truth::of($truth)), + Value::of(Scenario\Inline::of( + [$val], + static fn($assert, $foo) => null, + )), + ), + Debug::new(), + ); $written = $io->toString(); @@ -354,16 +365,21 @@ static function($assert) { $printer ->proof($io, $io, Name::of($name), []) - ->failed($io, $io, Failure::of( - Assert\Failure::of(Property::of( - $property, - $message, - )), - Value::of(Scenario\Inline::of( - [$val], - static fn($assert, $foo) => null, - )), - )); + ->failed( + $io, + $io, + Failure::of( + Assert\Failure::of(Property::of( + $property, + $message, + )), + Value::of(Scenario\Inline::of( + [$val], + static fn($assert, $foo) => null, + )), + ), + Debug::new(), + ); $written = $io->toString(); @@ -392,16 +408,21 @@ static function($assert) { $printer ->proof($io, $io, Name::of($name), []) - ->failed($io, $io, Failure::of( - Assert\Failure::of(Property::of( - $property, - $message, - )), - Value::of(Scenario\Inline::of( - [$val], - static fn($assert, $foo) => null, - )), - )); + ->failed( + $io, + $io, + Failure::of( + Assert\Failure::of(Property::of( + $property, + $message, + )), + Value::of(Scenario\Inline::of( + [$val], + static fn($assert, $foo) => null, + )), + ), + Debug::new(), + ); $written = $io->toString(); @@ -432,17 +453,22 @@ static function($assert) { $printer ->proof($io, $io, Name::of($name), []) - ->failed($io, $io, Failure::of( - Assert\Failure::of(Comparison::of( - $expected, - $actual, - $message, - )), - Value::of(Scenario\Inline::of( - [$val], - static fn($assert, $foo) => null, - )), - )); + ->failed( + $io, + $io, + Failure::of( + Assert\Failure::of(Comparison::of( + $expected, + $actual, + $message, + )), + Value::of(Scenario\Inline::of( + [$val], + static fn($assert, $foo) => null, + )), + ), + Debug::new(), + ); $written = $io->toString(); @@ -474,17 +500,22 @@ static function($assert) { $printer ->proof($io, $io, Name::of($name), []) - ->failed($io, $io, Failure::of( - Assert\Failure::of(Comparison::of( - $expected, - $actual, - $message, - )), - Value::of(Scenario\Inline::of( - [$val], - static fn($assert, $foo) => null, - )), - )); + ->failed( + $io, + $io, + Failure::of( + Assert\Failure::of(Comparison::of( + $expected, + $actual, + $message, + )), + Value::of(Scenario\Inline::of( + [$val], + static fn($assert, $foo) => null, + )), + ), + Debug::new(), + ); $written = $io->toString(); @@ -514,13 +545,18 @@ static function($assert) { $printer ->proof($io, $io, Name::of($name), []) - ->failed($io, $io, Failure::of( - Assert\Failure::of(Truth::of($message)), - Value::of(Scenario\Property::of( - new LowerBoundAtZero, - new Counter, - )), - )); + ->failed( + $io, + $io, + Failure::of( + Assert\Failure::of(Truth::of($message)), + Value::of(Scenario\Property::of( + new LowerBoundAtZero, + new Counter, + )), + ), + Debug::new(), + ); $written = $io->toString(); @@ -547,13 +583,18 @@ static function($assert) { $printer ->proof($io, $io, Name::of($name), []) - ->failed($io, $io, Failure::of( - Assert\Failure::of(Truth::of($message)), - Value::of(Scenario\Properties::of( - Properties::of(new LowerBoundAtZero), - new Counter, - )), - )); + ->failed( + $io, + $io, + Failure::of( + Assert\Failure::of(Truth::of($message)), + Value::of(Scenario\Properties::of( + Properties::of(new LowerBoundAtZero), + new Counter, + )), + ), + Debug::new(), + ); $written = $io->toString(); @@ -611,4 +652,57 @@ static function($assert) { ->endsWith("\n\n::endgroup::\n"); }) ->tag(Tag::ci); + + yield $prove + ->proof('Printer->proof()->failure() prints debug variables') + ->given( + Set::strings(), + Set::strings()->madeOf(Set::strings()->chars()->alphanumerical()), + Set::strings()->madeOf(Set::strings()->chars()->alphanumerical()), + Set::strings()->madeOf(Set::strings()->chars()->alphanumerical()), + Set::strings(), + Set::strings()->atLeast(1), + Set::strings()->madeOf(Set::strings()->chars()->alphanumerical()), + ) + ->test(static function($assert, $name, $expected, $actual, $val, $message, $debugName, $debugVariable) { + $printer = Standard::new()->disableGitHubOutput(); + $io = Collect::new(); + $debug = Debug::new(); + $debug->add($debugName, $debugVariable); + + $printer + ->proof($io, $io, Name::of($name), []) + ->failed( + $io, + $io, + Failure::of( + Assert\Failure::of(Comparison::of( + $expected, + $actual, + $message, + )), + Value::of(Scenario\Inline::of( + [$val], + static fn($assert, $foo) => null, + )), + ), + $debug, + ); + + $written = $io->toString(); + + $assert + ->string($written) + ->contains("F\n\n") + ->contains('$expected = ') + ->contains($expected) + ->contains('$actual = ') + ->contains($actual) + ->contains('$foo = ') + ->contains($val) + ->contains($message) + ->contains($debugName) + ->contains($debugVariable); + }) + ->tag(Tag::ci, Tag::local); }; diff --git a/src/Application.php b/src/Application.php index beb6e770..11d0bef1 100644 --- a/src/Application.php +++ b/src/Application.php @@ -12,7 +12,6 @@ Runner\WithoutShrinking, Result, Stats, - Assert, Filter, CodeCoverage, }; @@ -456,9 +455,8 @@ public function tryToProve(callable $proofs): Result $this->failWhenNoAssertions, ); $stats = Stats::new(); - $assert = Assert::of($stats); - $run($stats, $assert, $this->codeCoverage); + $run($stats, $this->codeCoverage); return Result::of($stats); } diff --git a/src/PHPUnit/ExtractFailure/OfProof.php b/src/PHPUnit/ExtractFailure/OfProof.php index ec0900a4..65290eeb 100644 --- a/src/PHPUnit/ExtractFailure/OfProof.php +++ b/src/PHPUnit/ExtractFailure/OfProof.php @@ -9,6 +9,7 @@ Runner\Proof\Scenario\Failure, Runner\IO, Runner\Assert\Failure\Property, + Runner\Assert\Debug, Set\Value, }; @@ -47,8 +48,12 @@ public function shrunk(IO $output, IO $error): void } #[\Override] - public function failed(IO $output, IO $error, Failure $failure): void - { + public function failed( + IO $output, + IO $error, + Failure $failure, + Debug $debug, + ): void { if (!($failure->assertion()->kind() instanceof Property)) { return; } diff --git a/src/PHPUnit/Proof.php b/src/PHPUnit/Proof.php index f4b6f075..a7841691 100644 --- a/src/PHPUnit/Proof.php +++ b/src/PHPUnit/Proof.php @@ -111,7 +111,10 @@ public function scenarii(int $count): Set if ($return === BlackBox\Proof::class) { // The true Assert instance is injected in Proof\Bridge - $test = new ($this->class)(Assert::of(Stats::new())); + $test = new ($this->class)(Assert::of( + Stats::new(), + Assert\Debug::new(), + )); /** @var BlackBox\Proof */ $proof = $test->{$this->method}(...$this->args); diff --git a/src/Runner/Assert.php b/src/Runner/Assert.php index 06d187b9..84d1229d 100644 --- a/src/Runner/Assert.php +++ b/src/Runner/Assert.php @@ -9,23 +9,36 @@ Failure\Property, Failure\Comparison, Expected, + Debug, }; final class Assert { private Stats $stats; + private Debug $debug; - private function __construct(Stats $stats) + private function __construct(Stats $stats, Debug $debug) { $this->stats = $stats; + $this->debug = $debug; } /** * @internal */ - public static function of(Stats $stats): self + public static function of(Stats $stats, Debug $debug): self { - return new self($stats); + return new self($stats, $debug); + } + + /** + * @param non-empty-string $name + */ + public function debug(string $name, mixed $variable): self + { + $this->debug->add($name, $variable); + + return $this; } /** diff --git a/src/Runner/Assert/Debug.php b/src/Runner/Assert/Debug.php new file mode 100644 index 00000000..7784bfdb --- /dev/null +++ b/src/Runner/Assert/Debug.php @@ -0,0 +1,54 @@ + $data + */ + private function __construct( + private array $data, + ) { + } + + /** + * @internal + */ + public static function new(): self + { + return new self([]); + } + + /** + * @internal + */ + public function reset(): void + { + $this->data = []; + } + + /** + * @internal + * + * @param non-empty-string $name + */ + public function add(string $name, mixed $value): void + { + $this->data[$name] = $value; + } + + public function empty(): bool + { + return \count($this->data) === 0; + } + + /** + * @return array + */ + public function all(): array + { + return $this->data; + } +} diff --git a/src/Runner/Printer/Proof.php b/src/Runner/Printer/Proof.php index 6031716a..f07a72bc 100644 --- a/src/Runner/Printer/Proof.php +++ b/src/Runner/Printer/Proof.php @@ -5,6 +5,7 @@ use Innmind\BlackBox\Runner\{ Proof\Scenario\Failure, + Assert\Debug, IO, }; @@ -13,6 +14,11 @@ interface Proof public function emptySet(IO $output, IO $error): void; public function success(IO $output, IO $error): void; public function shrunk(IO $output, IO $error): void; - public function failed(IO $output, IO $error, Failure $failure): void; + public function failed( + IO $output, + IO $error, + Failure $failure, + Debug $debug, + ): void; public function end(IO $output, IO $error): void; } diff --git a/src/Runner/Printer/Proof/Standard.php b/src/Runner/Printer/Proof/Standard.php index fae0e869..2fe90d9d 100644 --- a/src/Runner/Printer/Proof/Standard.php +++ b/src/Runner/Printer/Proof/Standard.php @@ -8,6 +8,7 @@ Runner\Assert\Failure\Truth, Runner\Assert\Failure\Property, Runner\Assert\Failure\Comparison, + Runner\Assert\Debug, Runner\IO, Runner\Printer\Proof, Runner\Proof\Scenario, @@ -75,12 +76,29 @@ public function shrunk(IO $output, IO $error): void } #[\Override] - public function failed(IO $output, IO $error, Failure $failure): void - { + public function failed( + IO $output, + IO $error, + Failure $failure, + Debug $debug, + ): void { $this->newLine($output); $output("F\n\n"); $this->renderScenario($output, $failure->scenario()->unwrap()); + if (!$debug->empty()) { + $output("\n"); + + /** @var mixed $variable */ + foreach ($debug->all() as $name => $variable) { + $output(\sprintf( + '$%s = %s', + $name, + $this->dump($variable), + )); + } + } + $output("\n"); $this->renderFailure($output, $failure->assertion()->kind()); diff --git a/src/Runner/Runner.php b/src/Runner/Runner.php index 4e4c82c1..7a6ca39b 100644 --- a/src/Runner/Runner.php +++ b/src/Runner/Runner.php @@ -58,7 +58,6 @@ private function __construct( public function __invoke( Stats $stats, - Assert $assert, ?CodeCoverage $codeCoverage, ): void { if ($this->disableMemoryLimit) { @@ -89,6 +88,8 @@ public function __invoke( ->values($this->random); foreach ($scenarii as $scenario) { + $debug = Assert\Debug::new(); + $assert = Assert::of($stats, $debug); $stats->incrementScenarii(); $assertions = $stats->assertions(); @@ -99,6 +100,7 @@ public function __invoke( $this->error, $assert, $scenario, + $debug, ); if ($this->failWhenNoAssertions && $stats->assertions() === $assertions) { @@ -122,6 +124,7 @@ public function __invoke( $this->output, $this->error, $e, + $debug, ); break; diff --git a/src/Runner/Runner/WithShrinking.php b/src/Runner/Runner/WithShrinking.php index d6c49f7c..ddfddaac 100644 --- a/src/Runner/Runner/WithShrinking.php +++ b/src/Runner/Runner/WithShrinking.php @@ -6,6 +6,7 @@ use Innmind\BlackBox\{ Set\Value, Runner\Assert, + Runner\Assert\Debug, Runner\Proof\Scenario, Runner\Printer, Runner\IO, @@ -35,6 +36,7 @@ public function __invoke( IO $error, Assert $assert, Value $scenario, + Debug $debug, ): void { try { $scenario->unwrap()($assert); @@ -47,6 +49,7 @@ public function __invoke( $error, $assert, $scenario, + $debug, ); } } @@ -81,6 +84,7 @@ private function shrink( IO $error, Assert $assert, Value $scenario, + Debug $debug, ): void { $identity = $this->hash($previousFailure); $previousStrategy = $scenario; @@ -95,6 +99,7 @@ private function shrink( try { try { + $debug->reset(); $currentStrategy->unwrap()($assert); } catch (Assert\Failure $e) { if ($this->canShrink($e, $identity)) { @@ -110,6 +115,7 @@ private function shrink( $currentStrategy = $dichotomy->b(); try { + $debug->reset(); $currentStrategy->unwrap()($assert); } catch (Assert\Failure $e) { if ($this->canShrink($e, $identity)) { diff --git a/src/Runner/Runner/WithoutShrinking.php b/src/Runner/Runner/WithoutShrinking.php index b1e4b9b6..ea204d39 100644 --- a/src/Runner/Runner/WithoutShrinking.php +++ b/src/Runner/Runner/WithoutShrinking.php @@ -6,6 +6,7 @@ use Innmind\BlackBox\{ Set\Value, Runner\Assert, + Runner\Assert\Debug, Runner\Proof\Scenario, Runner\Printer, Runner\IO, @@ -27,6 +28,7 @@ public function __invoke( IO $error, Assert $assert, Value $scenario, + Debug $debug, ): void { try { $scenario->unwrap()($assert);