refacto: 100% type coverage

This commit is contained in:
Nuno Maduro
2023-06-15 15:16:04 +02:00
parent 4f3796ed2e
commit 54f4ee57ad
17 changed files with 96 additions and 124 deletions

View File

@ -50,9 +50,11 @@
}, },
"require-dev": { "require-dev": {
"pestphp/pest-dev-tools": "^2.12.0", "pestphp/pest-dev-tools": "^2.12.0",
"pestphp/pest-plugin-type-coverage": "^2.0.0",
"symfony/process": "^6.3.0" "symfony/process": "^6.3.0"
}, },
"minimum-stability": "stable", "minimum-stability": "dev",
"prefer-stable": true,
"config": { "config": {
"sort-packages": true, "sort-packages": true,
"preferred-install": "dist", "preferred-install": "dist",

View File

@ -381,9 +381,7 @@ final class Expectation
$this, $this,
fn (ObjectDescription $object): bool => str_contains((string) file_get_contents($object->path), 'declare(strict_types=1);'), fn (ObjectDescription $object): bool => str_contains((string) file_get_contents($object->path), 'declare(strict_types=1);'),
'to use strict types', 'to use strict types',
FileLineFinder::where(function (string $line): bool { FileLineFinder::where(fn (string $line): bool => str_contains($line, '<?php')),
return str_contains($line, '<?php');
}),
); );
} }
@ -396,9 +394,7 @@ final class Expectation
$this, $this,
fn (ObjectDescription $object): bool => $object->reflectionClass->isFinal(), fn (ObjectDescription $object): bool => $object->reflectionClass->isFinal(),
'to be final', 'to be final',
FileLineFinder::where(function (string $line): bool { FileLineFinder::where(fn (string $line): bool => str_contains($line, 'class')),
return str_contains($line, 'class');
}),
); );
} }
@ -411,9 +407,7 @@ final class Expectation
$this, $this,
fn (ObjectDescription $object): bool => $object->reflectionClass->isReadOnly(), fn (ObjectDescription $object): bool => $object->reflectionClass->isReadOnly(),
'to be readonly', 'to be readonly',
FileLineFinder::where(function (string $line): bool { FileLineFinder::where(fn (string $line): bool => str_contains($line, 'class')),
return str_contains($line, 'class');
}),
); );
} }
@ -426,9 +420,7 @@ final class Expectation
$this, $this,
fn (ObjectDescription $object): bool => $object->reflectionClass->isTrait(), fn (ObjectDescription $object): bool => $object->reflectionClass->isTrait(),
'to be trait', 'to be trait',
FileLineFinder::where(function (string $line): bool { FileLineFinder::where(fn (string $line): bool => str_contains($line, 'class')),
return str_contains($line, 'class');
}),
); );
} }
@ -449,9 +441,7 @@ final class Expectation
$this, $this,
fn (ObjectDescription $object): bool => $object->reflectionClass->isAbstract(), fn (ObjectDescription $object): bool => $object->reflectionClass->isAbstract(),
'to be abstract', 'to be abstract',
FileLineFinder::where(function (string $line): bool { FileLineFinder::where(fn (string $line): bool => str_contains($line, 'class')),
return str_contains($line, 'class');
}),
); );
} }
@ -464,9 +454,7 @@ final class Expectation
$this, $this,
fn (ObjectDescription $object): bool => $object->reflectionClass->isEnum(), fn (ObjectDescription $object): bool => $object->reflectionClass->isEnum(),
'to be enum', 'to be enum',
FileLineFinder::where(function (string $line): bool { FileLineFinder::where(fn (string $line): bool => str_contains($line, 'class')),
return str_contains($line, 'class');
}),
); );
} }
@ -487,9 +475,7 @@ final class Expectation
$this, $this,
fn (ObjectDescription $object): bool => $object->reflectionClass->isInterface(), fn (ObjectDescription $object): bool => $object->reflectionClass->isInterface(),
'to be interface', 'to be interface',
FileLineFinder::where(function (string $line): bool { FileLineFinder::where(fn (string $line): bool => str_contains($line, 'class')),
return str_contains($line, 'class');
}),
); );
} }
@ -512,9 +498,7 @@ final class Expectation
$this, $this,
fn (ObjectDescription $object): bool => $object->reflectionClass->isSubclassOf($class), fn (ObjectDescription $object): bool => $object->reflectionClass->isSubclassOf($class),
sprintf("to extend '%s'", $class), sprintf("to extend '%s'", $class),
FileLineFinder::where(function (string $line): bool { FileLineFinder::where(fn (string $line): bool => str_contains($line, 'class')),
return str_contains($line, 'class');
}),
); );
} }
@ -527,9 +511,7 @@ final class Expectation
$this, $this,
fn (ObjectDescription $object): bool => $object->reflectionClass->getParentClass() === false, fn (ObjectDescription $object): bool => $object->reflectionClass->getParentClass() === false,
'to extend nothing', 'to extend nothing',
FileLineFinder::where(function (string $line): bool { FileLineFinder::where(fn (string $line): bool => str_contains($line, 'class')),
return str_contains($line, 'class');
}),
); );
} }
@ -542,9 +524,7 @@ final class Expectation
$this, $this,
fn (ObjectDescription $object): bool => $object->reflectionClass->getInterfaceNames() === [], fn (ObjectDescription $object): bool => $object->reflectionClass->getInterfaceNames() === [],
'to implement nothing', 'to implement nothing',
FileLineFinder::where(function (string $line): bool { FileLineFinder::where(fn (string $line): bool => str_contains($line, 'class')),
return str_contains($line, 'class');
}),
); );
} }
@ -562,9 +542,7 @@ final class Expectation
fn (ObjectDescription $object): bool => count($interfaces) === count($object->reflectionClass->getInterfaceNames()) fn (ObjectDescription $object): bool => count($interfaces) === count($object->reflectionClass->getInterfaceNames())
&& array_diff($interfaces, $object->reflectionClass->getInterfaceNames()) === [], && array_diff($interfaces, $object->reflectionClass->getInterfaceNames()) === [],
"to only implement '".implode("', '", $interfaces)."'", "to only implement '".implode("', '", $interfaces)."'",
FileLineFinder::where(function (string $line): bool { FileLineFinder::where(fn (string $line): bool => str_contains($line, 'class')),
return str_contains($line, 'class');
}),
); );
} }
@ -577,9 +555,7 @@ final class Expectation
$this, $this,
fn (ObjectDescription $object): bool => str_ends_with($object->reflectionClass->getName(), $suffix), fn (ObjectDescription $object): bool => str_ends_with($object->reflectionClass->getName(), $suffix),
"to have suffix '{$suffix}'", "to have suffix '{$suffix}'",
FileLineFinder::where(function (string $line): bool { FileLineFinder::where(fn (string $line): bool => str_contains($line, 'class')),
return str_contains($line, 'class');
}),
); );
} }
@ -592,9 +568,7 @@ final class Expectation
$this, $this,
fn (ObjectDescription $object): bool => str_starts_with($object->reflectionClass->getName(), $suffix), fn (ObjectDescription $object): bool => str_starts_with($object->reflectionClass->getName(), $suffix),
"to have prefix '{$suffix}'", "to have prefix '{$suffix}'",
FileLineFinder::where(function (string $line): bool { FileLineFinder::where(fn (string $line): bool => str_contains($line, 'class')),
return str_contains($line, 'class');
}),
); );
} }
@ -619,9 +593,7 @@ final class Expectation
return true; return true;
}, },
"to implement '".implode("', '", $interfaces)."'", "to implement '".implode("', '", $interfaces)."'",
FileLineFinder::where(function (string $line): bool { FileLineFinder::where(fn (string $line): bool => str_contains($line, 'class')),
return str_contains($line, 'class');
}),
); );
} }

