From ffd4e6d577654d828f6d1ad586fc293417bfa634 Mon Sep 17 00:00:00 2001 From: Fabio Ivona Date: Mon, 15 Nov 2021 12:23:53 +0100 Subject: [PATCH 1/9] upgrade to phpstan level 6 --- phpstan.neon | 2 +- src/Datasets.php | 17 +++++++++-------- src/Factories/Annotations/Depends.php | 4 ++++ src/Factories/Annotations/Groups.php | 4 ++++ src/Factories/TestCaseFactory.php | 2 ++ src/Repositories/TestRepository.php | 2 +- src/Support/Arr.php | 4 ++++ 7 files changed, 25 insertions(+), 10 deletions(-) diff --git a/phpstan.neon b/phpstan.neon index c1a0e56e..4594d0d2 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -4,7 +4,7 @@ includes: - vendor/thecodingmachine/phpstan-strict-rules/phpstan-strict-rules.neon parameters: - level: 5 + level: 6 paths: - src diff --git a/src/Datasets.php b/src/Datasets.php index 429de157..09e0219f 100644 --- a/src/Datasets.php +++ b/src/Datasets.php @@ -9,6 +9,7 @@ use Pest\Exceptions\DatasetAlreadyExist; use Pest\Exceptions\DatasetDoesNotExist; use SebastianBergmann\Exporter\Exporter; use Traversable; +use function sprintf; /** * @internal @@ -25,14 +26,14 @@ final class Datasets /** * Holds the withs. * - * @var array + * @var array|string> */ private static array $withs = []; /** * Sets the given. * - * @param Closure|iterable $data + * @phpstan-param Closure|iterable $data */ public static function set(string $name, Closure|iterable $data): void { @@ -46,7 +47,7 @@ final class Datasets /** * Sets the given. * - * @param Closure|iterable|string $with + * @phpstan-param Closure|iterable|string $with */ public static function with(string $filename, string $description, Closure|iterable|string $with): void { @@ -119,7 +120,7 @@ final class Datasets /** * @param array|string> $datasets * - * @return array + * @return array> */ private static function processDatasets(array $datasets): array { @@ -159,9 +160,9 @@ final class Datasets } /** - * @param array $combinations + * @param array> $combinations * - * @return array + * @return array> */ private static function getDataSetsCombinations(array $combinations): array { @@ -187,9 +188,9 @@ final class Datasets $exporter = new Exporter(); if (is_int($key)) { - return \sprintf('(%s)', $exporter->shortenedRecursiveExport($data)); + return sprintf('(%s)', $exporter->shortenedRecursiveExport($data)); } - return \sprintf('data set "%s"', $key); + return sprintf('data set "%s"', $key); } } diff --git a/src/Factories/Annotations/Depends.php b/src/Factories/Annotations/Depends.php index 15b29359..66c4838c 100644 --- a/src/Factories/Annotations/Depends.php +++ b/src/Factories/Annotations/Depends.php @@ -14,6 +14,10 @@ final class Depends { /** * Adds annotations regarding the "depends" feature. + * + * @param array $annotations + * + * @return array */ public function add(TestCaseMethodFactory $method, array $annotations): array { diff --git a/src/Factories/Annotations/Groups.php b/src/Factories/Annotations/Groups.php index 96752d6e..ab7749b7 100644 --- a/src/Factories/Annotations/Groups.php +++ b/src/Factories/Annotations/Groups.php @@ -13,6 +13,10 @@ final class Groups { /** * Adds annotations regarding the "groups" feature. + * + * @param array $annotations + * + * @return array */ public function add(TestCaseMethodFactory $method, array $annotations): array { diff --git a/src/Factories/TestCaseFactory.php b/src/Factories/TestCaseFactory.php index d21b5513..edb37fd3 100644 --- a/src/Factories/TestCaseFactory.php +++ b/src/Factories/TestCaseFactory.php @@ -98,6 +98,8 @@ final class TestCaseFactory /** * Creates a Test Case class using a runtime evaluate. + * + * @param array $methods */ public function evaluate(string $filename, array $methods): string { diff --git a/src/Repositories/TestRepository.php b/src/Repositories/TestRepository.php index b8e2b53e..3a65c529 100644 --- a/src/Repositories/TestRepository.php +++ b/src/Repositories/TestRepository.php @@ -80,7 +80,7 @@ final class TestRepository } } - public function get($filename): TestCaseFactory + public function get(string $filename): TestCaseFactory { return $this->testCases[$filename]; } diff --git a/src/Support/Arr.php b/src/Support/Arr.php index 3fbe0e61..531e0d19 100644 --- a/src/Support/Arr.php +++ b/src/Support/Arr.php @@ -11,6 +11,8 @@ final class Arr { /** * Checks if the given array has the given key. + * + * @param array $array */ public static function has(array $array, string|int $key): bool { @@ -33,6 +35,8 @@ final class Arr /** * Gets the given key value. + * + * @param array $array */ public static function get(array $array, string|int $key, mixed $default = null): mixed { From f2a9b73b83c100bf312bb2328bdf29ef8c57b114 Mon Sep 17 00:00:00 2001 From: Fabio Ivona Date: Mon, 15 Nov 2021 20:54:47 +0100 Subject: [PATCH 2/9] trying to disable phpstan parallel processing --- phpstan.neon | 2 ++ 1 file changed, 2 insertions(+) diff --git a/phpstan.neon b/phpstan.neon index 4594d0d2..eda92dbf 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -7,6 +7,8 @@ parameters: level: 6 paths: - src + parallel: + maximumNumberOfProcesses: 1 checkMissingIterableValueType: true checkGenericClassInNonGenericObjectType: false From f3f58c7f52751beb16bc98ffee5dbfe2c19fd80f Mon Sep 17 00:00:00 2001 From: Fabio Ivona Date: Mon, 15 Nov 2021 22:20:00 +0100 Subject: [PATCH 3/9] upgrade to phpstan lvl 7 --- phpstan.neon | 2 +- src/Bootstrappers/BootSubscribers.php | 2 +- src/Datasets.php | 10 +++++----- src/Factories/TestCaseFactory.php | 1 + src/Functions.php | 2 ++ src/Kernel.php | 1 + src/PendingCalls/UsesCall.php | 4 ++-- src/Plugin.php | 2 ++ src/Repositories/TestRepository.php | 2 +- src/Support/Container.php | 5 +++++ src/Support/HigherOrderMessage.php | 2 +- 11 files changed, 22 insertions(+), 11 deletions(-) diff --git a/phpstan.neon b/phpstan.neon index eda92dbf..1b341db4 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -4,7 +4,7 @@ includes: - vendor/thecodingmachine/phpstan-strict-rules/phpstan-strict-rules.neon parameters: - level: 6 + level: 7 paths: - src parallel: diff --git a/src/Bootstrappers/BootSubscribers.php b/src/Bootstrappers/BootSubscribers.php index c23e9bf0..42bdeaba 100644 --- a/src/Bootstrappers/BootSubscribers.php +++ b/src/Bootstrappers/BootSubscribers.php @@ -29,7 +29,7 @@ final class BootSubscribers { foreach (self::$subscribers as $subscriber) { Event\Facade::registerSubscriber( - new $subscriber() + new $subscriber() //@phpstan-ignore-line ); } } diff --git a/src/Datasets.php b/src/Datasets.php index 09e0219f..96aa00dd 100644 --- a/src/Datasets.php +++ b/src/Datasets.php @@ -8,8 +8,8 @@ use Closure; use Pest\Exceptions\DatasetAlreadyExist; use Pest\Exceptions\DatasetDoesNotExist; use SebastianBergmann\Exporter\Exporter; -use Traversable; use function sprintf; +use Traversable; /** * @internal @@ -19,14 +19,14 @@ final class Datasets /** * Holds the datasets. * - * @var array> + * @var array> */ private static array $datasets = []; /** * Holds the withs. * - * @var array|string> + * @var array|string>> */ private static array $withs = []; @@ -47,9 +47,9 @@ final class Datasets /** * Sets the given. * - * @phpstan-param Closure|iterable|string $with + * @phpstan-param array|string> $with */ - public static function with(string $filename, string $description, Closure|iterable|string $with): void + public static function with(string $filename, string $description, array $with): void { self::$withs[$filename . '>>>' . $description] = $with; } diff --git a/src/Factories/TestCaseFactory.php b/src/Factories/TestCaseFactory.php index edb37fd3..5b077d08 100644 --- a/src/Factories/TestCaseFactory.php +++ b/src/Factories/TestCaseFactory.php @@ -148,6 +148,7 @@ final class TestCaseFactory $annotations = ['@test']; foreach (self::$annotations as $annotation) { + //@phpstan-ignore-next-line $annotations = (new $annotation())->add($method, $annotations); } diff --git a/src/Functions.php b/src/Functions.php index 1e306999..ddc6f3af 100644 --- a/src/Functions.php +++ b/src/Functions.php @@ -70,6 +70,8 @@ if (!function_exists('uses')) { /** * The uses function binds the given * arguments to test closures. + * + * @param class-string ...$classAndTraits */ function uses(string ...$classAndTraits): UsesCall { diff --git a/src/Kernel.php b/src/Kernel.php index af2d82e6..67c4dcf9 100644 --- a/src/Kernel.php +++ b/src/Kernel.php @@ -37,6 +37,7 @@ final class Kernel public static function boot(): self { foreach (self::$bootstrappers as $bootstrapper) { + //@phpstan-ignore-next-line (new $bootstrapper())->__invoke(); } diff --git a/src/PendingCalls/UsesCall.php b/src/PendingCalls/UsesCall.php index 6609e8b2..457f8699 100644 --- a/src/PendingCalls/UsesCall.php +++ b/src/PendingCalls/UsesCall.php @@ -36,14 +36,14 @@ final class UsesCall /** * Holds the groups of the uses. * - * @var array + * @var array */ private array $groups = []; /** * Creates a new Pending Call. * - * @param array $classAndTraits + * @param array $classAndTraits */ public function __construct( private string $filename, diff --git a/src/Plugin.php b/src/Plugin.php index 9de1f707..5f676be4 100644 --- a/src/Plugin.php +++ b/src/Plugin.php @@ -18,6 +18,8 @@ final class Plugin /** * Lazy loads an `uses` call on the context of plugins. + * + * @param class-string ...$traits */ public static function uses(string ...$traits): void { diff --git a/src/Repositories/TestRepository.php b/src/Repositories/TestRepository.php index 3a65c529..869d1000 100644 --- a/src/Repositories/TestRepository.php +++ b/src/Repositories/TestRepository.php @@ -23,7 +23,7 @@ final class TestRepository private array $testCases = []; /** - * @var array>> + * @var array, 1: array, 2: array}> */ private array $uses = []; diff --git a/src/Support/Container.php b/src/Support/Container.php index 6390484b..b87fdd65 100644 --- a/src/Support/Container.php +++ b/src/Support/Container.php @@ -35,6 +35,8 @@ final class Container /** * Gets a dependency from the container. * + * @param class-string $id + * * @return object */ public function get(string $id) @@ -60,6 +62,8 @@ final class Container /** * Tries to build the given instance. + * + * @param class-string $id */ private function build(string $id): object { @@ -83,6 +87,7 @@ final class Container } } + //@phpstan-ignore-next-line return $this->get($candidate); }, $constructor->getParameters() diff --git a/src/Support/HigherOrderMessage.php b/src/Support/HigherOrderMessage.php index f756c64d..575eaf98 100644 --- a/src/Support/HigherOrderMessage.php +++ b/src/Support/HigherOrderMessage.php @@ -77,7 +77,7 @@ final class HigherOrderMessage */ public function when(callable $condition): self { - $this->condition = $condition; + $this->condition = Closure::fromCallable($condition); return $this; } From d4a8a3ec3726f25065febdbc6dfb38f87d2efe42 Mon Sep 17 00:00:00 2001 From: Fabio Ivona Date: Thu, 18 Nov 2021 00:12:39 +0100 Subject: [PATCH 4/9] upgrade to phpstan lvl 8 --- phpstan.neon | 2 +- src/Datasets.php | 9 +++++++- src/Factories/TestCaseFactory.php | 12 +++++++++++ src/Factories/TestCaseMethodFactory.php | 2 +- src/Support/ChainableClosure.php | 8 +++---- src/Support/Closure.php | 28 +++++++++++++++++++++++++ 6 files changed, 54 insertions(+), 7 deletions(-) create mode 100644 src/Support/Closure.php diff --git a/phpstan.neon b/phpstan.neon index 1b341db4..89377d38 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -4,7 +4,7 @@ includes: - vendor/thecodingmachine/phpstan-strict-rules/phpstan-strict-rules.neon parameters: - level: 7 + level: 8 paths: - src parallel: diff --git a/src/Datasets.php b/src/Datasets.php index 96aa00dd..c91de5e7 100644 --- a/src/Datasets.php +++ b/src/Datasets.php @@ -7,6 +7,7 @@ namespace Pest; use Closure; use Pest\Exceptions\DatasetAlreadyExist; use Pest\Exceptions\DatasetDoesNotExist; +use Pest\Exceptions\ShouldNotHappen; use SebastianBergmann\Exporter\Exporter; use function sprintf; use Traversable; @@ -61,7 +62,13 @@ final class Datasets { $dataset = self::$withs[$filename . '>>>' . $description]; - return self::resolve($description, $dataset); + $dataset = self::resolve($description, $dataset); + + if ($dataset === null) { + throw ShouldNotHappen::fromMessage('Could not resolve dataset.'); + } + + return $dataset; } /** diff --git a/src/Factories/TestCaseFactory.php b/src/Factories/TestCaseFactory.php index 5b077d08..517a586c 100644 --- a/src/Factories/TestCaseFactory.php +++ b/src/Factories/TestCaseFactory.php @@ -142,6 +142,10 @@ final class TestCaseFactory } $methodsCode = implode('', array_map(static function (TestCaseMethodFactory $method): string { + if ($method->description === null) { + throw ShouldNotHappen::fromMessage('The test description may not be empty.'); + } + $methodName = Str::evaluable($method->description); $datasetsCode = ''; @@ -224,6 +228,10 @@ EOF; } if (!$method->receivesArguments()) { + if ($method->closure === null) { + throw ShouldNotHappen::fromMessage('The test closure may not be empty.'); + } + $arguments = Reflection::getFunctionArguments($method->closure); if (count($arguments) > 0) { @@ -240,6 +248,10 @@ EOF; public function getMethod(string $methodName): TestCaseMethodFactory { foreach ($this->methods as $method) { + if ($method->description === null) { + throw ShouldNotHappen::fromMessage('The test description may not be empty.'); + } + if (Str::evaluable($method->description) === $methodName) { return $method; } diff --git a/src/Factories/TestCaseMethodFactory.php b/src/Factories/TestCaseMethodFactory.php index ffa4cb4b..e2ece273 100644 --- a/src/Factories/TestCaseMethodFactory.php +++ b/src/Factories/TestCaseMethodFactory.php @@ -89,7 +89,7 @@ final class TestCaseMethodFactory $testCase->chains->chain($this); $method->chains->chain($this); - return call_user_func(Closure::bind($closure, $this, $this::class), ...func_get_args()); + return \Pest\Support\Closure::safeBind($closure, $this, $this::class)(...func_get_args()); }; } diff --git a/src/Support/ChainableClosure.php b/src/Support/ChainableClosure.php index 8a136682..b3406d86 100644 --- a/src/Support/ChainableClosure.php +++ b/src/Support/ChainableClosure.php @@ -22,8 +22,8 @@ final class ChainableClosure throw ShouldNotHappen::fromMessage('$this not bound to chainable closure.'); } - call_user_func_array(Closure::bind($closure, $this, $this::class), func_get_args()); - call_user_func_array(Closure::bind($next, $this, $this::class), func_get_args()); + \Pest\Support\Closure::safeBind($closure, $this, $this::class)(...func_get_args()); + \Pest\Support\Closure::safeBind($next, $this, $this::class)(...func_get_args()); }; } @@ -33,8 +33,8 @@ final class ChainableClosure public static function fromStatic(Closure $closure, Closure $next): Closure { return static function () use ($closure, $next): void { - call_user_func_array(Closure::bind($closure, null, self::class), func_get_args()); - call_user_func_array(Closure::bind($next, null, self::class), func_get_args()); + \Pest\Support\Closure::safeBind($closure, null, self::class)(...func_get_args()); + \Pest\Support\Closure::safeBind($next, null, self::class)(...func_get_args()); }; } } diff --git a/src/Support/Closure.php b/src/Support/Closure.php new file mode 100644 index 00000000..ece77d57 --- /dev/null +++ b/src/Support/Closure.php @@ -0,0 +1,28 @@ + Date: Thu, 18 Nov 2021 01:01:56 +0100 Subject: [PATCH 5/9] wip toward lvl9 --- src/Exceptions/ExpectationException.php | 11 +++++++++++ src/Expectation.php | 5 +++++ src/Functions.php | 5 ++++- src/HigherOrderExpectation.php | 5 ++++- src/Plugins/Coverage.php | 5 ++++- src/Support/Container.php | 8 +++++--- src/Support/ExceptionTrace.php | 2 ++ src/Support/HigherOrderCallables.php | 5 ++++- 8 files changed, 39 insertions(+), 7 deletions(-) create mode 100644 src/Exceptions/ExpectationException.php diff --git a/src/Exceptions/ExpectationException.php b/src/Exceptions/ExpectationException.php new file mode 100644 index 00000000..dfe63bb9 --- /dev/null +++ b/src/Exceptions/ExpectationException.php @@ -0,0 +1,11 @@ +value)) { + throw ExpectationException::invalidValue('json', 'string'); + } + return $this->toBeJson()->and(json_decode($this->value, true)); } diff --git a/src/Functions.php b/src/Functions.php index ddc6f3af..0f72cee7 100644 --- a/src/Functions.php +++ b/src/Functions.php @@ -113,7 +113,10 @@ if (!function_exists('it')) { { $description = sprintf('it %s', $description); - return test($description, $closure); + /** @var TestCall $test */ + $test = test($description, $closure); + + return $test; } } diff --git a/src/HigherOrderExpectation.php b/src/HigherOrderExpectation.php index 839f3311..eb959cd4 100644 --- a/src/HigherOrderExpectation.php +++ b/src/HigherOrderExpectation.php @@ -80,7 +80,10 @@ final class HigherOrderExpectation } if (!$this->expectationHasMethod($name)) { - return new self($this->original, $this->retrieve($name, $this->getValue())); + /** @var array|object $value */ + $value = $this->getValue(); + + return new self($this->original, $this->retrieve($name, $value)); } return $this->performAssertion($name, []); diff --git a/src/Plugins/Coverage.php b/src/Plugins/Coverage.php index 8febde52..f2ee5457 100644 --- a/src/Plugins/Coverage.php +++ b/src/Plugins/Coverage.php @@ -80,7 +80,10 @@ final class Coverage implements AddsOutput, HandlesArguments } if ($input->getOption(self::MIN_OPTION) !== null) { - $this->coverageMin = (float) $input->getOption(self::MIN_OPTION); + /** @var int|float $min_option */ + $min_option = $input->getOption(self::MIN_OPTION); + + $this->coverageMin = (float) $min_option; } return $originals; diff --git a/src/Support/Container.php b/src/Support/Container.php index b87fdd65..6f2afc13 100644 --- a/src/Support/Container.php +++ b/src/Support/Container.php @@ -41,11 +41,13 @@ final class Container */ public function get(string $id) { - if (array_key_exists($id, $this->instances)) { - return $this->instances[$id]; + if (!array_key_exists($id, $this->instances)) { + $this->instances[$id] = $this->build($id); } - $this->instances[$id] = $this->build($id); + if (!is_object($this->instances[$id])) { + throw ShouldNotHappen::fromMessage('Cannot resolve a non-object from container'); + } return $this->instances[$id]; } diff --git a/src/Support/ExceptionTrace.php b/src/Support/ExceptionTrace.php index ec17afc8..17fc2e40 100644 --- a/src/Support/ExceptionTrace.php +++ b/src/Support/ExceptionTrace.php @@ -50,6 +50,8 @@ final class ExceptionTrace $property = new ReflectionProperty($t, 'serializableTrace'); $property->setAccessible(true); + + /** @var array> $trace */ $trace = $property->getValue($t); $cleanedTrace = []; diff --git a/src/Support/HigherOrderCallables.php b/src/Support/HigherOrderCallables.php index 1637ccb2..be02b86d 100644 --- a/src/Support/HigherOrderCallables.php +++ b/src/Support/HigherOrderCallables.php @@ -31,7 +31,10 @@ final class HigherOrderCallables */ public function expect(mixed $value): Expectation { - return new Expectation($value instanceof Closure ? Reflection::bindCallableWithData($value) : $value); + /** @var TValue $value */ + $value = $value instanceof Closure ? Reflection::bindCallableWithData($value) : $value; + + return new Expectation($value); } /** From 8cdca8d012c2af41de74e3ba6df66f297441bc29 Mon Sep 17 00:00:00 2001 From: Fabio Ivona Date: Thu, 18 Nov 2021 01:04:59 +0100 Subject: [PATCH 6/9] fix tests --- src/Exceptions/ExpectationException.php | 9 +++++++-- src/Support/Container.php | 4 ---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/Exceptions/ExpectationException.php b/src/Exceptions/ExpectationException.php index dfe63bb9..ca14ce76 100644 --- a/src/Exceptions/ExpectationException.php +++ b/src/Exceptions/ExpectationException.php @@ -1,10 +1,15 @@ instances[$id] = $this->build($id); } - if (!is_object($this->instances[$id])) { - throw ShouldNotHappen::fromMessage('Cannot resolve a non-object from container'); - } - return $this->instances[$id]; } From 9dd40e4610d685fde987344f37575a7be0a53c88 Mon Sep 17 00:00:00 2001 From: Fabio Ivona Date: Thu, 18 Nov 2021 01:14:57 +0100 Subject: [PATCH 7/9] fix phpstan failure --- phpstan.neon | 2 -- src/OppositeExpectation.php | 6 +++--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/phpstan.neon b/phpstan.neon index 89377d38..362ba447 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -7,8 +7,6 @@ parameters: level: 8 paths: - src - parallel: - maximumNumberOfProcesses: 1 checkMissingIterableValueType: true checkGenericClassInNonGenericObjectType: false diff --git a/src/OppositeExpectation.php b/src/OppositeExpectation.php index e4ec3d85..da9ec6ab 100644 --- a/src/OppositeExpectation.php +++ b/src/OppositeExpectation.php @@ -32,7 +32,7 @@ final class OppositeExpectation foreach ($keys as $key) { try { $this->original->toHaveKey($key); - } catch (ExpectationFailedException) { + } catch (ExpectationFailedException $exception) { continue; } @@ -54,7 +54,7 @@ final class OppositeExpectation try { /* @phpstan-ignore-next-line */ $this->original->{$name}(...$arguments); - } catch (ExpectationFailedException) { + } catch (ExpectationFailedException $exception) { return $this->original; } @@ -70,7 +70,7 @@ final class OppositeExpectation { try { $this->original->{$name}; // @phpstan-ignore-line - } catch (ExpectationFailedException) { // @phpstan-ignore-line + } catch (ExpectationFailedException $exception) { // @phpstan-ignore-line return $this->original; } From 7ea6d8a35d10758863f900ea078c14129f5104e0 Mon Sep 17 00:00:00 2001 From: Fabio Ivona Date: Thu, 18 Nov 2021 23:27:37 +0100 Subject: [PATCH 8/9] upgrade to phpstan lvl 9 --- phpstan.neon | 2 +- src/Datasets.php | 9 ++- src/Exceptions/ExpectationException.php | 7 ++- src/Expectation.php | 60 ++++++++++++++++++-- src/Support/Container.php | 2 +- src/Support/HigherOrderMessageCollection.php | 1 + 6 files changed, 70 insertions(+), 11 deletions(-) diff --git a/phpstan.neon b/phpstan.neon index 362ba447..ebd4bf30 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -4,7 +4,7 @@ includes: - vendor/thecodingmachine/phpstan-strict-rules/phpstan-strict-rules.neon parameters: - level: 8 + level: 9 paths: - src diff --git a/src/Datasets.php b/src/Datasets.php index c91de5e7..7f8013fe 100644 --- a/src/Datasets.php +++ b/src/Datasets.php @@ -98,7 +98,8 @@ final class Datasets foreach ($datasetCombination as $dataset_data) { $partialDescriptions[] = $dataset_data['label']; - $values = array_merge($values, $dataset_data['values']); + //@phpstan-ignore-next-line + $values = array_merge($values, $dataset_data['values']); } $dataSetDescriptions[] = $description . ' with ' . implode(' / ', $partialDescriptions); @@ -152,10 +153,11 @@ final class Datasets $datasets[$index] = iterator_to_array($datasets[$index]); } + //@phpstan-ignore-next-line foreach ($datasets[$index] as $key => $values) { $values = is_array($values) ? $values : [$values]; $processedDataset[] = [ - 'label' => self::getDataSetDescription($key, $values), + 'label' => self::getDataSetDescription($key, $values), //@phpstan-ignore-line 'values' => $values, ]; } @@ -169,7 +171,7 @@ final class Datasets /** * @param array> $combinations * - * @return array> + * @return array>> */ private static function getDataSetsCombinations(array $combinations): array { @@ -184,6 +186,7 @@ final class Datasets $result = $tmp; } + //@phpstan-ignore-next-line return $result; } diff --git a/src/Exceptions/ExpectationException.php b/src/Exceptions/ExpectationException.php index ca14ce76..be68b40c 100644 --- a/src/Exceptions/ExpectationException.php +++ b/src/Exceptions/ExpectationException.php @@ -9,8 +9,13 @@ namespace Pest\Exceptions; */ final class ExpectationException extends \Exception { - public static function invalidValue(string $expectationName, string $valueRequired): ExpectationException + public static function invalidCurrentValueType(string $expectationName, string $valueRequired): ExpectationException { return new ExpectationException(sprintf('%s expectation requires a %s value.', $expectationName, $valueRequired)); } + + public static function invalidExpectedValueType(string $expectationName, string $valueRequired): ExpectationException + { + return new ExpectationException(sprintf('%s expectation requires a %s as expected value.', $expectationName, $valueRequired)); + } } diff --git a/src/Expectation.php b/src/Expectation.php index dada9447..5ee04b0b 100644 --- a/src/Expectation.php +++ b/src/Expectation.php @@ -70,7 +70,7 @@ final class Expectation public function json(): Expectation { if (!is_string($this->value)) { - throw ExpectationException::invalidValue('json', 'string'); + throw ExpectationException::invalidCurrentValueType('json', 'string'); } return $this->toBeJson()->and(json_decode($this->value, true)); @@ -360,8 +360,14 @@ final class Expectation { foreach ($needles as $needle) { if (is_string($this->value)) { + if (!is_string($needle)) { + throw ExpectationException::invalidExpectedValueType('toContain', 'string'); + } Assert::assertStringContainsString($needle, $this->value); } else { + if (!is_iterable($this->value)) { + throw ExpectationException::invalidCurrentValueType('toContain', 'iterable'); + } Assert::assertContains($needle, $this->value); } } @@ -376,6 +382,10 @@ final class Expectation */ public function toStartWith(string $expected): Expectation { + if (!is_string($this->value)) { + throw ExpectationException::invalidCurrentValueType('toStartWith', 'string'); + } + Assert::assertStringStartsWith($expected, $this->value); return $this; @@ -388,6 +398,10 @@ final class Expectation */ public function toEndWith(string $expected): Expectation { + if (!is_string($this->value)) { + throw ExpectationException::invalidCurrentValueType('toEndWith', 'string'); + } + Assert::assertStringEndsWith($expected, $this->value); return $this; @@ -428,6 +442,10 @@ final class Expectation */ public function toHaveCount(int $count): Expectation { + if (!is_countable($this->value) && !is_iterable($this->value)) { + throw ExpectationException::invalidCurrentValueType('toHaveCount', 'string'); + } + Assert::assertCount($count, $this->value); return $this; @@ -440,6 +458,7 @@ final class Expectation { $this->toBeObject(); + //@phpstan-ignore-next-line Assert::assertTrue(property_exists($this->value, $name)); if (func_num_args() > 1) { @@ -651,6 +670,8 @@ final class Expectation public function toBeJson(): Expectation { Assert::assertIsString($this->value); + + //@phpstan-ignore-next-line Assert::assertJson($this->value); return $this; @@ -721,6 +742,10 @@ final class Expectation */ public function toBeDirectory(): Expectation { + if (!is_string($this->value)) { + throw ExpectationException::invalidCurrentValueType('toBeDirectory', 'string'); + } + Assert::assertDirectoryExists($this->value); return $this; @@ -731,6 +756,10 @@ final class Expectation */ public function toBeReadableDirectory(): Expectation { + if (!is_string($this->value)) { + throw ExpectationException::invalidCurrentValueType('toBeReadableDirectory', 'string'); + } + Assert::assertDirectoryIsReadable($this->value); return $this; @@ -741,6 +770,10 @@ final class Expectation */ public function toBeWritableDirectory(): Expectation { + if (!is_string($this->value)) { + throw ExpectationException::invalidCurrentValueType('toBeWritableDirectory', 'string'); + } + Assert::assertDirectoryIsWritable($this->value); return $this; @@ -751,6 +784,10 @@ final class Expectation */ public function toBeFile(): Expectation { + if (!is_string($this->value)) { + throw ExpectationException::invalidCurrentValueType('toBeFile', 'string'); + } + Assert::assertFileExists($this->value); return $this; @@ -761,6 +798,9 @@ final class Expectation */ public function toBeReadableFile(): Expectation { + if (!is_string($this->value)) { + throw ExpectationException::invalidCurrentValueType('toBeReadableFile', 'string'); + } Assert::assertFileIsReadable($this->value); return $this; @@ -771,6 +811,9 @@ final class Expectation */ public function toBeWritableFile(): Expectation { + if (!is_string($this->value)) { + throw ExpectationException::invalidCurrentValueType('toBeWritableFile', 'string'); + } Assert::assertFileIsWritable($this->value); return $this; @@ -815,6 +858,9 @@ final class Expectation public function toMatchObject(iterable|object $object): Expectation { foreach ((array) $object as $property => $value) { + if (!is_object($this->value) && !is_string($this->value)) { + throw ExpectationException::invalidCurrentValueType('toMatchObject', 'object|string'); + } Assert::assertTrue(property_exists($this->value, $property)); /* @phpstan-ignore-next-line */ @@ -838,6 +884,9 @@ final class Expectation */ public function toMatch(string $expression): Expectation { + if (!is_string($this->value)) { + throw ExpectationException::invalidCurrentValueType('toMatch', 'string'); + } Assert::assertMatchesRegularExpression($expression, $this->value); return $this; @@ -897,10 +946,10 @@ final class Expectation } if (!class_exists($exception)) { - throw new ExpectationFailedException("Exception with message \"{$exception}\" not thrown."); + throw new ExpectationFailedException("Exception with message \"$exception\" not thrown."); } - throw new ExpectationFailedException("Exception \"{$exception}\" not thrown."); + throw new ExpectationFailedException("Exception \"$exception\" not thrown."); } /** @@ -925,7 +974,7 @@ final class Expectation */ public function __call(string $method, array $parameters) { - if (!static::hasExtend($method)) { + if (!Expectation::hasExtend($method)) { /* @phpstan-ignore-next-line */ return new HigherOrderExpectation($this, $this->value->$method(...$parameters)); } @@ -939,7 +988,8 @@ final class Expectation */ public function __get(string $name): Expectation|OppositeExpectation|Each|HigherOrderExpectation { - if (!method_exists($this, $name) && !static::hasExtend($name)) { + if (!method_exists($this, $name) && !Expectation::hasExtend($name)) { + //@phpstan-ignore-next-line return new HigherOrderExpectation($this, $this->retrieve($name, $this->value)); } diff --git a/src/Support/Container.php b/src/Support/Container.php index 57b82f54..1f6b45cd 100644 --- a/src/Support/Container.php +++ b/src/Support/Container.php @@ -37,7 +37,7 @@ final class Container * * @param class-string $id * - * @return object + * @return mixed */ public function get(string $id) { diff --git a/src/Support/HigherOrderMessageCollection.php b/src/Support/HigherOrderMessageCollection.php index cb69a3a9..54bef82a 100644 --- a/src/Support/HigherOrderMessageCollection.php +++ b/src/Support/HigherOrderMessageCollection.php @@ -40,6 +40,7 @@ final class HigherOrderMessageCollection public function chain(object $target): void { foreach ($this->messages as $message) { + //@phpstan-ignore-next-line $target = $message->call($target) ?? $target; } } From 94585789dc24960c7f26d12889180ccaaf229cee Mon Sep 17 00:00:00 2001 From: Nuno Maduro Date: Thu, 18 Nov 2021 23:39:37 +0000 Subject: [PATCH 9/9] refacto(phpstan-to-8): few adjustments --- phpstan.neon | 2 +- src/Bootstrappers/BootSubscribers.php | 4 +- src/Datasets.php | 49 ++++++++++++---------- src/Exceptions/ExpectationException.php | 21 ---------- src/Exceptions/InvalidExpectationValue.php | 23 ++++++++++ src/Expectation.php | 36 ++++++++-------- src/Factories/Annotations/Depends.php | 6 +-- src/Factories/Annotations/Groups.php | 6 +-- src/Factories/TestCaseFactory.php | 10 ++--- src/Factories/TestCaseMethodFactory.php | 2 +- src/Functions.php | 2 +- src/PendingCalls/UsesCall.php | 6 +-- src/Plugins/Coverage.php | 6 +-- src/Support/Arr.php | 4 +- src/Support/ChainableClosure.php | 8 ++-- src/Support/Closure.php | 12 +++++- src/Support/ExceptionTrace.php | 2 +- src/Support/HigherOrderCallables.php | 2 +- 18 files changed, 107 insertions(+), 94 deletions(-) delete mode 100644 src/Exceptions/ExpectationException.php create mode 100644 src/Exceptions/InvalidExpectationValue.php diff --git a/phpstan.neon b/phpstan.neon index ebd4bf30..d5dc4ef6 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -4,7 +4,7 @@ includes: - vendor/thecodingmachine/phpstan-strict-rules/phpstan-strict-rules.neon parameters: - level: 9 + level: max paths: - src diff --git a/src/Bootstrappers/BootSubscribers.php b/src/Bootstrappers/BootSubscribers.php index 42bdeaba..12486f50 100644 --- a/src/Bootstrappers/BootSubscribers.php +++ b/src/Bootstrappers/BootSubscribers.php @@ -15,7 +15,7 @@ final class BootSubscribers /** * The Kernel subscribers. * - * @var array + * @var array> */ private static array $subscribers = [ Subscribers\EnsureConfigurationIsValid::class, @@ -29,7 +29,7 @@ final class BootSubscribers { foreach (self::$subscribers as $subscriber) { Event\Facade::registerSubscriber( - new $subscriber() //@phpstan-ignore-line + new $subscriber() ); } } diff --git a/src/Datasets.php b/src/Datasets.php index 7f8013fe..248b1d38 100644 --- a/src/Datasets.php +++ b/src/Datasets.php @@ -34,7 +34,7 @@ final class Datasets /** * Sets the given. * - * @phpstan-param Closure|iterable $data + * @param Closure|iterable $data */ public static function set(string $name, Closure|iterable $data): void { @@ -46,9 +46,9 @@ final class Datasets } /** - * Sets the given. + * Sets the given "with". * - * @phpstan-param array|string> $with + * @param array|string> $with */ public static function with(string $filename, string $description, array $with): void { @@ -56,7 +56,9 @@ final class Datasets } /** - * @return Closure|iterable + * @return Closure|iterable|never + * + * @throws ShouldNotHappen */ public static function get(string $filename, string $description): Closure|iterable { @@ -65,7 +67,7 @@ final class Datasets $dataset = self::resolve($description, $dataset); if ($dataset === null) { - throw ShouldNotHappen::fromMessage('Could not resolve dataset.'); + throw ShouldNotHappen::fromMessage('Dataset [%s] not resolvable.'); } return $dataset; @@ -87,39 +89,40 @@ final class Datasets $dataset = self::processDatasets($dataset); - $datasetCombinations = self::getDataSetsCombinations($dataset); + $datasetCombinations = self::getDatasetsCombinations($dataset); - $dataSetDescriptions = []; - $dataSetValues = []; + $datasetDescriptions = []; + $datasetValues = []; foreach ($datasetCombinations as $datasetCombination) { $partialDescriptions = []; $values = []; - foreach ($datasetCombination as $dataset_data) { - $partialDescriptions[] = $dataset_data['label']; - //@phpstan-ignore-next-line - $values = array_merge($values, $dataset_data['values']); + foreach ($datasetCombination as $datasetCombinationElement) { + $partialDescriptions[] = $datasetCombinationElement['label']; + + // @phpstan-ignore-next-line + $values = array_merge($values, $datasetCombinationElement['values']); } - $dataSetDescriptions[] = $description . ' with ' . implode(' / ', $partialDescriptions); - $dataSetValues[] = $values; + $datasetDescriptions[] = $description . ' with ' . implode(' / ', $partialDescriptions); + $datasetValues[] = $values; } - foreach (array_count_values($dataSetDescriptions) as $descriptionToCheck => $count) { + foreach (array_count_values($datasetDescriptions) as $descriptionToCheck => $count) { if ($count > 1) { $index = 1; - foreach ($dataSetDescriptions as $i => $dataSetDescription) { - if ($dataSetDescription === $descriptionToCheck) { - $dataSetDescriptions[$i] .= sprintf(' #%d', $index++); + foreach ($datasetDescriptions as $i => $datasetDescription) { + if ($datasetDescription === $descriptionToCheck) { + $datasetDescriptions[$i] .= sprintf(' #%d', $index++); } } } } $namedData = []; - foreach ($dataSetDescriptions as $i => $dataSetDescription) { - $namedData[$dataSetDescription] = $dataSetValues[$i]; + foreach ($datasetDescriptions as $i => $datasetDescription) { + $namedData[$datasetDescription] = $datasetValues[$i]; } return $namedData; @@ -157,7 +160,7 @@ final class Datasets foreach ($datasets[$index] as $key => $values) { $values = is_array($values) ? $values : [$values]; $processedDataset[] = [ - 'label' => self::getDataSetDescription($key, $values), //@phpstan-ignore-line + 'label' => self::getDatasetDescription($key, $values), //@phpstan-ignore-line 'values' => $values, ]; } @@ -173,7 +176,7 @@ final class Datasets * * @return array>> */ - private static function getDataSetsCombinations(array $combinations): array + private static function getDatasetsCombinations(array $combinations): array { $result = [[]]; foreach ($combinations as $index => $values) { @@ -193,7 +196,7 @@ final class Datasets /** * @param array $data */ - private static function getDataSetDescription(int|string $key, array $data): string + private static function getDatasetDescription(int|string $key, array $data): string { $exporter = new Exporter(); diff --git a/src/Exceptions/ExpectationException.php b/src/Exceptions/ExpectationException.php deleted file mode 100644 index be68b40c..00000000 --- a/src/Exceptions/ExpectationException.php +++ /dev/null @@ -1,21 +0,0 @@ -value)) { - throw ExpectationException::invalidCurrentValueType('json', 'string'); + InvalidExpectationValue::expected('string'); } return $this->toBeJson()->and(json_decode($this->value, true)); @@ -360,13 +360,11 @@ final class Expectation { foreach ($needles as $needle) { if (is_string($this->value)) { - if (!is_string($needle)) { - throw ExpectationException::invalidExpectedValueType('toContain', 'string'); - } - Assert::assertStringContainsString($needle, $this->value); + // @phpstan-ignore-next-line + Assert::assertStringContainsString((string) $needle, $this->value); } else { if (!is_iterable($this->value)) { - throw ExpectationException::invalidCurrentValueType('toContain', 'iterable'); + InvalidExpectationValue::expected('iterable'); } Assert::assertContains($needle, $this->value); } @@ -383,7 +381,7 @@ final class Expectation public function toStartWith(string $expected): Expectation { if (!is_string($this->value)) { - throw ExpectationException::invalidCurrentValueType('toStartWith', 'string'); + InvalidExpectationValue::expected('string'); } Assert::assertStringStartsWith($expected, $this->value); @@ -399,7 +397,7 @@ final class Expectation public function toEndWith(string $expected): Expectation { if (!is_string($this->value)) { - throw ExpectationException::invalidCurrentValueType('toEndWith', 'string'); + InvalidExpectationValue::expected('string'); } Assert::assertStringEndsWith($expected, $this->value); @@ -443,7 +441,7 @@ final class Expectation public function toHaveCount(int $count): Expectation { if (!is_countable($this->value) && !is_iterable($this->value)) { - throw ExpectationException::invalidCurrentValueType('toHaveCount', 'string'); + InvalidExpectationValue::expected('string'); } Assert::assertCount($count, $this->value); @@ -743,7 +741,7 @@ final class Expectation public function toBeDirectory(): Expectation { if (!is_string($this->value)) { - throw ExpectationException::invalidCurrentValueType('toBeDirectory', 'string'); + InvalidExpectationValue::expected('string'); } Assert::assertDirectoryExists($this->value); @@ -757,7 +755,7 @@ final class Expectation public function toBeReadableDirectory(): Expectation { if (!is_string($this->value)) { - throw ExpectationException::invalidCurrentValueType('toBeReadableDirectory', 'string'); + InvalidExpectationValue::expected('string'); } Assert::assertDirectoryIsReadable($this->value); @@ -771,7 +769,7 @@ final class Expectation public function toBeWritableDirectory(): Expectation { if (!is_string($this->value)) { - throw ExpectationException::invalidCurrentValueType('toBeWritableDirectory', 'string'); + InvalidExpectationValue::expected('string'); } Assert::assertDirectoryIsWritable($this->value); @@ -785,7 +783,7 @@ final class Expectation public function toBeFile(): Expectation { if (!is_string($this->value)) { - throw ExpectationException::invalidCurrentValueType('toBeFile', 'string'); + InvalidExpectationValue::expected('string'); } Assert::assertFileExists($this->value); @@ -799,8 +797,9 @@ final class Expectation public function toBeReadableFile(): Expectation { if (!is_string($this->value)) { - throw ExpectationException::invalidCurrentValueType('toBeReadableFile', 'string'); + InvalidExpectationValue::expected('string'); } + Assert::assertFileIsReadable($this->value); return $this; @@ -812,7 +811,7 @@ final class Expectation public function toBeWritableFile(): Expectation { if (!is_string($this->value)) { - throw ExpectationException::invalidCurrentValueType('toBeWritableFile', 'string'); + InvalidExpectationValue::expected('string'); } Assert::assertFileIsWritable($this->value); @@ -859,8 +858,9 @@ final class Expectation { foreach ((array) $object as $property => $value) { if (!is_object($this->value) && !is_string($this->value)) { - throw ExpectationException::invalidCurrentValueType('toMatchObject', 'object|string'); + InvalidExpectationValue::expected('object|string'); } + Assert::assertTrue(property_exists($this->value, $property)); /* @phpstan-ignore-next-line */ @@ -885,7 +885,7 @@ final class Expectation public function toMatch(string $expression): Expectation { if (!is_string($this->value)) { - throw ExpectationException::invalidCurrentValueType('toMatch', 'string'); + InvalidExpectationValue::expected('string'); } Assert::assertMatchesRegularExpression($expression, $this->value); diff --git a/src/Factories/Annotations/Depends.php b/src/Factories/Annotations/Depends.php index 66c4838c..f41076d9 100644 --- a/src/Factories/Annotations/Depends.php +++ b/src/Factories/Annotations/Depends.php @@ -15,11 +15,11 @@ final class Depends /** * Adds annotations regarding the "depends" feature. * - * @param array $annotations + * @param array $annotations * - * @return array + * @return array */ - public function add(TestCaseMethodFactory $method, array $annotations): array + public function __invoke(TestCaseMethodFactory $method, array $annotations): array { foreach ($method->depends as $depend) { $depend = Str::evaluable($depend); diff --git a/src/Factories/Annotations/Groups.php b/src/Factories/Annotations/Groups.php index ab7749b7..0876ff5c 100644 --- a/src/Factories/Annotations/Groups.php +++ b/src/Factories/Annotations/Groups.php @@ -14,11 +14,11 @@ final class Groups /** * Adds annotations regarding the "groups" feature. * - * @param array $annotations + * @param array $annotations * - * @return array + * @return array */ - public function add(TestCaseMethodFactory $method, array $annotations): array + public function __invoke(TestCaseMethodFactory $method, array $annotations): array { foreach ($method->groups as $group) { $annotations[] = "@group $group"; diff --git a/src/Factories/TestCaseFactory.php b/src/Factories/TestCaseFactory.php index 517a586c..f6a61ba2 100644 --- a/src/Factories/TestCaseFactory.php +++ b/src/Factories/TestCaseFactory.php @@ -73,9 +73,9 @@ final class TestCaseFactory { $methodsUsingOnly = $this->methodsUsingOnly(); - $methods = array_filter($this->methods, function ($method) use ($methodsUsingOnly) { + $methods = array_values(array_filter($this->methods, function ($method) use ($methodsUsingOnly) { return count($methodsUsingOnly) === 0 || in_array($method, $methodsUsingOnly, true); - }); + })); if (count($methods) > 0) { $this->evaluate($this->filename, $methods); @@ -99,7 +99,7 @@ final class TestCaseFactory /** * Creates a Test Case class using a runtime evaluate. * - * @param array $methods + * @param array $methods */ public function evaluate(string $filename, array $methods): string { @@ -152,8 +152,8 @@ final class TestCaseFactory $annotations = ['@test']; foreach (self::$annotations as $annotation) { - //@phpstan-ignore-next-line - $annotations = (new $annotation())->add($method, $annotations); + /** @phpstan-ignore-next-line */ + $annotations = (new $annotation())->__invoke($method, $annotations); } if (count($method->datasets) > 0) { diff --git a/src/Factories/TestCaseMethodFactory.php b/src/Factories/TestCaseMethodFactory.php index e2ece273..540f2677 100644 --- a/src/Factories/TestCaseMethodFactory.php +++ b/src/Factories/TestCaseMethodFactory.php @@ -89,7 +89,7 @@ final class TestCaseMethodFactory $testCase->chains->chain($this); $method->chains->chain($this); - return \Pest\Support\Closure::safeBind($closure, $this, $this::class)(...func_get_args()); + return \Pest\Support\Closure::bind($closure, $this, $this::class)(...func_get_args()); }; } diff --git a/src/Functions.php b/src/Functions.php index 0f72cee7..fe1dd39a 100644 --- a/src/Functions.php +++ b/src/Functions.php @@ -77,7 +77,7 @@ if (!function_exists('uses')) { { $filename = Backtrace::file(); - return new UsesCall($filename, $classAndTraits); + return new UsesCall($filename, array_values($classAndTraits)); } } diff --git a/src/PendingCalls/UsesCall.php b/src/PendingCalls/UsesCall.php index 457f8699..cb3fdc8c 100644 --- a/src/PendingCalls/UsesCall.php +++ b/src/PendingCalls/UsesCall.php @@ -36,14 +36,14 @@ final class UsesCall /** * Holds the groups of the uses. * - * @var array + * @var array */ private array $groups = []; /** * Creates a new Pending Call. * - * @param array $classAndTraits + * @param array $classAndTraits */ public function __construct( private string $filename, @@ -89,7 +89,7 @@ final class UsesCall */ public function group(string ...$groups): UsesCall { - $this->groups = $groups; + $this->groups = array_values($groups); return $this; } diff --git a/src/Plugins/Coverage.php b/src/Plugins/Coverage.php index f2ee5457..9cf45f3b 100644 --- a/src/Plugins/Coverage.php +++ b/src/Plugins/Coverage.php @@ -80,10 +80,10 @@ final class Coverage implements AddsOutput, HandlesArguments } if ($input->getOption(self::MIN_OPTION) !== null) { - /** @var int|float $min_option */ - $min_option = $input->getOption(self::MIN_OPTION); + /** @var int|float $minOption */ + $minOption = $input->getOption(self::MIN_OPTION); - $this->coverageMin = (float) $min_option; + $this->coverageMin = (float) $minOption; } return $originals; diff --git a/src/Support/Arr.php b/src/Support/Arr.php index 531e0d19..922110e1 100644 --- a/src/Support/Arr.php +++ b/src/Support/Arr.php @@ -12,7 +12,7 @@ final class Arr /** * Checks if the given array has the given key. * - * @param array $array + * @param array $array */ public static function has(array $array, string|int $key): bool { @@ -36,7 +36,7 @@ final class Arr /** * Gets the given key value. * - * @param array $array + * @param array $array */ public static function get(array $array, string|int $key, mixed $default = null): mixed { diff --git a/src/Support/ChainableClosure.php b/src/Support/ChainableClosure.php index b3406d86..5c92e6fd 100644 --- a/src/Support/ChainableClosure.php +++ b/src/Support/ChainableClosure.php @@ -22,8 +22,8 @@ final class ChainableClosure throw ShouldNotHappen::fromMessage('$this not bound to chainable closure.'); } - \Pest\Support\Closure::safeBind($closure, $this, $this::class)(...func_get_args()); - \Pest\Support\Closure::safeBind($next, $this, $this::class)(...func_get_args()); + \Pest\Support\Closure::bind($closure, $this, $this::class)(...func_get_args()); + \Pest\Support\Closure::bind($next, $this, $this::class)(...func_get_args()); }; } @@ -33,8 +33,8 @@ final class ChainableClosure public static function fromStatic(Closure $closure, Closure $next): Closure { return static function () use ($closure, $next): void { - \Pest\Support\Closure::safeBind($closure, null, self::class)(...func_get_args()); - \Pest\Support\Closure::safeBind($next, null, self::class)(...func_get_args()); + \Pest\Support\Closure::bind($closure, null, self::class)(...func_get_args()); + \Pest\Support\Closure::bind($next, null, self::class)(...func_get_args()); }; } } diff --git a/src/Support/Closure.php b/src/Support/Closure.php index ece77d57..decb9b71 100644 --- a/src/Support/Closure.php +++ b/src/Support/Closure.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace Pest\Support; +use Closure as BaseClosure; use Pest\Exceptions\ShouldNotHappen; /** @@ -11,13 +12,20 @@ use Pest\Exceptions\ShouldNotHappen; */ final class Closure { - public static function safeBind(\Closure|null $closure, ?object $newThis, object|string|null $newScope = 'static'): \Closure + /** + * Binds the given closure to the given "this". + * + * @return BaseClosure|never + * + * @throws ShouldNotHappen + */ + public static function bind(BaseClosure|null $closure, ?object $newThis, object|string|null $newScope = 'static'): BaseClosure { if ($closure == null) { throw ShouldNotHappen::fromMessage('Could not bind null closure.'); } - $closure = \Closure::bind($closure, $newThis, $newScope); + $closure = BaseClosure::bind($closure, $newThis, $newScope); if ($closure == false) { throw ShouldNotHappen::fromMessage('Could not bind closure.'); diff --git a/src/Support/ExceptionTrace.php b/src/Support/ExceptionTrace.php index 17fc2e40..2e6d53f4 100644 --- a/src/Support/ExceptionTrace.php +++ b/src/Support/ExceptionTrace.php @@ -51,7 +51,7 @@ final class ExceptionTrace $property = new ReflectionProperty($t, 'serializableTrace'); $property->setAccessible(true); - /** @var array> $trace */ + /** @var array> $trace */ $trace = $property->getValue($t); $cleanedTrace = []; diff --git a/src/Support/HigherOrderCallables.php b/src/Support/HigherOrderCallables.php index be02b86d..c6533929 100644 --- a/src/Support/HigherOrderCallables.php +++ b/src/Support/HigherOrderCallables.php @@ -25,7 +25,7 @@ final class HigherOrderCallables * * Create a new expectation. Callable values will be executed prior to returning the new expectation. * - * @param (callable():TValue)|TValue $value + * @param (Closure():TValue)|TValue $value * * @return Expectation */