Code quality improvements

This commit is contained in:
Nuno Maduro
2022-09-16 11:27:17 +01:00
parent e9564febaf
commit 45011ebd14
42 changed files with 266 additions and 278 deletions

View File

@ -52,6 +52,3 @@ jobs:
- name: Style - name: Style
run: composer test:lint run: composer test:lint
- name: Recfato
run: composer test:refacto

View File

@ -56,8 +56,7 @@
"phpstan/phpstan": "^1.8.5", "phpstan/phpstan": "^1.8.5",
"phpstan/phpstan-strict-rules": "^1.4.3", "phpstan/phpstan-strict-rules": "^1.4.3",
"symfony/var-dumper": "^6.2.0", "symfony/var-dumper": "^6.2.0",
"thecodingmachine/phpstan-strict-rules": "^1.0.0", "thecodingmachine/phpstan-strict-rules": "^1.0.0"
"rector/rector": "^0.14.2"
}, },
"minimum-stability": "dev", "minimum-stability": "dev",
"prefer-stable": true, "prefer-stable": true,
@ -73,9 +72,7 @@
], ],
"scripts": { "scripts": {
"lint": "pint --test", "lint": "pint --test",
"refactor": "rector",
"test:lint": "pint --test", "test:lint": "pint --test",
"test:refactor": "rector --dry-run",
"test:types": "phpstan analyse --ansi --memory-limit=-1 --debug", "test:types": "phpstan analyse --ansi --memory-limit=-1 --debug",
"test:unit": "php bin/pest --colors=always --exclude-group=integration", "test:unit": "php bin/pest --colors=always --exclude-group=integration",
"test:parallel": "exit 1", "test:parallel": "exit 1",
@ -85,8 +82,7 @@
"@test:lint", "@test:lint",
"@test:types", "@test:types",
"@test:unit", "@test:unit",
"@test:integration", "@test:integration"
"@test:refactor"
] ]
}, },
"extra": { "extra": {

View File

@ -63,8 +63,12 @@ final class BootFiles
*/ */
private function load(string $filename): void private function load(string $filename): void
{ {
if (Str::endsWith($filename, '.php') && file_exists($filename)) { if (! Str::endsWith($filename, '.php')) {
return;
}
if (! file_exists($filename)) {
return;
}
include_once $filename; include_once $filename;
} }
} }
}

View File