View File

@ -84,9 +84,7 @@ final class OppositeExpectation
$this->original, $this->original,
fn (ObjectDescription $object): bool => ! str_contains((string) file_get_contents($object->path), 'declare(strict_types=1);'), fn (ObjectDescription $object): bool => ! str_contains((string) file_get_contents($object->path), 'declare(strict_types=1);'),
'not to use strict types', 'not to use strict types',
FileLineFinder::where(function (string $line): bool { FileLineFinder::where(fn (string $line): bool => str_contains($line, '<?php')),
return str_contains($line, '<?php');
}),
); );
} }
@ -99,9 +97,7 @@ final class OppositeExpectation
$this->original, $this->original,
fn (ObjectDescription $object): bool => ! $object->reflectionClass->isFinal(), fn (ObjectDescription $object): bool => ! $object->reflectionClass->isFinal(),
'not to be final', 'not to be final',
FileLineFinder::where(function (string $line): bool { FileLineFinder::where(fn (string $line): bool => str_contains($line, 'class')),
return str_contains($line, 'class');
}),
); );
} }
@ -114,9 +110,7 @@ final class OppositeExpectation
$this->original, $this->original,
fn (ObjectDescription $object): bool => ! $object->reflectionClass->isReadOnly(), fn (ObjectDescription $object): bool => ! $object->reflectionClass->isReadOnly(),
'not to be readonly', 'not to be readonly',
FileLineFinder::where(function (string $line): bool { FileLineFinder::where(fn (string $line): bool => str_contains($line, 'class')),
return str_contains($line, 'class');
}),
); );
} }
@ -129,9 +123,7 @@ final class OppositeExpectation
$this->original, $this->original,
fn (ObjectDescription $object): bool => ! $object->reflectionClass->isTrait(), fn (ObjectDescription $object): bool => ! $object->reflectionClass->isTrait(),
'not to be trait', 'not to be trait',
FileLineFinder::where(function (string $line): bool { FileLineFinder::where(fn (string $line): bool => str_contains($line, 'class')),
return str_contains($line, 'class');
}),
); );
} }
@ -144,9 +136,7 @@ final class OppositeExpectation
$this->original, $this->original,
fn (ObjectDescription $object): bool => ! $object->reflectionClass->isAbstract(), fn (ObjectDescription $object): bool => ! $object->reflectionClass->isAbstract(),
'not to be abstract', 'not to be abstract',
FileLineFinder::where(function (string $line): bool { FileLineFinder::where(fn (string $line): bool => str_contains($line, 'class')),
return str_contains($line, 'class');
}),
); );
} }
@ -159,9 +149,7 @@ final class OppositeExpectation
$this->original, $this->original,
fn (ObjectDescription $object): bool => ! $object->reflectionClass->isEnum(), fn (ObjectDescription $object): bool => ! $object->reflectionClass->isEnum(),
'not to be enum', 'not to be enum',
FileLineFinder::where(function (string $line): bool { FileLineFinder::where(fn (string $line): bool => str_contains($line, 'class')),
return str_contains($line, 'class');
}),
); );
} }
@ -174,9 +162,7 @@ final class OppositeExpectation
$this->original, $this->original,
fn (ObjectDescription $object): bool => ! $object->reflectionClass->isInterface(), fn (ObjectDescription $object): bool => ! $object->reflectionClass->isInterface(),
'not to be interface', 'not to be interface',
FileLineFinder::where(function (string $line): bool { FileLineFinder::where(fn (string $line): bool => str_contains($line, 'class')),
return str_contains($line, 'class');
}),
); );
} }
@ -191,9 +177,7 @@ final class OppositeExpectation
$this->original, $this->original,
fn (ObjectDescription $object): bool => ! $object->reflectionClass->isSubclassOf($class), fn (ObjectDescription $object): bool => ! $object->reflectionClass->isSubclassOf($class),
sprintf("not to extend '%s'", $class), sprintf("not to extend '%s'", $class),
FileLineFinder::where(function (string $line): bool { FileLineFinder::where(fn (string $line): bool => str_contains($line, 'class')),
return str_contains($line, 'class');
}),
); );
} }
@ -206,14 +190,14 @@ final class OppositeExpectation
$this->original, $this->original,
fn (ObjectDescription $object): bool => $object->reflectionClass->getParentClass() !== false, fn (ObjectDescription $object): bool => $object->reflectionClass->getParentClass() !== false,
'to extend a class', 'to extend a class',
FileLineFinder::where(function (string $line): bool { FileLineFinder::where(fn (string $line): bool => str_contains($line, 'class')),
return str_contains($line, 'class');
}),
); );
} }
/** /**
* Asserts that the given expectation target not to implement the given interfaces. * Asserts that the given expectation target not to implement the given interfaces.
*
* @param array<int, class-string>|string $interfaces
*/ */
public function toImplement(array|string $interfaces): ArchExpectation public function toImplement(array|string $interfaces): ArchExpectation
{ {
@ -230,10 +214,8 @@ final class OppositeExpectation
return true; return true;
}, },
"not to implement '".implode("', '", (array) $interfaces)."'", "not to implement '".implode("', '", $interfaces)."'",
FileLineFinder::where(function (string $line): bool { FileLineFinder::where(fn (string $line): bool => str_contains($line, 'class')),
return str_contains($line, 'class');
}),
); );
} }
@ -243,31 +225,42 @@ final class OppositeExpectation
public function toImplementNothing(): ArchExpectation public function toImplementNothing(): ArchExpectation
{ {
return Targeted::make( return Targeted::make(
$this, $this->original,
fn (ObjectDescription $object): bool => $object->reflectionClass->getInterfaceNames() !== [], fn (ObjectDescription $object): bool => $object->reflectionClass->getInterfaceNames() !== [],
'to implement an interface', 'to implement an interface',
FileLineFinder::where(function (string $line): bool { FileLineFinder::where(fn (string $line): bool => str_contains($line, 'class')),
return str_contains($line, 'class');
}),
); );
} }
public function toOnlyImplement(array|string $interfaces): ArchExpectation /**
* Not supported.
*
* @param array<int, class-string>|string $interfaces
*/
public function toOnlyImplement(array|string $interfaces): never
{ {
throw InvalidExpectation::fromMethods(['not', 'toOnlyImplement']); throw InvalidExpectation::fromMethods(['not', 'toOnlyImplement']);
} }
/**
* Not supported.
*/
public function toHavePrefix(string $suffix): never public function toHavePrefix(string $suffix): never
{ {
throw InvalidExpectation::fromMethods(['not', 'toHavePrefix']); throw InvalidExpectation::fromMethods(['not', 'toHavePrefix']);
} }
/**
* Not supported.
*/
public function toHaveSuffix(string $suffix): never public function toHaveSuffix(string $suffix): never
{ {
throw InvalidExpectation::fromMethods(['not', 'toHaveSuffix']); throw InvalidExpectation::fromMethods(['not', 'toHaveSuffix']);
} }
/** /**
* Not supported.
*
* @param array<int, string>|string $targets * @param array<int, string>|string $targets
*/ */
public function toOnlyUse(array|string $targets): never public function toOnlyUse(array|string $targets): never
@ -275,6 +268,9 @@ final class OppositeExpectation
throw InvalidExpectation::fromMethods(['not', 'toOnlyUse']); throw InvalidExpectation::fromMethods(['not', 'toOnlyUse']);
} }
/**
* Not supported.
*/
public function toUseNothing(): never public function toUseNothing(): never
{ {
throw InvalidExpectation::fromMethods(['not', 'toUseNothing']); throw InvalidExpectation::fromMethods(['not', 'toUseNothing']);
@ -358,8 +354,13 @@ final class OppositeExpectation
$exporter = Exporter::default(); $exporter = Exporter::default();
$toString = fn ($argument): string => $exporter->shortenedExport($argument); $toString = fn (mixed $argument): string => $exporter->shortenedExport($argument);
throw new ExpectationFailedException(sprintf('Expecting %s not %s %s.', $toString($this->original->value), strtolower((string) preg_replace('/(?<!\ )[A-Z]/', ' $0', $name)), implode(' ', array_map(fn ($argument): string => $toString($argument), $arguments)))); throw new ExpectationFailedException(sprintf(
'Expecting %s not %s %s.',
$toString($this->original->value),
strtolower((string) preg_replace('/(?<!\ )[A-Z]/', ' $0', $name)),
implode(' ', array_map(fn (mixed $argument): string => $toString($argument), $arguments)),
));
} }
} }

View File

@ -98,7 +98,7 @@ final class TestCaseFactory
{ {
if ('\\' === DIRECTORY_SEPARATOR) { if ('\\' === DIRECTORY_SEPARATOR) {
// In case Windows, strtolower drive name, like in UsesCall. // In case Windows, strtolower drive name, like in UsesCall.
$filename = (string) preg_replace_callback('~^(?P<drive>[a-z]+:\\\)~i', static fn ($match): string => strtolower($match['drive']), $filename); $filename = (string) preg_replace_callback('~^(?P<drive>[a-z]+:\\\)~i', static fn (array $match): string => strtolower($match['drive']), $filename);
} }
$filename = str_replace('\\\\', '\\', addslashes((string) realpath($filename))); $filename = str_replace('\\\\', '\\', addslashes((string) realpath($filename)));
@ -134,7 +134,7 @@ final class TestCaseFactory
$hasPrintableTestCaseClassFQN = sprintf('\%s', HasPrintableTestCaseName::class); $hasPrintableTestCaseClassFQN = sprintf('\%s', HasPrintableTestCaseName::class);
$traitsCode = sprintf('use %s;', implode(', ', array_map( $traitsCode = sprintf('use %s;', implode(', ', array_map(
static fn ($trait): string => sprintf('\%s', $trait), $this->traits)) static fn (string $trait): string => sprintf('\%s', $trait), $this->traits))
); );
$partsFQN = explode('\\', $classFQN); $partsFQN = explode('\\', $classFQN);

View File

@ -147,11 +147,11 @@ final class TestCaseMethodFactory
} }
$annotations = implode('', array_map( $annotations = implode('', array_map(
static fn ($annotation): string => sprintf("\n * %s", $annotation), $annotations, static fn (string $annotation): string => sprintf("\n * %s", $annotation), $annotations,
)); ));
$attributes = implode('', array_map( $attributes = implode('', array_map(
static fn ($attribute): string => sprintf("\n %s", $attribute), $attributes, static fn (string $attribute): string => sprintf("\n %s", $attribute), $attributes,
)); ));
return <<<PHP return <<<PHP