@ -17,7 +17,7 @@ final class BootSubscribers
* *
* @var array<int, class-string<\PHPUnit\Event\Subscriber>> * @var array<int, class-string<\PHPUnit\Event\Subscriber>>
*/ */
private static array $subscribers = [ private const SUBSCRIBERS = [
Subscribers\EnsureConfigurationIsValid::class, Subscribers\EnsureConfigurationIsValid::class,
Subscribers\EnsureConfigurationDefaults::class, Subscribers\EnsureConfigurationDefaults::class,
Subscribers\EnsureRetryRepositoryExists::class, Subscribers\EnsureRetryRepositoryExists::class,
@ -29,7 +29,7 @@ final class BootSubscribers
*/ */
public function __invoke(): void public function __invoke(): void
{ {
foreach (self::$subscribers as $subscriber) { foreach (self::SUBSCRIBERS as $subscriber) {
Event\Facade::registerSubscriber( Event\Facade::registerSubscriber(
new $subscriber() new $subscriber()
); );

View File

@ -35,16 +35,14 @@ trait Pipeable
public function intercept(string $name, string|Closure $filter, Closure $handler): void public function intercept(string $name, string|Closure $filter, Closure $handler): void
{ {
if (is_string($filter)) { if (is_string($filter)) {
$filter = function ($value) use ($filter): bool { $filter = fn ($value): bool => $value instanceof $filter;
return $value instanceof $filter;
};
} }
$this->pipe($name, function ($next, ...$arguments) use ($handler, $filter) { $this->pipe($name, function ($next, ...$arguments) use ($handler, $filter): void {
/* @phpstan-ignore-next-line */ /* @phpstan-ignore-next-line */
if ($filter($this->value, ...$arguments)) { if ($filter($this->value, ...$arguments)) {
// @phpstan-ignore-next-line // @phpstan-ignore-next-line
$handler->bindTo($this, get_class($this))(...$arguments); $handler->bindTo($this, $this::class)(...$arguments);
return; return;
} }

View File

@ -79,7 +79,7 @@ trait Testable
*/ */
public function __addBeforeAll(?Closure $hook): void public function __addBeforeAll(?Closure $hook): void
{ {
if (! $hook) { if ($hook === null) {
return; return;
} }
@ -93,7 +93,7 @@ trait Testable
*/ */
public function __addAfterAll(?Closure $hook): void public function __addAfterAll(?Closure $hook): void
{ {
if (! $hook) { if ($hook === null) {
return; return;
} }
@ -123,7 +123,7 @@ trait Testable
*/ */
private function __addHook(string $property, ?Closure $hook): void private function __addHook(string $property, ?Closure $hook): void
{ {
if (! $hook) { if ($hook === null) {
return; return;
} }
@ -221,11 +221,7 @@ trait Testable
{ {
$method = TestSuite::getInstance()->tests->get(self::$__filename)->getMethod($this->name()); $method = TestSuite::getInstance()->tests->get(self::$__filename)->getMethod($this->name());
if ($this->dataName()) { self::$__description = $this->dataName() ? $method->description.' with '.$this->dataName() : $method->description;
self::$__description = $method->description.' with '.$this->dataName();
} else {
self::$__description = $method->description;
}
if (count($arguments) !== 1) { if (count($arguments) !== 1) {
return $arguments; return $arguments;
@ -238,13 +234,15 @@ trait Testable
$underlyingTest = Reflection::getFunctionVariable($this->__test, 'closure'); $underlyingTest = Reflection::getFunctionVariable($this->__test, 'closure');
$testParameterTypes = array_values(Reflection::getFunctionArguments($underlyingTest)); $testParameterTypes = array_values(Reflection::getFunctionArguments($underlyingTest));
if (in_array($testParameterTypes[0], ['Closure', 'callable'])) { if (in_array($testParameterTypes[0], [\Closure::class, 'callable'])) {
return $arguments; return $arguments;
} }
$boundDatasetResult = $this->__callClosure($arguments[0], []); $boundDatasetResult = $this->__callClosure($arguments[0], []);
if (count($testParameterTypes) === 1) {
if (count($testParameterTypes) === 1 || ! is_array($boundDatasetResult)) { return [$boundDatasetResult];
}
if (! is_array($boundDatasetResult)) {
return [$boundDatasetResult]; return [$boundDatasetResult];
} }

View File

@ -28,7 +28,7 @@ final class ConfigLoader
/** /**
* Creates a new instance of the config loader. * Creates a new instance of the config loader.
*/ */
public function __construct(private string $rootPath) public function __construct(private readonly string $rootPath)
{ {
$this->loadConfiguration(); $this->loadConfiguration();
} }
@ -38,14 +38,14 @@ final class ConfigLoader
*/ */
public function getTestsDirectory(): string public function getTestsDirectory(): string
{ {
$suiteDirectory = [];
if (is_null($this->config)) { if (is_null($this->config)) {
return self::DEFAULT_TESTS_PATH; return self::DEFAULT_TESTS_PATH;
} }
$suiteDirectory = $this->config->xpath('/phpunit/testsuites/testsuite/directory'); $suiteDirectory = $this->config->xpath('/phpunit/testsuites/testsuite/directory');
// @phpstan-ignore-next-line if ($suiteDirectory === []) {
if (! $suiteDirectory || count($suiteDirectory) === 0) {
return self::DEFAULT_TESTS_PATH; return self::DEFAULT_TESTS_PATH;
} }
@ -68,7 +68,7 @@ final class ConfigLoader
/** /**
* Get the configuration file path. * Get the configuration file path.
*/ */
public function getConfigurationFilePath(): string|false public function getConfigurationFilePath(): string|bool
{ {
$candidates = [ $candidates = [
$this->rootPath.'/phpunit.xml', $this->rootPath.'/phpunit.xml',
@ -92,7 +92,7 @@ final class ConfigLoader
{ {
$configPath = $this->getConfigurationFilePath(); $configPath = $this->getConfigurationFilePath();
if ($configPath === false) { if (is_bool($configPath)) {
return; return;
} }

View File

@ -27,7 +27,7 @@ final class Help
/** /**
* Creates a new Console Command instance. * Creates a new Console Command instance.
*/ */
public function __construct(private OutputInterface $output) public function __construct(private readonly OutputInterface $output)
{ {
// .. // ..
} }

View File

@ -32,7 +32,7 @@ final class Thanks
/** /**
* Creates a new Console Command instance. * Creates a new Console Command instance.
*/ */
public function __construct(private OutputInterface $output) public function __construct(private readonly OutputInterface $output)
{ {
// .. // ..
} }

View File

@ -70,7 +70,7 @@ final class Expectation
} }
/** @var array<int|string, mixed>|bool $value */ /** @var array<int|string, mixed>|bool $value */
$value = json_decode($this->value, true); $value = json_decode($this->value, true, 512);
return $this->toBeJson()->and($value); return $this->toBeJson()->and($value);
} }
@ -159,7 +159,7 @@ final class Expectation
* @param (callable(self<TValue>, self<string|int>): void)|TSequenceValue ...$callbacks * @param (callable(self<TValue>, self<string|int>): void)|TSequenceValue ...$callbacks
* @return self<TValue> * @return self<TValue>
*/ */
public function sequence(mixed ...$callbacks): Expectation public function sequence(mixed ...$callbacks): self
{ {
if (! is_iterable($this->value)) { if (! is_iterable($this->value)) {
throw new BadMethodCallException('Expectation value is not iterable.'); throw new BadMethodCallException('Expectation value is not iterable.');
@ -203,7 +203,7 @@ final class Expectation
* @param array<TMatchSubject, (callable(self<TValue>): mixed)|TValue> $expressions * @param array<TMatchSubject, (callable(self<TValue>): mixed)|TValue> $expressions
* @return self<TValue> * @return self<TValue>
*/ */
public function match(mixed $subject, array $expressions): Expectation public function match(mixed $subject, array $expressions): self
{ {
$subject = $subject instanceof Closure ? $subject() : $subject; $subject = $subject instanceof Closure ? $subject() : $subject;
@ -245,9 +245,7 @@ final class Expectation
{ {
$condition = is_callable($condition) $condition = is_callable($condition)
? $condition ? $condition
: static function () use ($condition): bool { : static fn (): bool => $condition;
return $condition;
};
return $this->when(! $condition(), $callback); return $this->when(! $condition(), $callback);
} }
@ -259,13 +257,11 @@ final class Expectation
* @param callable(self<TValue>): mixed $callback * @param callable(self<TValue>): mixed $callback
* @return self<TValue> * @return self<TValue>
*/ */
public function when(callable|bool $condition, callable $callback): Expectation public function when(callable|bool $condition, callable $callback): self
{ {
$condition = is_callable($condition) $condition = is_callable($condition)
? $condition ? $condition
: static function () use ($condition): bool { : static fn (): bool => $condition;
return $condition;
};
if ($condition()) { if ($condition()) {
$callback($this->and($this->value)); $callback($this->and($this->value));

View File

@ -23,7 +23,7 @@ final class EachExpectation
* *
* @param Expectation<TValue> $original * @param Expectation<TValue> $original
*/ */
public function __construct(private Expectation $original) public function __construct(private readonly Expectation $original)
{ {
} }
@ -45,7 +45,7 @@ final class EachExpectation
* *
* @return self<TValue> * @return self<TValue>
*/ */
public function not(): EachExpectation public function not(): self
{ {
$this->opposite = true; $this->opposite = true;
@ -58,7 +58,7 @@ final class EachExpectation
* @param array<int|string, mixed> $arguments * @param array<int|string, mixed> $arguments
* @return self<TValue> * @return self<TValue>
*/ */
public function __call(string $name, array $arguments): EachExpectation public function __call(string $name, array $arguments): self
{ {
foreach ($this->original->value as $item) { foreach ($this->original->value as $item) {
/* @phpstan-ignore-next-line */ /* @phpstan-ignore-next-line */
@ -75,7 +75,7 @@ final class EachExpectation
* *
* @return self<TValue> * @return self<TValue>
*/ */
public function __get(string $name): EachExpectation public function __get(string $name): self
{ {
/* @phpstan-ignore-next-line */ /* @phpstan-ignore-next-line */
return $this->$name(); return $this->$name();

View File

@ -35,7 +35,7 @@ final class HigherOrderExpectation
* @param Expectation<TOriginalValue> $original * @param Expectation<TOriginalValue> $original
* @param TValue $value * @param TValue $value
*/ */
public function __construct(private Expectation $original, mixed $value) public function __construct(private readonly Expectation $original, mixed $value)
{ {
$this->expectation = $this->expect($value); $this->expectation = $this->expect($value);
} }
@ -45,7 +45,7 @@ final class HigherOrderExpectation
* *
* @return self<TOriginalValue, TValue> * @return self<TOriginalValue, TValue>
*/ */
public function not(): HigherOrderExpectation public function not(): self
{ {
$this->opposite = ! $this->opposite; $this->opposite = ! $this->opposite;
@ -144,7 +144,14 @@ final class HigherOrderExpectation
*/ */
private function expectationHasMethod(string $name): bool private function expectationHasMethod(string $name): bool
{ {
return method_exists($this->original, $name) || $this->original::hasMethod($name) || $this->original::hasExtend($name); if (method_exists($this->original, $name)) {
return true;
}
if ($this->original::hasMethod($name)) {
return true;
}
return $this->original::hasExtend($name);
} }
/** /**

View File

@ -23,7 +23,7 @@ final class OppositeExpectation
* *
* @param Expectation<TValue> $original * @param Expectation<TValue> $original
*/ */
public function __construct(private Expectation $original) public function __construct(private readonly Expectation $original)
{ {
} }

View File

@ -30,7 +30,7 @@ final class TestCaseFactory
* *
* @var array<int, class-string> * @var array<int, class-string>
*/ */
private static array $annotations = [ private const ANNOTATIONS = [
Annotations\Depends::class, Annotations\Depends::class,
Annotations\Groups::class, Annotations\Groups::class,
Annotations\CoversNothing::class, Annotations\CoversNothing::class,
@ -41,7 +41,7 @@ final class TestCaseFactory
* *
* @var array<int, class-string<\Pest\Factories\Attributes\Attribute>> * @var array<int, class-string<\Pest\Factories\Attributes\Attribute>>
*/ */
private static array $attributes = [ private const ATTRIBUTES = [
Attributes\Covers::class, Attributes\Covers::class,
]; ];
@ -84,10 +84,10 @@ final class TestCaseFactory
$methods = array_values(array_filter( $methods = array_values(array_filter(
$this->methods, $this->methods,
fn ($method) => count($methodsUsingOnly) === 0 || in_array($method, $methodsUsingOnly, true) fn ($method) => $methodsUsingOnly === [] || in_array($method, $methodsUsingOnly, true)
)); ));
if (count($methods) > 0) { if ($methods !== []) {
$this->evaluate($this->filename, $methods); $this->evaluate($this->filename, $methods);
} }
} }
@ -162,8 +162,8 @@ final class TestCaseFactory
$classFQN .= $className; $classFQN .= $className;
} }
$classAvailableAttributes = array_filter(self::$attributes, fn (string $attribute) => $attribute::ABOVE_CLASS); $classAvailableAttributes = array_filter(self::ATTRIBUTES, fn (string $attribute) => $attribute::ABOVE_CLASS);
$methodAvailableAttributes = array_filter(self::$attributes, fn (string $attribute) => ! $attribute::ABOVE_CLASS); $methodAvailableAttributes = array_filter(self::ATTRIBUTES, fn (string $attribute) => ! $attribute::ABOVE_CLASS);
$classAttributes = []; $classAttributes = [];
@ -178,7 +178,7 @@ final class TestCaseFactory
$methodsCode = implode('', array_map( $methodsCode = implode('', array_map(
fn (TestCaseMethodFactory $methodFactory) => $methodFactory->buildForEvaluation( fn (TestCaseMethodFactory $methodFactory) => $methodFactory->buildForEvaluation(
$classFQN, $classFQN,
self::$annotations, self::ANNOTATIONS,
$methodAvailableAttributes $methodAvailableAttributes
), ),
$methods $methods
@ -232,7 +232,7 @@ final class TestCaseFactory
$arguments = Reflection::getFunctionArguments($method->closure); $arguments = Reflection::getFunctionArguments($method->closure);
if (count($arguments) > 0) { if ($arguments !== []) {
throw new DatasetMissing($method->filename, $method->description, $arguments); throw new DatasetMissing($method->filename, $method->description, $arguments);
} }
} }

View File

@ -62,7 +62,7 @@ final class TestCaseMethodFactory
public ?string $description, public ?string $description,
public ?Closure $closure, public ?Closure $closure,
) { ) {
$this->closure ??= function () { $this->closure ??= function (): void {
Assert::getCount() > 0 ?: self::markTestIncomplete(); // @phpstan-ignore-line Assert::getCount() > 0 ?: self::markTestIncomplete(); // @phpstan-ignore-line
}; };
@ -106,7 +106,7 @@ final class TestCaseMethodFactory
*/ */
public function receivesArguments(): bool public function receivesArguments(): bool
{ {
return count($this->datasets) > 0 || count($this->depends) > 0; return $this->datasets !== [] || $this->depends !== [];
} }
/** /**
@ -140,7 +140,7 @@ final class TestCaseMethodFactory
$attributes = (new $attribute())->__invoke($this, $attributes); $attributes = (new $attribute())->__invoke($this, $attributes);
} }
if (count($this->datasets) > 0) { if ($this->datasets !== []) {
$dataProviderName = $methodName.'_dataset'; $dataProviderName = $methodName.'_dataset';
$annotations[] = "@dataProvider $dataProviderName"; $annotations[] = "@dataProvider $dataProviderName";
$datasetsCode = $this->buildDatasetForEvaluation($methodName, $dataProviderName); $datasetsCode = $this->buildDatasetForEvaluation($methodName, $dataProviderName);

View File

@ -19,8 +19,8 @@ if (! function_exists('expect')) {
* *
* @template TValue * @template TValue
* *
* @param TValue $value * @param TValue|null $value
* @return Expectation<TValue> * @return Expectation<TValue|null>
*/ */
function expect(mixed $value = null): Expectation function expect(mixed $value = null): Expectation
{ {

View File

@ -24,7 +24,7 @@ final class Kernel
* *
* @var array<int, class-string> * @var array<int, class-string>
*/ */
private static array $bootstrappers = [ private const BOOTSTRAPPERS = [
Bootstrappers\BootExceptionHandler::class, Bootstrappers\BootExceptionHandler::class,
Bootstrappers\BootSubscribers::class, Bootstrappers\BootSubscribers::class,
Bootstrappers\BootFiles::class, Bootstrappers\BootFiles::class,
@ -34,7 +34,7 @@ final class Kernel
* Creates a new Kernel instance. * Creates a new Kernel instance.
*/ */
public function __construct( public function __construct(
private Application $application private readonly Application $application
) { ) {
// .. // ..
} }
@ -44,8 +44,7 @@ final class Kernel
*/ */
public static function boot(): self public static function boot(): self
{ {
foreach (self::$bootstrappers as $bootstrapper) { foreach (self::BOOTSTRAPPERS as $bootstrapper) {
// @phpstan-ignore-next-line
(new $bootstrapper())->__invoke(); (new $bootstrapper())->__invoke();
} }
@ -123,7 +122,7 @@ final class Kernel
} }
if ($result->hasTestErroredEvents()) { if ($result->hasTestErroredEvents()) {
$returnCode = self::EXCEPTION_EXIT; return self::EXCEPTION_EXIT;
} }
return $returnCode; return $returnCode;

View File

@ -32,7 +32,7 @@ final class PestDuskCommand extends DuskCommand
* *
* @return array<string> * @return array<string>
*/ */
protected function binary() protected function binary(): array
{ {
if ('phpdbg' === PHP_SAPI) { if ('phpdbg' === PHP_SAPI) {
return [PHP_BINARY, '-qrr', 'vendor/pestphp/pest/bin/pest']; return [PHP_BINARY, '-qrr', 'vendor/pestphp/pest/bin/pest'];

View File

@ -30,6 +30,11 @@ final class PestInstallCommand extends Command
*/ */
protected $description = 'Creates Pest resources in your current PHPUnit test suite'; protected $description = 'Creates Pest resources in your current PHPUnit test suite';
/**
* @var string
*/
private const STUBS = 'stubs/Laravel';
/** /**
* Execute the console command. * Execute the console command.
*/ */
@ -40,7 +45,6 @@ final class PestInstallCommand extends Command
/* @phpstan-ignore-next-line */ /* @phpstan-ignore-next-line */
$pest = base_path(testDirectory('Pest.php')); $pest = base_path(testDirectory('Pest.php'));
$stubs = 'stubs/Laravel';
if (File::exists($pest)) { if (File::exists($pest)) {
throw new InvalidConsoleArgument(sprintf('%s already exist', $pest)); throw new InvalidConsoleArgument(sprintf('%s already exist', $pest));
@ -48,7 +52,7 @@ final class PestInstallCommand extends Command
File::copy(implode(DIRECTORY_SEPARATOR, [ File::copy(implode(DIRECTORY_SEPARATOR, [
dirname(__DIR__, 3), dirname(__DIR__, 3),
$stubs, self::STUBS,
'Pest.php', 'Pest.php',
]), $pest); ]), $pest);

View File

@ -52,8 +52,8 @@ final class PestTestCommand extends Command
/* @phpstan-ignore-next-line */ /* @phpstan-ignore-next-line */
$target = base_path($relativePath); $target = base_path($relativePath);
if (! File::isDirectory(dirname($target))) { if (! File::isDirectory(dirname((string) $target))) {
File::makeDirectory(dirname($target), 0777, true, true); File::makeDirectory(dirname((string) $target), 0777, true, true);
} }
if (File::exists($target) && ! (bool) $this->option('force')) { if (File::exists($target) && ! (bool) $this->option('force')) {

View File

@ -51,9 +51,9 @@ final class Expectation
* value. Used on objects, it asserts that two * value. Used on objects, it asserts that two
* variables reference the same object. * variables reference the same object.
* *
* @return Expectation<TValue> * @return self<TValue>
*/ */
public function toBe(mixed $expected): Expectation public function toBe(mixed $expected): self
{ {
Assert::assertSame($expected, $this->value); Assert::assertSame($expected, $this->value);
@ -63,9 +63,9 @@ final class Expectation
/** /**
* Asserts that the value is empty. * Asserts that the value is empty.
* *
* @return Expectation<TValue> * @return self<TValue>
*/ */
public function toBeEmpty(): Expectation public function toBeEmpty(): self
{ {
Assert::assertEmpty($this->value); Assert::assertEmpty($this->value);
@ -75,9 +75,9 @@ final class Expectation
/** /**
* Asserts that the value is true. * Asserts that the value is true.
* *
* @return Expectation<TValue> * @return self<TValue>
*/ */
public function toBeTrue(): Expectation public function toBeTrue(): self
{ {
Assert::assertTrue($this->value); Assert::assertTrue($this->value);
@ -87,9 +87,9 @@ final class Expectation
/** /**
* Asserts that the value is truthy. * Asserts that the value is truthy.
* *
* @return Expectation<TValue> * @return self<TValue>
*/ */
public function toBeTruthy(): Expectation public function toBeTruthy(): self
{ {
Assert::assertTrue((bool) $this->value); Assert::assertTrue((bool) $this->value);
@ -99,9 +99,9 @@ final class Expectation
/** /**
* Asserts that the value is false. * Asserts that the value is false.
* *
* @return Expectation<TValue> * @return self<TValue>
*/ */
public function toBeFalse(): Expectation public function toBeFalse(): self
{ {
Assert::assertFalse($this->value); Assert::assertFalse($this->value);
@ -111,9 +111,9 @@ final class Expectation
/** /**
* Asserts that the value is falsy. * Asserts that the value is falsy.
* *
* @return Expectation<TValue> * @return self<TValue>
*/ */
public function toBeFalsy(): Expectation public function toBeFalsy(): self
{ {
Assert::assertFalse((bool) $this->value); Assert::assertFalse((bool) $this->value);
@ -123,9 +123,9 @@ final class Expectation
/** /**
* Asserts that the value is greater than $expected. * Asserts that the value is greater than $expected.
* *
* @return Expectation<TValue> * @return self<TValue>
*/ */
public function toBeGreaterThan(int|float $expected): Expectation public function toBeGreaterThan(int|float $expected): self
{ {
Assert::assertGreaterThan($expected, $this->value); Assert::assertGreaterThan($expected, $this->value);
@ -135,9 +135,9 @@ final class Expectation
/** /**
* Asserts that the value is greater than or equal to $expected. * Asserts that the value is greater than or equal to $expected.
* *
* @return Expectation<TValue> * @return self<TValue>
*/ */
public function toBeGreaterThanOrEqual(int|float $expected): Expectation public function toBeGreaterThanOrEqual(int|float $expected): self
{ {
Assert::assertGreaterThanOrEqual($expected, $this->value); Assert::assertGreaterThanOrEqual($expected, $this->value);
@ -147,9 +147,9 @@ final class Expectation
/** /**
* Asserts that the value is less than or equal to $expected. * Asserts that the value is less than or equal to $expected.
* *
* @return Expectation<TValue> * @return self<TValue>
*/ */
public function toBeLessThan(int|float $expected): Expectation public function toBeLessThan(int|float $expected): self
{ {
Assert::assertLessThan($expected, $this->value); Assert::assertLessThan($expected, $this->value);
@ -159,9 +159,9 @@ final class Expectation
/** /**
* Asserts that the value is less than $expected. * Asserts that the value is less than $expected.
* *
* @return Expectation<TValue> * @return self<TValue>
*/ */
public function toBeLessThanOrEqual(int|float $expected): Expectation public function toBeLessThanOrEqual(int|float $expected): self
{ {
Assert::assertLessThanOrEqual($expected, $this->value); Assert::assertLessThanOrEqual($expected, $this->value);
@ -171,9 +171,9 @@ final class Expectation
/** /**
* Asserts that $needle is an element of the value. * Asserts that $needle is an element of the value.
* *
* @return Expectation<TValue> * @return self<TValue>
*/ */
public function toContain(mixed ...$needles): Expectation public function toContain(mixed ...$needles): self
{ {
foreach ($needles as $needle) { foreach ($needles as $needle) {
if (is_string($this->value)) { if (is_string($this->value)) {
@ -194,9 +194,9 @@ final class Expectation
* Asserts that the value starts with $expected. * Asserts that the value starts with $expected.
* *
* @param non-empty-string $expected * @param non-empty-string $expected
*@return Expectation<TValue> *@return self<TValue>
*/ */
public function toStartWith(string $expected): Expectation public function toStartWith(string $expected): self
{ {
if (! is_string($this->value)) { if (! is_string($this->value)) {
InvalidExpectationValue::expected('string'); InvalidExpectationValue::expected('string');
@ -211,9 +211,9 @@ final class Expectation
* Asserts that the value ends with $expected. * Asserts that the value ends with $expected.
* *
* @param non-empty-string $expected * @param non-empty-string $expected
*@return Expectation<TValue> *@return self<TValue>
*/ */
public function toEndWith(string $expected): Expectation public function toEndWith(string $expected): self
{ {
if (! is_string($this->value)) { if (! is_string($this->value)) {
InvalidExpectationValue::expected('string'); InvalidExpectationValue::expected('string');
@ -227,9 +227,9 @@ final class Expectation
/** /**
* Asserts that $number matches value's Length. * Asserts that $number matches value's Length.
* *
* @return Expectation<TValue> * @return self<TValue>
*/ */
public function toHaveLength(int $number): Expectation public function toHaveLength(int $number): self
{ {
if (is_string($this->value)) { if (is_string($this->value)) {
Assert::assertEquals($number, mb_strlen($this->value)); Assert::assertEquals($number, mb_strlen($this->value));
@ -242,11 +242,7 @@ final class Expectation
} }
if (is_object($this->value)) { if (is_object($this->value)) {
if (method_exists($this->value, 'toArray')) { $array = method_exists($this->value, 'toArray') ? $this->value->toArray() : (array) $this->value;
$array = $this->value->toArray();
} else {
$array = (array) $this->value;
}
Assert::assertCount($number, $array); Assert::assertCount($number, $array);
@ -259,9 +255,9 @@ final class Expectation
/** /**
* Asserts that $count matches the number of elements of the value. * Asserts that $count matches the number of elements of the value.
* *
* @return Expectation<TValue> * @return self<TValue>
*/ */
public function toHaveCount(int $count): Expectation public function toHaveCount(int $count): self
{ {
if (! is_countable($this->value) && ! is_iterable($this->value)) { if (! is_countable($this->value) && ! is_iterable($this->value)) {
InvalidExpectationValue::expected('string'); InvalidExpectationValue::expected('string');
@ -275,9 +271,9 @@ final class Expectation
/** /**
* Asserts that the value contains the property $name. * Asserts that the value contains the property $name.
* *
* @return Expectation<TValue> * @return self<TValue>
*/ */
public function toHaveProperty(string $name, mixed $value = null): Expectation public function toHaveProperty(string $name, mixed $value = null): self
{ {
$this->toBeObject(); $this->toBeObject();
@ -296,9 +292,9 @@ final class Expectation
* Asserts that the value contains the provided properties $names. * Asserts that the value contains the provided properties $names.
* *
* @param iterable<array-key, string> $names * @param iterable<array-key, string> $names
*@return Expectation<TValue> *@return self<TValue>
*/ */
public function toHaveProperties(iterable $names): Expectation public function toHaveProperties(iterable $names): self
{ {
foreach ($names as $name) { foreach ($names as $name) {
$this->toHaveProperty($name); $this->toHaveProperty($name);
@ -310,9 +306,9 @@ final class Expectation
/** /**
* Asserts that two variables have the same value. * Asserts that two variables have the same value.
* *
* @return Expectation<TValue> * @return self<TValue>
*/ */
public function toEqual(mixed $expected): Expectation public function toEqual(mixed $expected): self
{ {
Assert::assertEquals($expected, $this->value); Assert::assertEquals($expected, $this->value);
@ -328,9 +324,9 @@ final class Expectation
* are objects, each object is converted to an array containing all * are objects, each object is converted to an array containing all
* private, protected and public attributes. * private, protected and public attributes.
* *
* @return Expectation<TValue> * @return self<TValue>
*/ */
public function toEqualCanonicalizing(mixed $expected): Expectation public function toEqualCanonicalizing(mixed $expected): self
{ {
Assert::assertEqualsCanonicalizing($expected, $this->value); Assert::assertEqualsCanonicalizing($expected, $this->value);
@ -341,9 +337,9 @@ final class Expectation
* Asserts that the absolute difference between the value and $expected * Asserts that the absolute difference between the value and $expected
* is lower than $delta. * is lower than $delta.
* *
* @return Expectation<TValue> * @return self<TValue>
*/ */
public function toEqualWithDelta(mixed $expected, float $delta): Expectation public function toEqualWithDelta(mixed $expected, float $delta): self
{ {
Assert::assertEqualsWithDelta($expected, $this->value, $delta); Assert::assertEqualsWithDelta($expected, $this->value, $delta);
@ -354,9 +350,9 @@ final class Expectation
* Asserts that the value is one of the given values. * Asserts that the value is one of the given values.
* *
* @param iterable<int|string, mixed> $values * @param iterable<int|string, mixed> $values
* @return Expectation<TValue> * @return self<TValue>
*/ */
public function toBeIn(iterable $values): Expectation public function toBeIn(iterable $values): self
{ {
Assert::assertContains($this->value, $values); Assert::assertContains($this->value, $values);
@ -366,9 +362,9 @@ final class Expectation
/** /**
* Asserts that the value is infinite. * Asserts that the value is infinite.
* *
* @return Expectation<TValue> * @return self<TValue>
*/ */
public function toBeInfinite(): Expectation public function toBeInfinite(): self
{ {
Assert::assertInfinite($this->value); Assert::assertInfinite($this->value);
@ -379,9 +375,9 @@ final class Expectation
* Asserts that the value is an instance of $class. * Asserts that the value is an instance of $class.
* *
* @param class-string $class * @param class-string $class
* @return Expectation<TValue> * @return self<TValue>
*/ */
public function toBeInstanceOf(string $class): Expectation public function toBeInstanceOf(string $class): self
{ {
Assert::assertInstanceOf($class, $this->value); Assert::assertInstanceOf($class, $this->value);
@ -391,9 +387,9 @@ final class Expectation
/** /**
* Asserts that the value is an array. * Asserts that the value is an array.
* *
* @return Expectation<TValue> * @return self<TValue>
*/ */
public function toBeArray(): Expectation public function toBeArray(): self
{ {
Assert::assertIsArray($this->value); Assert::assertIsArray($this->value);
@ -403,9 +399,9 @@ final class Expectation
/** /**
* Asserts that the value is of type bool. * Asserts that the value is of type bool.
* *
* @return Expectation<TValue> * @return self<TValue>
*/ */
public function toBeBool(): Expectation public function toBeBool(): self
{ {
Assert::assertIsBool($this->value); Assert::assertIsBool($this->value);
@ -415,9 +411,9 @@ final class Expectation
/** /**
* Asserts that the value is of type callable. * Asserts that the value is of type callable.
* *
* @return Expectation<TValue> * @return self<TValue>
*/ */
public function toBeCallable(): Expectation public function toBeCallable(): self
{ {
Assert::assertIsCallable($this->value); Assert::assertIsCallable($this->value);
@ -427,9 +423,9 @@ final class Expectation
/** /**
* Asserts that the value is of type float. * Asserts that the value is of type float.
* *
* @return Expectation<TValue> * @return self<TValue>
*/ */
public function toBeFloat(): Expectation public function toBeFloat(): self
{ {
Assert::assertIsFloat($this->value); Assert::assertIsFloat($this->value);
@ -439,9 +435,9 @@ final class Expectation
/** /**
* Asserts that the value is of type int. * Asserts that the value is of type int.
* *
* @return Expectation<TValue> * @return self<TValue>
*/ */
public function toBeInt(): Expectation public function toBeInt(): self
{ {
Assert::assertIsInt($this->value); Assert::assertIsInt($this->value);
@ -451,9 +447,9 @@ final class Expectation
/** /**
* Asserts that the value is of type iterable. * Asserts that the value is of type iterable.
* *
* @return Expectation<TValue> * @return self<TValue>
*/ */
public function toBeIterable(): Expectation public function toBeIterable(): self
{ {
Assert::assertIsIterable($this->value); Assert::assertIsIterable($this->value);
@ -463,9 +459,9 @@ final class Expectation
/** /**
* Asserts that the value is of type numeric. * Asserts that the value is of type numeric.
* *
* @return Expectation<TValue> * @return self<TValue>
*/ */
public function toBeNumeric(): Expectation public function toBeNumeric(): self
{ {
Assert::assertIsNumeric($this->value); Assert::assertIsNumeric($this->value);
@ -475,9 +471,9 @@ final class Expectation
/** /**
* Asserts that the value is of type object. * Asserts that the value is of type object.
* *
* @return Expectation<TValue> * @return self<TValue>
*/ */
public function toBeObject(): Expectation public function toBeObject(): self
{ {
Assert::assertIsObject($this->value); Assert::assertIsObject($this->value);
@ -487,9 +483,9 @@ final class Expectation
/** /**
* Asserts that the value is of type resource. * Asserts that the value is of type resource.
* *
* @return Expectation<TValue> * @return self<TValue>
*/ */
public function toBeResource(): Expectation public function toBeResource(): self
{ {
Assert::assertIsResource($this->value); Assert::assertIsResource($this->value);
@ -499,9 +495,9 @@ final class Expectation
/** /**
* Asserts that the value is of type scalar. * Asserts that the value is of type scalar.
* *
* @return Expectation<TValue> * @return self<TValue>
*/ */
public function toBeScalar(): Expectation public function toBeScalar(): self
{ {
Assert::assertIsScalar($this->value); Assert::assertIsScalar($this->value);
@ -511,9 +507,9 @@ final class Expectation
/** /**
* Asserts that the value is of type string. * Asserts that the value is of type string.
* *
* @return Expectation<TValue> * @return self<TValue>
*/ */
public function toBeString(): Expectation public function toBeString(): self
{ {
Assert::assertIsString($this->value); Assert::assertIsString($this->value);
@ -523,9 +519,9 @@ final class Expectation
/** /**
* Asserts that the value is a JSON string. * Asserts that the value is a JSON string.
* *
* @return Expectation<TValue> * @return self<TValue>
*/ */
public function toBeJson(): Expectation public function toBeJson(): self
{ {
Assert::assertIsString($this->value); Assert::assertIsString($this->value);
@ -538,9 +534,9 @@ final class Expectation
/** /**
* Asserts that the value is NAN. * Asserts that the value is NAN.
* *
* @return Expectation<TValue> * @return self<TValue>
*/ */
public function toBeNan(): Expectation public function toBeNan(): self
{ {
Assert::assertNan($this->value); Assert::assertNan($this->value);
@ -550,9 +546,9 @@ final class Expectation
/** /**
* Asserts that the value is null. * Asserts that the value is null.
* *
* @return Expectation<TValue> * @return self<TValue>
*/ */
public function toBeNull(): Expectation public function toBeNull(): self
{ {
Assert::assertNull($this->value); Assert::assertNull($this->value);
@ -562,9 +558,9 @@ final class Expectation
/** /**
* Asserts that the value array has the provided $key. * Asserts that the value array has the provided $key.
* *
* @return Expectation<TValue> * @return self<TValue>
*/ */
public function toHaveKey(string|int $key, mixed $value = null): Expectation public function toHaveKey(string|int $key, mixed $value = null): self
{ {
if (is_object($this->value) && method_exists($this->value, 'toArray')) { if (is_object($this->value) && method_exists($this->value, 'toArray')) {
$array = $this->value->toArray(); $array = $this->value->toArray();
@ -591,9 +587,9 @@ final class Expectation
* Asserts that the value array has the provided $keys. * Asserts that the value array has the provided $keys.
* *
* @param array<int, int|string|array<int-string, mixed>> $keys * @param array<int, int|string|array<int-string, mixed>> $keys
* @return Expectation<TValue> * @return self<TValue>
*/ */
public function toHaveKeys(array $keys): Expectation public function toHaveKeys(array $keys): self
{ {
foreach ($keys as $k => $key) { foreach ($keys as $k => $key) {
if (is_array($key)) { if (is_array($key)) {
@ -609,9 +605,9 @@ final class Expectation
/** /**
* Asserts that the value is a directory. * Asserts that the value is a directory.
* *
* @return Expectation<TValue> * @return self<TValue>
*/ */
public function toBeDirectory(): Expectation public function toBeDirectory(): self
{ {
if (! is_string($this->value)) { if (! is_string($this->value)) {
InvalidExpectationValue::expected('string'); InvalidExpectationValue::expected('string');
@ -625,9 +621,9 @@ final class Expectation
/** /**
* Asserts that the value is a directory and is readable. * Asserts that the value is a directory and is readable.
* *
* @return Expectation<TValue> * @return self<TValue>
*/ */
public function toBeReadableDirectory(): Expectation public function toBeReadableDirectory(): self
{ {
if (! is_string($this->value)) { if (! is_string($this->value)) {
InvalidExpectationValue::expected('string'); InvalidExpectationValue::expected('string');
@ -641,9 +637,9 @@ final class Expectation
/** /**
* Asserts that the value is a directory and is writable. * Asserts that the value is a directory and is writable.
* *
* @return Expectation<TValue> * @return self<TValue>
*/ */
public function toBeWritableDirectory(): Expectation public function toBeWritableDirectory(): self
{ {
if (! is_string($this->value)) { if (! is_string($this->value)) {
InvalidExpectationValue::expected('string'); InvalidExpectationValue::expected('string');
@ -657,9 +653,9 @@ final class Expectation
/** /**
* Asserts that the value is a file. * Asserts that the value is a file.
* *
* @return Expectation<TValue> * @return self<TValue>
*/ */
public function toBeFile(): Expectation public function toBeFile(): self
{ {
if (! is_string($this->value)) { if (! is_string($this->value)) {
InvalidExpectationValue::expected('string'); InvalidExpectationValue::expected('string');
@ -673,9 +669,9 @@ final class Expectation
/** /**
* Asserts that the value is a file and is readable. * Asserts that the value is a file and is readable.
* *
* @return Expectation<TValue> * @return self<TValue>
*/ */
public function toBeReadableFile(): Expectation public function toBeReadableFile(): self
{ {
if (! is_string($this->value)) { if (! is_string($this->value)) {
InvalidExpectationValue::expected('string'); InvalidExpectationValue::expected('string');
@ -689,9 +685,9 @@ final class Expectation
/** /**
* Asserts that the value is a file and is writable. * Asserts that the value is a file and is writable.
* *
* @return Expectation<TValue> * @return self<TValue>
*/ */
public function toBeWritableFile(): Expectation public function toBeWritableFile(): self
{ {
if (! is_string($this->value)) { if (! is_string($this->value)) {
InvalidExpectationValue::expected('string'); InvalidExpectationValue::expected('string');
@ -705,9 +701,9 @@ final class Expectation
* Asserts that the value array matches the given array subset. * Asserts that the value array matches the given array subset.
* *
* @param iterable<int|string, mixed> $array * @param iterable<int|string, mixed> $array
* @return Expectation<TValue> * @return self<TValue>
*/ */
public function toMatchArray(iterable $array): Expectation public function toMatchArray(iterable $array): self
{ {
if (is_object($this->value) && method_exists($this->value, 'toArray')) { if (is_object($this->value) && method_exists($this->value, 'toArray')) {
$valueAsArray = $this->value->toArray(); $valueAsArray = $this->value->toArray();
@ -737,9 +733,9 @@ final class Expectation
* of the properties of an given object. * of the properties of an given object.
* *
* @param iterable<string, mixed> $object * @param iterable<string, mixed> $object
* @return Expectation<TValue> * @return self<TValue>
*/ */
public function toMatchObject(iterable $object): Expectation public function toMatchObject(iterable $object): self
{ {
foreach ((array) $object as $property => $value) { foreach ((array) $object as $property => $value) {
if (! is_object($this->value) && ! is_string($this->value)) { if (! is_object($this->value) && ! is_string($this->value)) {
@ -767,9 +763,9 @@ final class Expectation
/** /**
* Asserts that the value matches a regular expression. * Asserts that the value matches a regular expression.
* *
* @return Expectation<TValue> * @return self<TValue>
*/ */
public function toMatch(string $expression): Expectation public function toMatch(string $expression): self
{ {
if (! is_string($this->value)) { if (! is_string($this->value)) {
InvalidExpectationValue::expected('string'); InvalidExpectationValue::expected('string');
@ -782,9 +778,9 @@ final class Expectation
/** /**
* Asserts that the value matches a constraint. * Asserts that the value matches a constraint.
* *
* @return Expectation<TValue> * @return self<TValue>
*/ */
public function toMatchConstraint(Constraint $constraint): Expectation public function toMatchConstraint(Constraint $constraint): self
{ {
Assert::assertThat($this->value, $constraint); Assert::assertThat($this->value, $constraint);
@ -793,9 +789,9 @@ final class Expectation
/** /**
* @param class-string $class * @param class-string $class
* @return Expectation<TValue> * @return self<TValue>
*/ */
public function toContainOnlyInstancesOf(string $class): Expectation public function toContainOnlyInstancesOf(string $class): self
{ {
if (! is_iterable($this->value)) { if (! is_iterable($this->value)) {
InvalidExpectationValue::expected('iterable'); InvalidExpectationValue::expected('iterable');
@ -810,9 +806,9 @@ final class Expectation
* Asserts that executing value throws an exception. * Asserts that executing value throws an exception.
* *
* @param (Closure(Throwable): mixed)|string $exception * @param (Closure(Throwable): mixed)|string $exception
* @return Expectation<TValue> * @return self<TValue>
*/ */
public function toThrow(callable|string $exception, string $exceptionMessage = null): Expectation public function toThrow(callable|string $exception, string $exceptionMessage = null): self
{ {
$callback = NullClosure::create(); $callback = NullClosure::create();

View File

@ -19,19 +19,19 @@ final class AfterEachCall
/** /**
* The "afterEach" closure. * The "afterEach" closure.
*/ */
private Closure $closure; private readonly Closure $closure;
/** /**
* The calls that should be proxied. * The calls that should be proxied.
*/ */
private HigherOrderMessageCollection $proxies; private readonly HigherOrderMessageCollection $proxies;
/** /**
* Creates a new Pending Call. * Creates a new Pending Call.
*/ */
public function __construct( public function __construct(
private TestSuite $testSuite, private readonly TestSuite $testSuite,
private string $filename, private readonly string $filename,
Closure $closure = null Closure $closure = null
) { ) {
$this->closure = $closure instanceof Closure ? $closure : NullClosure::create(); $this->closure = $closure instanceof Closure ? $closure : NullClosure::create();

View File

@ -19,19 +19,19 @@ final class BeforeEachCall
/** /**
* Holds the before each closure. * Holds the before each closure.
*/ */
private \Closure $closure; private readonly \Closure $closure;
/** /**
* The calls that should be proxied. * The calls that should be proxied.
*/ */
private HigherOrderMessageCollection $proxies; private readonly HigherOrderMessageCollection $proxies;
/** /**
* Creates a new Pending Call. * Creates a new Pending Call.
*/ */
public function __construct( public function __construct(
private TestSuite $testSuite, private readonly TestSuite $testSuite,
private string $filename, private readonly string $filename,
Closure $closure = null Closure $closure = null
) { ) {
$this->closure = $closure instanceof Closure ? $closure : NullClosure::create(); $this->closure = $closure instanceof Closure ? $closure : NullClosure::create();

View File

@ -26,18 +26,18 @@ final class TestCall
/** /**
* The Test Case Factory. * The Test Case Factory.
*/ */
private TestCaseMethodFactory $testCaseMethod; private readonly TestCaseMethodFactory $testCaseMethod;
/** /**
* If test call is descriptionLess. * If test call is descriptionLess.
*/ */
private bool $descriptionLess; private readonly bool $descriptionLess;
/** /**
* Creates a new Pending Call. * Creates a new Pending Call.
*/ */
public function __construct( public function __construct(
private TestSuite $testSuite, private readonly TestSuite $testSuite,
string $filename, string $filename,
string $description = null, string $description = null,
Closure $closure = null Closure $closure = null
@ -49,7 +49,7 @@ final class TestCall
/** /**
* Asserts that the test throws the given `$exceptionClass` when called. * Asserts that the test throws the given `$exceptionClass` when called.
*/ */
public function throws(string|int $exception, string $exceptionMessage = null, int $exceptionCode = null): TestCall public function throws(string|int $exception, string $exceptionMessage = null, int $exceptionCode = null): self
{ {
if (is_int($exception)) { if (is_int($exception)) {
$exceptionCode = $exception; $exceptionCode = $exception;
@ -81,13 +81,11 @@ final class TestCall
* *
* @param (callable(): bool)|bool $condition * @param (callable(): bool)|bool $condition
*/ */
public function throwsIf(callable|bool $condition, string|int $exception, string $exceptionMessage = null, int $exceptionCode = null): TestCall public function throwsIf(callable|bool $condition, string|int $exception, string $exceptionMessage = null, int $exceptionCode = null): self
{ {
$condition = is_callable($condition) $condition = is_callable($condition)
? $condition ? $condition
: static function () use ($condition): bool { : static fn (): bool => $condition;
return $condition;
};
if ($condition()) { if ($condition()) {
return $this->throws($exception, $exceptionMessage, $exceptionCode); return $this->throws($exception, $exceptionMessage, $exceptionCode);
@ -102,7 +100,7 @@ final class TestCall
* *
* @param array<\Closure|iterable<int|string, mixed>|string> $data * @param array<\Closure|iterable<int|string, mixed>|string> $data
*/ */
public function with(Closure|iterable|string ...$data): TestCall public function with(Closure|iterable|string ...$data): self
{ {
foreach ($data as $dataset) { foreach ($data as $dataset) {
$this->testCaseMethod->datasets[] = $dataset; $this->testCaseMethod->datasets[] = $dataset;
@ -114,7 +112,7 @@ final class TestCall
/** /**
* Sets the test depends. * Sets the test depends.
*/ */
public function depends(string ...$depends): TestCall public function depends(string ...$depends): self
{ {
foreach ($depends as $depend) { foreach ($depends as $depend) {
$this->testCaseMethod->depends[] = $depend; $this->testCaseMethod->depends[] = $depend;
@ -126,7 +124,7 @@ final class TestCall
/** /**
* Makes the test suite only this test case. * Makes the test suite only this test case.
*/ */
public function only(): TestCall public function only(): self
{ {
$this->testCaseMethod->only = true; $this->testCaseMethod->only = true;
@ -136,7 +134,7 @@ final class TestCall
/** /**
* Sets the test group(s). * Sets the test group(s).
*/ */
public function group(string ...$groups): TestCall public function group(string ...$groups): self
{ {
foreach ($groups as $group) { foreach ($groups as $group) {
$this->testCaseMethod->groups[] = $group; $this->testCaseMethod->groups[] = $group;
@ -148,7 +146,7 @@ final class TestCall
/** /**
* Skips the current test. * Skips the current test.
*/ */
public function skip(Closure|bool|string $conditionOrMessage = true, string $message = ''): TestCall public function skip(Closure|bool|string $conditionOrMessage = true, string $message = ''): self
{ {
$condition = is_string($conditionOrMessage) $condition = is_string($conditionOrMessage)
? NullClosure::create() ? NullClosure::create()
@ -175,7 +173,7 @@ final class TestCall
/** /**
* Sets the covered classes or methods. * Sets the covered classes or methods.
*/ */
public function covers(string ...$classesOrFunctions): TestCall public function covers(string ...$classesOrFunctions): self
{ {
foreach ($classesOrFunctions as $classOrFunction) { foreach ($classesOrFunctions as $classOrFunction) {
$isClass = class_exists($classOrFunction); $isClass = class_exists($classOrFunction);
@ -198,7 +196,7 @@ final class TestCall
/** /**
* Sets the covered classes. * Sets the covered classes.
*/ */
public function coversClass(string ...$classes): TestCall public function coversClass(string ...$classes): self
{ {
foreach ($classes as $class) { foreach ($classes as $class) {
$this->testCaseMethod->covers[] = new CoversClass($class); $this->testCaseMethod->covers[] = new CoversClass($class);
@ -210,7 +208,7 @@ final class TestCall
/** /**
* Sets the covered functions. * Sets the covered functions.
*/ */
public function coversFunction(string ...$functions): TestCall public function coversFunction(string ...$functions): self
{ {
foreach ($functions as $function) { foreach ($functions as $function) {
$this->testCaseMethod->covers[] = new CoversFunction($function); $this->testCaseMethod->covers[] = new CoversFunction($function);
@ -222,7 +220,7 @@ final class TestCall
/** /**
* Sets that the current test covers nothing. * Sets that the current test covers nothing.
*/ */
public function coversNothing(): TestCall public function coversNothing(): self
{ {
$this->testCaseMethod->covers = [new CoversNothing()]; $this->testCaseMethod->covers = [new CoversNothing()];
@ -234,7 +232,7 @@ final class TestCall
* and its purpose is simply to check whether the given code can * and its purpose is simply to check whether the given code can
* be executed without throwing exceptions. * be executed without throwing exceptions.
*/ */
public function throwsNoExceptions(): TestCall public function throwsNoExceptions(): self
{ {
$this->testCaseMethod->proxies->add(Backtrace::file(), Backtrace::line(), 'expectNotToPerformAssertions', []); $this->testCaseMethod->proxies->add(Backtrace::file(), Backtrace::line(), 'expectNotToPerformAssertions', []);

View File

@ -46,8 +46,8 @@ final class UsesCall
* @param array<int, string> $classAndTraits * @param array<int, string> $classAndTraits
*/ */
public function __construct( public function __construct(
private string $filename, private readonly string $filename,
private array $classAndTraits private readonly array $classAndTraits
) { ) {
$this->targets = [$filename]; $this->targets = [$filename];
} }
@ -87,7 +87,7 @@ final class UsesCall
/** /**
* Sets the test group(s). * Sets the test group(s).
*/ */
public function group(string ...$groups): UsesCall public function group(string ...$groups): self
{ {
$this->groups = array_values($groups); $this->groups = array_values($groups);
@ -97,7 +97,7 @@ final class UsesCall
/** /**
* Sets the global beforeAll test hook. * Sets the global beforeAll test hook.
*/ */
public function beforeAll(Closure $hook): UsesCall public function beforeAll(Closure $hook): self
{ {
$this->hooks[0] = $hook; $this->hooks[0] = $hook;
@ -107,7 +107,7 @@ final class UsesCall
/** /**
* Sets the global beforeEach test hook. * Sets the global beforeEach test hook.
*/ */
public function beforeEach(Closure $hook): UsesCall public function beforeEach(Closure $hook): self
{ {
$this->hooks[1] = $hook; $this->hooks[1] = $hook;
@ -117,7 +117,7 @@ final class UsesCall
/** /**
* Sets the global afterEach test hook. * Sets the global afterEach test hook.
*/ */
public function afterEach(Closure $hook): UsesCall public function afterEach(Closure $hook): self
{ {
$this->hooks[2] = $hook; $this->hooks[2] = $hook;
@ -127,7 +127,7 @@ final class UsesCall
/** /**
* Sets the global afterAll test hook. * Sets the global afterAll test hook.
*/ */
public function afterAll(Closure $hook): UsesCall public function afterAll(Closure $hook): self
{ {
$this->hooks[3] = $hook; $this->hooks[3] = $hook;

View File

@ -40,7 +40,7 @@ final class Coverage implements AddsOutput, HandlesArguments
/** /**
* Creates a new Plugin instance. * Creates a new Plugin instance.
*/ */
public function __construct(private OutputInterface $output) public function __construct(private readonly OutputInterface $output)
{ {
// .. // ..
} }
@ -52,7 +52,10 @@ final class Coverage implements AddsOutput, HandlesArguments
{ {
$arguments = [...[''], ...array_values(array_filter($originals, function ($original): bool { $arguments = [...[''], ...array_values(array_filter($originals, function ($original): bool {
foreach ([self::COVERAGE_OPTION, self::MIN_OPTION] as $option) { foreach ([self::COVERAGE_OPTION, self::MIN_OPTION] as $option) {
if ($original === sprintf('--%s', $option) || Str::startsWith($original, sprintf('--%s=', $option))) { if ($original === sprintf('--%s', $option)) {
return true;
}
if (Str::startsWith($original, sprintf('--%s=', $option))) {
return true; return true;
} }
} }

View File

@ -32,8 +32,8 @@ final class Init implements HandlesArguments
* Creates a new Plugin instance. * Creates a new Plugin instance.
*/ */
public function __construct( public function __construct(
private TestSuite $testSuite, private readonly TestSuite $testSuite,
private OutputInterface $output private readonly OutputInterface $output
) { ) {
// .. // ..
} }
@ -43,10 +43,12 @@ final class Init implements HandlesArguments
*/ */
public function handleArguments(array $arguments): array public function handleArguments(array $arguments): array
{ {
if (! array_key_exists(1, $arguments) || $arguments[1] !== self::INIT_OPTION) { if (! array_key_exists(1, $arguments)) {
return $arguments;
}
if ($arguments[1] !== self::INIT_OPTION) {
return $arguments; return $arguments;
} }
unset($arguments[1]); unset($arguments[1]);
$this->init(); $this->init();

View File

@ -24,7 +24,7 @@ final class Memory implements AddsOutput, HandlesArguments
* Creates a new Plugin instance. * Creates a new Plugin instance.
*/ */
public function __construct( public function __construct(
private OutputInterface $output private readonly OutputInterface $output
) { ) {
// .. // ..
} }
@ -47,7 +47,7 @@ final class Memory implements AddsOutput, HandlesArguments
if ($this->enabled) { if ($this->enabled) {
$this->output->writeln(sprintf( $this->output->writeln(sprintf(
' <fg=gray;options=bold>Memory:</> <fg=default>%s MB</>', ' <fg=gray;options=bold>Memory:</> <fg=default>%s MB</>',
round(memory_get_usage(true) / pow(1000, 2), 3) round(memory_get_usage(true) / 1000 ** 2, 3)
)); ));
} }

View File

@ -19,7 +19,7 @@ final class Version implements HandlesArguments
* Creates a new Plugin instance. * Creates a new Plugin instance.
*/ */
public function __construct( public function __construct(
private OutputInterface $output private readonly OutputInterface $output
) { ) {
// .. // ..
} }

View File

@ -61,11 +61,11 @@ final class DatasetsRepository
} }
/** /**
* @return Closure|iterable<int|string, mixed>|never * @return Closure|array<int|string, mixed>|never
* *
* @throws ShouldNotHappen * @throws ShouldNotHappen
*/ */
public static function get(string $filename, string $description): Closure|iterable public static function get(string $filename, string $description)
{ {
$dataset = self::$withs[$filename.'>>>'.$description]; $dataset = self::$withs[$filename.'>>>'.$description];

View File

@ -14,7 +14,7 @@ final class TempRepository
/** /**
* Creates a new Temp Repository instance. * Creates a new Temp Repository instance.
*/ */
public function __construct(private string $filename) public function __construct(private readonly string $filename)
{ {
// .. // ..
} }
@ -24,10 +24,7 @@ final class TempRepository
*/ */
public function add(string $element): void public function add(string $element): void
{ {
$this->save(array_merge( $this->save([...$this->all(), ...[$element]]);
$this->all(),
[$element]
));
} }
/** /**
@ -59,7 +56,7 @@ final class TempRepository
assert(is_string($contents)); assert(is_string($contents));
$all = json_decode($contents, true); $all = json_decode($contents, true, 512, JSON_THROW_ON_ERROR);
return is_array($all) ? $all : []; return is_array($all) ? $all : [];
} }
@ -71,7 +68,7 @@ final class TempRepository
*/ */
private function save(array $elements): void private function save(array $elements): void
{ {
$contents = json_encode($elements); $contents = json_encode($elements, JSON_THROW_ON_ERROR);
file_put_contents(self::FOLDER.'/'.$this->filename.'.json', $contents); file_put_contents(self::FOLDER.'/'.$this->filename.'.json', $contents);
} }

View File

@ -42,9 +42,9 @@ final class TestRepository
*/ */
public function getFilenames(): array public function getFilenames(): array
{ {
$testCases = array_filter($this->testCases, static fn (TestCaseFactory $testCase) => count($testCase->methodsUsingOnly()) > 0); $testCases = array_filter($this->testCases, static fn (TestCaseFactory $testCase) => $testCase->methodsUsingOnly() !== []);
if (count($testCases) === 0) { if ($testCases === []) {
$testCases = $this->testCases; $testCases = $this->testCases;
} }
@ -62,9 +62,13 @@ final class TestRepository
public function use(array $classOrTraits, array $groups, array $paths, array $hooks): void public function use(array $classOrTraits, array $groups, array $paths, array $hooks): void
{ {
foreach ($classOrTraits as $classOrTrait) { foreach ($classOrTraits as $classOrTrait) {
if (! class_exists($classOrTrait) && ! trait_exists($classOrTrait)) { if (class_exists($classOrTrait)) {
throw new TestCaseClassOrTraitNotFound($classOrTrait); continue;
} }
if (trait_exists($classOrTrait)) {
continue;
}
throw new TestCaseClassOrTraitNotFound($classOrTrait);
} }
foreach ($paths as $path) { foreach ($paths as $path) {
@ -137,7 +141,7 @@ final class TestRepository
} }
foreach ($testCase->methods as $method) { foreach ($testCase->methods as $method) {
$method->groups = array_merge($groups, $method->groups); $method->groups = [...$groups, ...$method->groups];
} }
$testCase->factoryProxies->add($testCase->filename, 0, '__addBeforeAll', [$hooks[0] ?? null]); $testCase->factoryProxies->add($testCase->filename, 0, '__addBeforeAll', [$hooks[0] ?? null]);

View File

@ -72,7 +72,7 @@ final class Arr
$results = []; $results = [];
foreach ($array as $key => $value) { foreach ($array as $key => $value) {
if (is_array($value) && count($value) > 0) { if (is_array($value) && $value !== []) {
$results = array_merge($results, static::dot($value, $prepend.$key.'.')); $results = array_merge($results, static::dot($value, $prepend.$key.'.'));
} else { } else {
$results[$prepend.$value] = $value; $results[$prepend.$value] = $value;

View File

@ -15,7 +15,6 @@ final class Closure
/** /**
* Binds the given closure to the given "this". * Binds the given closure to the given "this".
* *
* @return BaseClosure|never
* *
* @throws ShouldNotHappen * @throws ShouldNotHappen
*/ */

View File

@ -26,7 +26,7 @@ final class Container
public static function getInstance(): self public static function getInstance(): self
{ {
if (static::$instance === null) { if (static::$instance === null) {
static::$instance = new static(); static::$instance = new self();
} }
return static::$instance; return static::$instance;
@ -49,10 +49,8 @@ final class Container
/** /**
* Adds the given instance to the container. * Adds the given instance to the container.
*
* @param mixed $instance
*/ */
public function add(string $id, $instance): void public function add(string $id, mixed $instance): void
{ {
$this->instances[$id] = $instance; $this->instances[$id] = $instance;
} }

View File

@ -153,7 +153,7 @@ final class Coverage
$shouldBeNewLine = true; $shouldBeNewLine = true;
$eachLine = function (array $array, array $tests, int $line) use (&$shouldBeNewLine): array { $eachLine = function (array $array, array $tests, int $line) use (&$shouldBeNewLine): array {
if (count($tests) > 0) { if ($tests !== []) {
$shouldBeNewLine = true; $shouldBeNewLine = true;
return $array; return $array;
@ -168,8 +168,8 @@ final class Coverage
$lastKey = count($array) - 1; $lastKey = count($array) - 1;
if (array_key_exists($lastKey, $array) && str_contains($array[$lastKey], '..')) { if (array_key_exists($lastKey, $array) && str_contains((string) $array[$lastKey], '..')) {
[$from] = explode('..', $array[$lastKey]); [$from] = explode('..', (string) $array[$lastKey]);
$array[$lastKey] = $line > $from ? sprintf('%s..%s', $from, $line) : sprintf('%s..%s', $line, $from); $array[$lastKey] = $line > $from ? sprintf('%s..%s', $from, $line) : sprintf('%s..%s', $line, $from);
return $array; return $array;

View File

@ -25,17 +25,12 @@ final class ExpectationPipeline
*/ */
private array $passables; private array $passables;
/**
* The expectation closure.
*/
private Closure $closure;
/** /**
* Creates a new instance of Expectation Pipeline. * Creates a new instance of Expectation Pipeline.
*/ */
public function __construct(Closure $closure) public function __construct(
{ private readonly Closure $closure
$this->closure = $closure; ) {
} }
/** /**
@ -89,10 +84,6 @@ final class ExpectationPipeline
*/ */
public function carry(): Closure public function carry(): Closure
{ {
return function ($stack, $pipe): Closure { return fn ($stack, $pipe): Closure => fn () => $pipe($stack, ...$this->passables);
return function () use ($stack, $pipe) {
return $pipe($stack, ...$this->passables);
};
};
} }
} }

View File

@ -15,7 +15,7 @@ final class HigherOrderCallables
/** /**
* Creates a new Higher Order Callables instances. * Creates a new Higher Order Callables instances.
*/ */
public function __construct(private object $target) public function __construct(private readonly object $target)
{ {
// .. // ..
} }
@ -44,7 +44,7 @@ final class HigherOrderCallables
* @param callable|TValue $value * @param callable|TValue $value
* @return Expectation<(callable(): mixed)|TValue> * @return Expectation<(callable(): mixed)|TValue>
*/ */
public function and(mixed $value) public function and(mixed $value): Expectation
{ {
return $this->expect($value); return $this->expect($value);
} }

View File

@ -25,7 +25,7 @@ final class HigherOrderMessage
/** /**
* Creates a new higher order message. * Creates a new higher order message.
* *
* @param array<int, mixed> $arguments * @param array<int, mixed>|null $arguments
*/ */
public function __construct( public function __construct(
public string $filename, public string $filename,
@ -97,7 +97,7 @@ final class HigherOrderMessage
private static function getUndefinedMethodMessage(object $target, string $methodName): string private static function getUndefinedMethodMessage(object $target, string $methodName): string
{ {
if (\PHP_MAJOR_VERSION >= 8) { if (\PHP_MAJOR_VERSION >= 8) {
return sprintf(sprintf(self::UNDEFINED_METHOD, sprintf('%s::%s()', $target::class, $methodName))); return sprintf(self::UNDEFINED_METHOD, sprintf('%s::%s()', $target::class, $methodName));
} }
return sprintf(self::UNDEFINED_METHOD, $methodName); return sprintf(self::UNDEFINED_METHOD, $methodName);

View File

@ -26,10 +26,8 @@ final class HigherOrderTapProxy
/** /**
* Dynamically sets properties on the target. * Dynamically sets properties on the target.
*
* @param mixed $value
*/ */
public function __set(string $property, $value): void public function __set(string $property, mixed $value): void
{ {
$this->target->{$property} = $value; // @phpstan-ignore-line $this->target->{$property} = $value; // @phpstan-ignore-line
} }

View File

@ -9,10 +9,10 @@ use PHPUnit\Util\Filesystem;
abstract class Printer implements \PHPUnit\Util\Printer abstract class Printer implements \PHPUnit\Util\Printer
{ {
/** @var resource|false */ /** @var resource|bool */
private $stream; private $stream;
private bool $isPhpStream; private readonly bool $isPhpStream;
private bool $isOpen; private bool $isOpen;
@ -46,12 +46,14 @@ abstract class Printer implements \PHPUnit\Util\Printer
assert($this->isOpen); assert($this->isOpen);
assert($this->stream !== false); assert($this->stream !== false);
// @phpstan-ignore-next-line
fwrite($this->stream, $buffer); fwrite($this->stream, $buffer);
} }
final public function flush(): void final public function flush(): void
{ {
if ($this->isOpen && $this->isPhpStream && $this->stream !== false) { if ($this->isOpen && $this->isPhpStream && $this->stream !== false) {
// @phpstan-ignore-next-line
fclose($this->stream); fclose($this->stream);
$this->isOpen = false; $this->isOpen = false;

View File

@ -69,9 +69,9 @@ final class Reflection
{ {
$test = TestSuite::getInstance()->test; $test = TestSuite::getInstance()->test;
return $test === null return $test instanceof \PHPUnit\Framework\TestCase
? static::bindCallable($callable) ? Closure::fromCallable($callable)->bindTo($test)(...$test->providedData())
: Closure::fromCallable($callable)->bindTo($test)(...$test->providedData()); : static::bindCallable($callable);
} }
/** /**
@ -119,9 +119,8 @@ final class Reflection
* @template TValue of object * @template TValue of object
* *
* @param TValue $object * @param TValue $object
* @param mixed $value
*/ */
public static function setPropertyValue(object $object, string $property, $value): void public static function setPropertyValue(object $object, string $property, mixed $value): void
{ {
/** @var ReflectionClass<TValue> $reflectionClass */ /** @var ReflectionClass<TValue> $reflectionClass */
$reflectionClass = new ReflectionClass($object); $reflectionClass = new ReflectionClass($object);
@ -153,8 +152,10 @@ final class Reflection
public static function getParameterClassName(ReflectionParameter $parameter): ?string public static function getParameterClassName(ReflectionParameter $parameter): ?string
{ {
$type = $parameter->getType(); $type = $parameter->getType();
if (! $type instanceof ReflectionNamedType) {
if (! $type instanceof ReflectionNamedType || $type->isBuiltin()) { return null;
}
if ($type->isBuiltin()) {
return null; return null;
} }