View File

@ -66,11 +66,11 @@ final class UsesCall
*/ */
public function in(string ...$targets): void public function in(string ...$targets): void
{ {
$targets = array_map(function ($path): string { $targets = array_map(function (string $path): string {
$startChar = DIRECTORY_SEPARATOR; $startChar = DIRECTORY_SEPARATOR;
if ('\\' === DIRECTORY_SEPARATOR || preg_match('~\A[A-Z]:(?![^/\\\\])~i', $path) > 0) { if ('\\' === DIRECTORY_SEPARATOR || preg_match('~\A[A-Z]:(?![^/\\\\])~i', $path) > 0) {
$path = (string) preg_replace_callback('~^(?P<drive>[a-z]+:\\\)~i', fn ($match): string => strtolower($match['drive']), $path); $path = (string) preg_replace_callback('~^(?P<drive>[a-z]+:\\\)~i', fn (array $match): string => strtolower($match['drive']), $path);
$startChar = strtolower((string) preg_replace('~^([a-z]+:\\\).*$~i', '$1', __DIR__)); $startChar = strtolower((string) preg_replace('~^([a-z]+:\\\).*$~i', '$1', __DIR__));
} }

View File

@ -50,7 +50,7 @@ final class Coverage implements AddsOutput, HandlesArguments
*/ */
public function handleArguments(array $originals): array public function handleArguments(array $originals): array
{ {
$arguments = [...[''], ...array_values(array_filter($originals, function ($original): bool { $arguments = [...[''], ...array_values(array_filter($originals, function (string $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)) { if ($original === sprintf('--%s', $option)) {
return true; return true;

View File

@ -115,13 +115,13 @@ final class Parallel implements HandlesArguments
private function runTestSuiteInParallel(array $arguments): int private function runTestSuiteInParallel(array $arguments): int
{ {
$handlers = array_filter( $handlers = array_filter(
array_map(fn ($handler): object|string => Container::getInstance()->get($handler), self::HANDLERS), array_map(fn (string $handler): object|string => Container::getInstance()->get($handler), self::HANDLERS),
fn ($handler): bool => $handler instanceof HandlesArguments, fn (object|string $handler): bool => $handler instanceof HandlesArguments,
); );
$filteredArguments = array_reduce( $filteredArguments = array_reduce(
$handlers, $handlers,
fn ($arguments, HandlesArguments $handler): array => $handler->handleArguments($arguments), fn (array $arguments, HandlesArguments $handler): array => $handler->handleArguments($arguments),
$arguments $arguments
); );
@ -139,13 +139,13 @@ final class Parallel implements HandlesArguments
private function runWorkerHandlers(array $arguments): array private function runWorkerHandlers(array $arguments): array
{ {
$handlers = array_filter( $handlers = array_filter(
array_map(fn ($handler): object|string => Container::getInstance()->get($handler), self::HANDLERS), array_map(fn (string $handler): object|string => Container::getInstance()->get($handler), self::HANDLERS),
fn ($handler): bool => $handler instanceof HandlersWorkerArguments, fn (object|string $handler): bool => $handler instanceof HandlersWorkerArguments,
); );
return array_reduce( return array_reduce(
$handlers, $handlers,
fn ($arguments, HandlersWorkerArguments $handler): array => $handler->handleWorkerArguments($arguments), fn (array $arguments, HandlersWorkerArguments $handler): array => $handler->handleWorkerArguments($arguments),
$arguments $arguments
); );
} }

View File

@ -30,7 +30,7 @@ final class Parallel implements HandlesArguments
*/ */
public function handleArguments(array $arguments): array public function handleArguments(array $arguments): array
{ {
$args = array_reduce(self::ARGS_TO_REMOVE, fn ($args, $arg): array => $this->popArgument($arg, $args), $arguments); $args = array_reduce(self::ARGS_TO_REMOVE, fn (array $args, string $arg): array => $this->popArgument($arg, $args), $arguments);
return $this->pushArgument('--runner='.WrapperRunner::class, $args); return $this->pushArgument('--runner='.WrapperRunner::class, $args);
} }

View File

@ -23,6 +23,7 @@ use ParaTest\WrapperRunner\WrapperWorker;
use Pest\Result; use Pest\Result;
use Pest\TestSuite; use Pest\TestSuite;
use PHPUnit\Event\Facade as EventFacade; use PHPUnit\Event\Facade as EventFacade;
use PHPUnit\Event\TestRunner\WarningTriggered;
use PHPUnit\Runner\CodeCoverage; use PHPUnit\Runner\CodeCoverage;
use PHPUnit\TestRunner\TestResult\Facade as TestResultFacade; use PHPUnit\TestRunner\TestResult\Facade as TestResultFacade;
use PHPUnit\TestRunner\TestResult\TestResult; use PHPUnit\TestRunner\TestResult\TestResult;
@ -317,7 +318,10 @@ final class WrapperRunner implements RunnerInterface
$testResultSum->testTriggeredPhpunitErrorEvents(), $testResultSum->testTriggeredPhpunitErrorEvents(),
$testResultSum->testTriggeredPhpunitWarningEvents(), $testResultSum->testTriggeredPhpunitWarningEvents(),
$testResultSum->testRunnerTriggeredDeprecationEvents(), $testResultSum->testRunnerTriggeredDeprecationEvents(),
array_values(array_filter($testResultSum->testRunnerTriggeredWarningEvents(), fn ($event): bool => ! str_contains($event->message(), 'No tests found'))), array_values(array_filter(
$testResultSum->testRunnerTriggeredWarningEvents(),
fn (WarningTriggered $event): bool => ! str_contains($event->message(), 'No tests found')
)),
); );
$this->printer->printResults( $this->printer->printResults(

View File

@ -66,11 +66,11 @@ final class DatasetsRepository
} }
/** /**
* @return Closure|array<int|string, mixed>|never * @return Closure|array<int|string, mixed>
* *
* @throws ShouldNotHappen * @throws ShouldNotHappen
*/ */
public static function get(string $filename, string $description) public static function get(string $filename, string $description): Closure|array
{ {
$dataset = self::$withs[$filename.self::SEPARATOR.$description]; $dataset = self::$withs[$filename.self::SEPARATOR.$description];
@ -138,7 +138,7 @@ final class DatasetsRepository
/** /**
* @param array<Closure|iterable<int|string, mixed>|string> $datasets * @param array<Closure|iterable<int|string, mixed>|string> $datasets
* @return array<array<mixed>> * @return array<int, array<int, mixed>>
*/ */
private static function processDatasets(array $datasets, string $currentTestFile): array private static function processDatasets(array $datasets, string $currentTestFile): array
{ {
@ -193,7 +193,7 @@ final class DatasetsRepository
$closestScopeDatasetKey = array_reduce( $closestScopeDatasetKey = array_reduce(
array_keys($matchingDatasets), array_keys($matchingDatasets),
fn ($keyA, $keyB) => $keyA !== null && strlen((string) $keyA) > strlen($keyB) ? $keyA : $keyB fn (string|int|null $keyA, string|int|null $keyB): string|int|null => $keyA !== null && strlen((string) $keyA) > strlen((string) $keyB) ? $keyA : $keyB
); );
if ($closestScopeDatasetKey === null) { if ($closestScopeDatasetKey === null) {

View File

@ -159,10 +159,9 @@ final class Coverage
* ['11', '20..25', '50', '60..80']; * ['11', '20..25', '50', '60..80'];
* ``` * ```
* *
* @param File $file
* @return array<int, string> * @return array<int, string>
*/ */
public static function getMissingCoverage($file): array public static function getMissingCoverage(File $file): array
{ {
$shouldBeNewLine = true; $shouldBeNewLine = true;

View File

@ -18,11 +18,9 @@ final class ExceptionTrace
/** /**
* Ensures the given closure reports the good execution context. * Ensures the given closure reports the good execution context.
* *
* @return mixed
*
* @throws Throwable * @throws Throwable
*/ */
public static function ensure(Closure $closure) public static function ensure(Closure $closure): mixed
{ {
try { try {
return $closure(); return $closure();

View File

@ -84,6 +84,6 @@ final class ExpectationPipeline
*/ */
public function carry(): Closure public function carry(): Closure
{ {
return fn ($stack, $pipe): Closure => fn () => $pipe($stack, ...$this->passables); return fn (mixed $stack, callable $pipe): Closure => fn () => $pipe($stack, ...$this->passables);
} }
} }

View File

@ -24,9 +24,8 @@ final class Reflection
* Calls the given method with args on the given object. * Calls the given method with args on the given object.
* *
* @param array<int, mixed> $args * @param array<int, mixed> $args
* @return mixed
*/ */
public static function call(object $object, string $method, array $args = []) public static function call(object $object, string $method, array $args = []): mixed
{ {
$reflectionClass = new ReflectionClass($object); $reflectionClass = new ReflectionClass($object);
@ -53,9 +52,8 @@ final class Reflection
* Bind a callable to the TestCase and return the result. * Bind a callable to the TestCase and return the result.
* *
* @param array<int, mixed> $args * @param array<int, mixed> $args
* @return mixed
*/ */
public static function bindCallable(callable $callable, array $args = []) public static function bindCallable(callable $callable, array $args = []): mixed
{ {
return Closure::fromCallable($callable)->bindTo(TestSuite::getInstance()->test)(...$args); return Closure::fromCallable($callable)->bindTo(TestSuite::getInstance()->test)(...$args);
} }
@ -63,10 +61,8 @@ final class Reflection
/** /**
* Bind a callable to the TestCase and return the result, * Bind a callable to the TestCase and return the result,
* passing in the current dataset values as arguments. * passing in the current dataset values as arguments.
*
* @return mixed
*/ */
public static function bindCallableWithData(callable $callable) public static function bindCallableWithData(callable $callable): mixed
{ {
$test = TestSuite::getInstance()->test; $test = TestSuite::getInstance()->test;
@ -87,10 +83,8 @@ final class Reflection
/** /**
* Gets the property value from of the given object. * Gets the property value from of the given object.
*
* @return mixed
*/ */
public static function getPropertyValue(object $object, string $property) public static function getPropertyValue(object $object, string $property): mixed
{ {
$reflectionClass = new ReflectionClass($object); $reflectionClass = new ReflectionClass($object);
@ -206,10 +200,7 @@ final class Reflection
return $arguments; return $arguments;
} }
/** public static function getFunctionVariable(Closure $function, string $key): mixed
* @return mixed
*/
public static function getFunctionVariable(Closure $function, string $key)
{ {
return (new ReflectionFunction($function))->getStaticVariables()[$key] ?? null; return (new ReflectionFunction($function))->getStaticVariables()[$key] ?? null;
} }

View File

@ -59,13 +59,18 @@ final class GitDirtyTestCaseFilter implements TestCaseFilter
$dirtyFiles[substr($dirtyFile, 3)] = trim(substr($dirtyFile, 0, 3)); $dirtyFiles[substr($dirtyFile, 3)] = trim(substr($dirtyFile, 0, 3));
} }
$dirtyFiles = array_filter($dirtyFiles, fn ($status): bool => $status !== 'D'); $dirtyFiles = array_filter($dirtyFiles, fn (string $status): bool => $status !== 'D');
$dirtyFiles = array_map(fn ($file, $status): string => in_array($status, ['R', 'RM'], true) ? explode(' -> ', $file)[1] : $file, array_keys($dirtyFiles), $dirtyFiles); $dirtyFiles = array_map(
fn (string $file, string $status): string => in_array($status, ['R', 'RM'], true)
? explode(' -> ', $file)[1]
: $file, array_keys($dirtyFiles), $dirtyFiles,
);
$dirtyFiles = array_filter( $dirtyFiles = array_filter(
$dirtyFiles, $dirtyFiles,
fn ($file): bool => str_starts_with('.'.DIRECTORY_SEPARATOR.$file, TestSuite::getInstance()->testPath) || str_starts_with($file, TestSuite::getInstance()->testPath) fn (string $file): bool => str_starts_with('.'.DIRECTORY_SEPARATOR.$file, TestSuite::getInstance()->testPath)
|| str_starts_with($file, TestSuite::getInstance()->testPath)
); );
$dirtyFiles = array_values($dirtyFiles); $dirtyFiles = array_values($dirtyFiles);

View File

@ -18,7 +18,7 @@ $run = function () {
test('parallel', function () use ($run) { test('parallel', function () use ($run) {
expect($run('--exclude-group=integration')) expect($run('--exclude-group=integration'))
->toContain('Tests: 1 deprecated, 3 warnings, 4 incomplete, 1 notice, 8 todos, 15 skipped, 707 passed (1720 assertions)') ->toContain('Tests: 1 deprecated, 4 warnings, 5 incomplete, 2 notices, 13 todos, 15 skipped, 720 passed (1740 assertions)')
->toContain('Parallel: 3 processes'); ->toContain('Parallel: 3 processes');
})->skipOnWindows(); })->skipOnWindows();