mirror of
https://github.com/pestphp/pest.git
synced 2026-03-06 15:57:21 +01:00
refactor: PHP 8 features
This commit is contained in:
@ -15,7 +15,7 @@ trait Extendable
|
||||
/**
|
||||
* @var array<string, Closure>
|
||||
*/
|
||||
private static $extends = [];
|
||||
private static array $extends = [];
|
||||
|
||||
/**
|
||||
* Register a custom extend.
|
||||
|
||||
@ -13,61 +13,42 @@ use PHPUnit\Framework\ExecutionOrderDependency;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* To avoid inheritance conflicts, all the fields related to Pest only will be prefixed by double underscore.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
trait Testable
|
||||
{
|
||||
/**
|
||||
* The test case description. Contains the first
|
||||
* argument of global functions like `it` and `test`.
|
||||
*
|
||||
* @var string
|
||||
* The Test Case description.
|
||||
*/
|
||||
private $__description;
|
||||
private string $__description;
|
||||
|
||||
/**
|
||||
* Holds the test closure function.
|
||||
*
|
||||
* @var Closure
|
||||
* The Test Case "test" closure.
|
||||
*/
|
||||
private $__test;
|
||||
private Closure $__test;
|
||||
|
||||
/**
|
||||
* Holds a global/shared beforeEach ("set up") closure if one has been
|
||||
* defined.
|
||||
*
|
||||
* @var Closure|null
|
||||
* The Test Case "setUp" closure.
|
||||
*/
|
||||
private $__beforeEach = null;
|
||||
private ?Closure $__beforeEach = null;
|
||||
|
||||
/**
|
||||
* Holds a global/shared afterEach ("tear down") closure if one has been
|
||||
* defined.
|
||||
*
|
||||
* @var Closure|null
|
||||
* The Test Case "tearDown" closure.
|
||||
*/
|
||||
private $__afterEach = null;
|
||||
private ?Closure $__afterEach = null;
|
||||
|
||||
/**
|
||||
* Holds a global/shared beforeAll ("set up before") closure if one has been
|
||||
* defined.
|
||||
*
|
||||
* @var Closure|null
|
||||
* The Test Case "setUpBeforeClass" closure.
|
||||
*/
|
||||
private static $__beforeAll = null;
|
||||
private static ?Closure $__beforeAll = null;
|
||||
|
||||
/**
|
||||
* Holds a global/shared afterAll ("tear down after") closure if one has
|
||||
* been defined.
|
||||
*
|
||||
* @var Closure|null
|
||||
* The test "tearDownAfterClass" closure.
|
||||
*/
|
||||
private static $__afterAll = null;
|
||||
private static ?Closure $__afterAll = null;
|
||||
|
||||
/**
|
||||
* Creates a new instance of the test case.
|
||||
* Creates a new Test Case instance.
|
||||
*/
|
||||
public function __construct(Closure $test, string $description, array $data)
|
||||
{
|
||||
@ -82,7 +63,7 @@ trait Testable
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the groups to the current test case.
|
||||
* Adds groups to the Test Case.
|
||||
*/
|
||||
public function addGroups(array $groups): void
|
||||
{
|
||||
@ -92,14 +73,14 @@ trait Testable
|
||||
}
|
||||
|
||||
/**
|
||||
* Add dependencies to the test case and map them to instances of ExecutionOrderDependency.
|
||||
* Adds dependencies to the Test Case.
|
||||
*/
|
||||
public function addDependencies(array $tests): void
|
||||
{
|
||||
$className = get_class($this);
|
||||
$className = $this::class;
|
||||
|
||||
$tests = array_map(function (string $test) use ($className): ExecutionOrderDependency {
|
||||
if (strpos($test, '::') === false) {
|
||||
$tests = array_map(static function (string $test) use ($className): ExecutionOrderDependency {
|
||||
if (!str_contains($test, '::')) {
|
||||
$test = "{$className}::{$test}";
|
||||
}
|
||||
|
||||
@ -110,8 +91,7 @@ trait Testable
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a shared/"global" before all test hook that will execute **before**
|
||||
* the test defined `beforeAll` hook(s).
|
||||
* Adds a new "setUpBeforeClass" to the Test Case.
|
||||
*/
|
||||
public function __addBeforeAll(?Closure $hook): void
|
||||
{
|
||||
@ -125,8 +105,7 @@ trait Testable
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a shared/"global" after all test hook that will execute **before**
|
||||
* the test defined `afterAll` hook(s).
|
||||
* Adds a new "tearDownAfterClass" to the Test Case.
|
||||
*/
|
||||
public function __addAfterAll(?Closure $hook): void
|
||||
{
|
||||
@ -140,8 +119,7 @@ trait Testable
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a shared/"global" before each test hook that will execute **before**
|
||||
* the test defined `beforeEach` hook.
|
||||
* Adds a new "setUp" to the Test Case.
|
||||
*/
|
||||
public function __addBeforeEach(?Closure $hook): void
|
||||
{
|
||||
@ -149,8 +127,7 @@ trait Testable
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a shared/"global" after each test hook that will execute **before**
|
||||
* the test defined `afterEach` hook.
|
||||
* Adds a new "tearDown" to the Test Case.
|
||||
*/
|
||||
public function __addAfterEach(?Closure $hook): void
|
||||
{
|
||||
@ -158,7 +135,7 @@ trait Testable
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a shared/global hook and compose them if more than one is passed.
|
||||
* Adds a new "hook" to the Test Case.
|
||||
*/
|
||||
private function __addHook(string $property, ?Closure $hook): void
|
||||
{
|
||||
@ -172,9 +149,7 @@ trait Testable
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the test case name. Note that, in Pest
|
||||
* we ignore withDataset argument as the description
|
||||
* already contains the dataset description.
|
||||
* Gets the Test Case name.
|
||||
*/
|
||||
public function getName(bool $withDataSet = true): string
|
||||
{
|
||||
@ -183,13 +158,16 @@ trait Testable
|
||||
: $this->__description;
|
||||
}
|
||||
|
||||
public static function __getFileName(): string
|
||||
/**
|
||||
* Gets the Test Case filename.
|
||||
*/
|
||||
public static function __getFilename(): string
|
||||
{
|
||||
return self::$__filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called before the first test of this test class is run.
|
||||
* This method is called before the first test of this Test Case is run.
|
||||
*/
|
||||
public static function setUpBeforeClass(): void
|
||||
{
|
||||
@ -205,7 +183,7 @@ trait Testable
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called after the last test of this test class is run.
|
||||
* This method is called after the last test of this Test Case is run.
|
||||
*/
|
||||
public static function tearDownAfterClass(): void
|
||||
{
|
||||
@ -221,7 +199,7 @@ trait Testable
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets executed before the test.
|
||||
* Gets executed before the Test Case.
|
||||
*/
|
||||
protected function setUp(): void
|
||||
{
|
||||
@ -239,7 +217,7 @@ trait Testable
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets executed after the test.
|
||||
* Gets executed after the Test Case.
|
||||
*/
|
||||
protected function tearDown(): void
|
||||
{
|
||||
@ -257,7 +235,7 @@ trait Testable
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the test case as string.
|
||||
* Gets the Test Case filename and description.
|
||||
*/
|
||||
public function toString(): string
|
||||
{
|
||||
@ -269,13 +247,11 @@ trait Testable
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the test.
|
||||
*
|
||||
* @return mixed
|
||||
* Executes the Test Case current test.
|
||||
*
|
||||
* @throws Throwable
|
||||
*/
|
||||
public function __test()
|
||||
public function __test(): mixed
|
||||
{
|
||||
return $this->__callClosure($this->__test, $this->__resolveTestArguments(func_get_args()));
|
||||
}
|
||||
@ -287,23 +263,20 @@ trait Testable
|
||||
*/
|
||||
private function __resolveTestArguments(array $arguments): array
|
||||
{
|
||||
return array_map(function ($data) {
|
||||
return $data instanceof Closure ? $this->__callClosure($data, []) : $data;
|
||||
}, $arguments);
|
||||
return array_map(fn ($data) => $data instanceof Closure ? $this->__callClosure($data, []) : $data, $arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*
|
||||
* @throws Throwable
|
||||
*/
|
||||
private function __callClosure(Closure $closure, array $arguments)
|
||||
private function __callClosure(Closure $closure, array $arguments): mixed
|
||||
{
|
||||
return ExceptionTrace::ensure(function () use ($closure, $arguments) {
|
||||
return call_user_func_array(Closure::bind($closure, $this, get_class($this)), $arguments);
|
||||
});
|
||||
return ExceptionTrace::ensure(fn () => call_user_func_array(Closure::bind($closure, $this, $this::class), $arguments));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Test Case name that should be used by printers.
|
||||
*/
|
||||
public function getPrintableTestCaseName(): string
|
||||
{
|
||||
return ltrim(self::class, 'P\\');
|
||||
|
||||
@ -20,12 +20,9 @@ final class Help
|
||||
' <info>--group=<fg=cyan><name></></info> Only runs tests from the specified group(s)',
|
||||
];
|
||||
|
||||
/** @var OutputInterface */
|
||||
private $output;
|
||||
|
||||
public function __construct(OutputInterface $output)
|
||||
public function __construct(private OutputInterface $output)
|
||||
{
|
||||
$this->output = $output;
|
||||
// ..
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
|
||||
@ -25,12 +25,9 @@ final class Thanks
|
||||
' <options=bold>https://github.com/sponsors/nunomaduro</>',
|
||||
];
|
||||
|
||||
/** @var OutputInterface */
|
||||
private $output;
|
||||
|
||||
public function __construct(OutputInterface $output)
|
||||
public function __construct(private OutputInterface $output)
|
||||
{
|
||||
$this->output = $output;
|
||||
// ..
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -20,14 +20,14 @@ final class Datasets
|
||||
*
|
||||
* @var array<int|string, Closure|iterable<int|string, mixed>>
|
||||
*/
|
||||
private static $datasets = [];
|
||||
private static array $datasets = [];
|
||||
|
||||
/**
|
||||
* Sets the given.
|
||||
*
|
||||
* @param Closure|iterable<int|string, mixed> $data
|
||||
*/
|
||||
public static function set(string $name, $data): void
|
||||
public static function set(string $name, Closure|iterable $data): void
|
||||
{
|
||||
if (array_key_exists($name, self::$datasets)) {
|
||||
throw new DatasetAlreadyExist($name);
|
||||
@ -39,7 +39,7 @@ final class Datasets
|
||||
/**
|
||||
* @return Closure|iterable<int|string, mixed>
|
||||
*/
|
||||
public static function get(string $name)
|
||||
public static function get(string $name): Closure|iterable
|
||||
{
|
||||
if (!array_key_exists($name, self::$datasets)) {
|
||||
throw new DatasetDoesNotExist($name);
|
||||
@ -161,10 +161,9 @@ final class Datasets
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int|string $key
|
||||
* @param array<int, mixed> $data
|
||||
*/
|
||||
private static function getDataSetDescription($key, array $data): string
|
||||
private static function getDataSetDescription(int|string $key, array $data): string
|
||||
{
|
||||
$exporter = new Exporter();
|
||||
|
||||
|
||||
14
src/Each.php
14
src/Each.php
@ -11,22 +11,14 @@ namespace Pest;
|
||||
*/
|
||||
final class Each
|
||||
{
|
||||
/**
|
||||
* @var Expectation
|
||||
*/
|
||||
private $original;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $opposite = false;
|
||||
private bool $opposite = false;
|
||||
|
||||
/**
|
||||
* Creates an expectation on each item of the iterable "value".
|
||||
*/
|
||||
public function __construct(Expectation $original)
|
||||
public function __construct(private Expectation $original)
|
||||
{
|
||||
$this->original = $original;
|
||||
// ..
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -27,9 +27,7 @@ final class DatasetMissing extends BadFunctionCallException implements Exception
|
||||
"A test with the description '%s' has %d argument(s) ([%s]) and no dataset(s) provided in %s",
|
||||
$name,
|
||||
count($args),
|
||||
implode(', ', array_map(static function (string $arg, string $type): string {
|
||||
return sprintf('%s $%s', $type, $arg);
|
||||
}, array_keys($args), $args)),
|
||||
implode(', ', array_map(static fn (string $arg, string $type): string => sprintf('%s $%s', $type, $arg), array_keys($args), $args)),
|
||||
$file,
|
||||
));
|
||||
}
|
||||
|
||||
@ -29,37 +29,26 @@ use Throwable;
|
||||
*/
|
||||
final class Expectation
|
||||
{
|
||||
use Extendable {
|
||||
use RetrievesValues, Extendable {
|
||||
__call as __extendsCall;
|
||||
}
|
||||
use RetrievesValues;
|
||||
|
||||
/**
|
||||
* The expectation value.
|
||||
*
|
||||
* @readonly
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
public $value;
|
||||
|
||||
/**
|
||||
* The exporter instance, if any.
|
||||
*
|
||||
* @readonly
|
||||
*
|
||||
* @var Exporter|null
|
||||
*/
|
||||
private $exporter;
|
||||
private ?Exporter $exporter = null;
|
||||
|
||||
/**
|
||||
* Creates a new expectation.
|
||||
*
|
||||
* @param TValue $value
|
||||
*/
|
||||
public function __construct($value)
|
||||
{
|
||||
$this->value = $value;
|
||||
public function __construct(
|
||||
public mixed $value
|
||||
) {
|
||||
// ..
|
||||
}
|
||||
|
||||
/**
|
||||
@ -69,7 +58,7 @@ final class Expectation
|
||||
*
|
||||
* @return Expectation<TValue>
|
||||
*/
|
||||
public function and($value): Expectation
|
||||
public function and(mixed $value): Expectation
|
||||
{
|
||||
return new self($value);
|
||||
}
|
||||
@ -103,9 +92,9 @@ final class Expectation
|
||||
/**
|
||||
* Send the expectation value to Ray along with all given arguments.
|
||||
*
|
||||
* @param mixed $arguments
|
||||
* @param ...mixed $arguments
|
||||
*/
|
||||
public function ray(...$arguments): self
|
||||
public function ray(mixed ...$arguments): self
|
||||
{
|
||||
if (function_exists('ray')) {
|
||||
// @phpstan-ignore-next-line
|
||||
@ -146,9 +135,9 @@ final class Expectation
|
||||
*
|
||||
* @template TSequenceValue
|
||||
*
|
||||
* @param callable(self, self): void|TSequenceValue ...$callbacks
|
||||
* @param (callable(self, self): void)|TSequenceValue ...$callbacks
|
||||
*/
|
||||
public function sequence(...$callbacks): Expectation
|
||||
public function sequence(mixed ...$callbacks): Expectation
|
||||
{
|
||||
if (!is_iterable($this->value)) {
|
||||
throw new BadMethodCallException('Expectation value is not iterable.');
|
||||
@ -187,16 +176,14 @@ final class Expectation
|
||||
*
|
||||
* @template TMatchSubject of array-key
|
||||
*
|
||||
* @param callable(): TMatchSubject|TMatchSubject $subject
|
||||
* @param (callable(): TMatchSubject)|TMatchSubject $subject
|
||||
* @param array<TMatchSubject, (callable(Expectation<TValue>): mixed)|TValue> $expressions
|
||||
*/
|
||||
public function match($subject, array $expressions): Expectation
|
||||
public function match(mixed $subject, array $expressions): Expectation
|
||||
{
|
||||
$subject = is_callable($subject)
|
||||
? $subject
|
||||
: function () use ($subject) {
|
||||
return $subject;
|
||||
};
|
||||
: fn () => $subject;
|
||||
|
||||
$subject = $subject();
|
||||
|
||||
@ -229,15 +216,15 @@ final class Expectation
|
||||
/**
|
||||
* Apply the callback if the given "condition" is falsy.
|
||||
*
|
||||
* @param (callable(): bool)|bool $condition
|
||||
* @param (callable(): bool)|bool $condition
|
||||
* @param callable(Expectation<TValue>): mixed $callback
|
||||
*/
|
||||
public function unless($condition, callable $callback): Expectation
|
||||
public function unless(callable|bool $condition, callable $callback): Expectation
|
||||
{
|
||||
$condition = is_callable($condition)
|
||||
? $condition
|
||||
: static function () use ($condition): bool {
|
||||
return (bool) $condition; // @phpstan-ignore-line
|
||||
return $condition; // @phpstan-ignore-line
|
||||
};
|
||||
|
||||
return $this->when(!$condition(), $callback);
|
||||
@ -246,15 +233,15 @@ final class Expectation
|
||||
/**
|
||||
* Apply the callback if the given "condition" is truthy.
|
||||
*
|
||||
* @param (callable(): bool)|bool $condition
|
||||
* @param (callable(): bool)|bool $condition
|
||||
* @param callable(Expectation<TValue>): mixed $callback
|
||||
*/
|
||||
public function when($condition, callable $callback): Expectation
|
||||
public function when(callable|bool $condition, callable $callback): Expectation
|
||||
{
|
||||
$condition = is_callable($condition)
|
||||
? $condition
|
||||
: static function () use ($condition): bool {
|
||||
return (bool) $condition; // @phpstan-ignore-line
|
||||
return $condition; // @phpstan-ignore-line
|
||||
};
|
||||
|
||||
if ($condition()) {
|
||||
@ -268,10 +255,8 @@ final class Expectation
|
||||
* Asserts that two variables have the same type and
|
||||
* value. Used on objects, it asserts that two
|
||||
* variables reference the same object.
|
||||
*
|
||||
* @param mixed $expected
|
||||
*/
|
||||
public function toBe($expected): Expectation
|
||||
public function toBe(mixed $expected): Expectation
|
||||
{
|
||||
Assert::assertSame($expected, $this->value);
|
||||
|
||||
@ -330,10 +315,8 @@ final class Expectation
|
||||
|
||||
/**
|
||||
* Asserts that the value is greater than $expected.
|
||||
*
|
||||
* @param int|float $expected
|
||||
*/
|
||||
public function toBeGreaterThan($expected): Expectation
|
||||
public function toBeGreaterThan(int|float $expected): Expectation
|
||||
{
|
||||
Assert::assertGreaterThan($expected, $this->value);
|
||||
|
||||
@ -342,10 +325,8 @@ final class Expectation
|
||||
|
||||
/**
|
||||
* Asserts that the value is greater than or equal to $expected.
|
||||
*
|
||||
* @param int|float $expected
|
||||
*/
|
||||
public function toBeGreaterThanOrEqual($expected): Expectation
|
||||
public function toBeGreaterThanOrEqual(int|float $expected): Expectation
|
||||
{
|
||||
Assert::assertGreaterThanOrEqual($expected, $this->value);
|
||||
|
||||
@ -354,10 +335,8 @@ final class Expectation
|
||||
|
||||
/**
|
||||
* Asserts that the value is less than or equal to $expected.
|
||||
*
|
||||
* @param int|float $expected
|
||||
*/
|
||||
public function toBeLessThan($expected): Expectation
|
||||
public function toBeLessThan(int|float $expected): Expectation
|
||||
{
|
||||
Assert::assertLessThan($expected, $this->value);
|
||||
|
||||
@ -366,10 +345,8 @@ final class Expectation
|
||||
|
||||
/**
|
||||
* Asserts that the value is less than $expected.
|
||||
*
|
||||
* @param int|float $expected
|
||||
*/
|
||||
public function toBeLessThanOrEqual($expected): Expectation
|
||||
public function toBeLessThanOrEqual(int|float $expected): Expectation
|
||||
{
|
||||
Assert::assertLessThanOrEqual($expected, $this->value);
|
||||
|
||||
@ -378,10 +355,8 @@ final class Expectation
|
||||
|
||||
/**
|
||||
* Asserts that $needle is an element of the value.
|
||||
*
|
||||
* @param mixed $needles
|
||||
*/
|
||||
public function toContain(...$needles): Expectation
|
||||
public function toContain(mixed ...$needles): Expectation
|
||||
{
|
||||
foreach ($needles as $needle) {
|
||||
if (is_string($this->value)) {
|
||||
@ -456,10 +431,8 @@ final class Expectation
|
||||
|
||||
/**
|
||||
* Asserts that the value contains the property $name.
|
||||
*
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function toHaveProperty(string $name, $value = null): Expectation
|
||||
public function toHaveProperty(string $name, mixed $value = null): Expectation
|
||||
{
|
||||
$this->toBeObject();
|
||||
|
||||
@ -489,10 +462,8 @@ final class Expectation
|
||||
|
||||
/**
|
||||
* Asserts that two variables have the same value.
|
||||
*
|
||||
* @param mixed $expected
|
||||
*/
|
||||
public function toEqual($expected): Expectation
|
||||
public function toEqual(mixed $expected): Expectation
|
||||
{
|
||||
Assert::assertEquals($expected, $this->value);
|
||||
|
||||
@ -507,10 +478,8 @@ final class Expectation
|
||||
* are sorted before they are compared. When $expected and $this->value
|
||||
* are objects, each object is converted to an array containing all
|
||||
* private, protected and public attributes.
|
||||
*
|
||||
* @param mixed $expected
|
||||
*/
|
||||
public function toEqualCanonicalizing($expected): Expectation
|
||||
public function toEqualCanonicalizing(mixed $expected): Expectation
|
||||
{
|
||||
Assert::assertEqualsCanonicalizing($expected, $this->value);
|
||||
|
||||
@ -520,10 +489,8 @@ final class Expectation
|
||||
/**
|
||||
* Asserts that the absolute difference between the value and $expected
|
||||
* is lower than $delta.
|
||||
*
|
||||
* @param mixed $expected
|
||||
*/
|
||||
public function toEqualWithDelta($expected, float $delta): Expectation
|
||||
public function toEqualWithDelta(mixed $expected, float $delta): Expectation
|
||||
{
|
||||
Assert::assertEqualsWithDelta($expected, $this->value, $delta);
|
||||
|
||||
@ -555,9 +522,9 @@ final class Expectation
|
||||
/**
|
||||
* Asserts that the value is an instance of $class.
|
||||
*
|
||||
* @param string $class
|
||||
* @param class-string $class
|
||||
*/
|
||||
public function toBeInstanceOf($class): Expectation
|
||||
public function toBeInstanceOf(string $class): Expectation
|
||||
{
|
||||
/* @phpstan-ignore-next-line */
|
||||
Assert::assertInstanceOf($class, $this->value);
|
||||
@ -708,11 +675,8 @@ final class Expectation
|
||||
|
||||
/**
|
||||
* Asserts that the value array has the provided $key.
|
||||
*
|
||||
* @param string|int $key
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function toHaveKey($key, $value = null): Expectation
|
||||
public function toHaveKey(string|int $key, mixed $value = null): Expectation
|
||||
{
|
||||
if (is_object($this->value) && method_exists($this->value, 'toArray')) {
|
||||
$array = $this->value->toArray();
|
||||
@ -812,9 +776,9 @@ final class Expectation
|
||||
/**
|
||||
* Asserts that the value array matches the given array subset.
|
||||
*
|
||||
* @param array<int|string, mixed> $array
|
||||
* @param iterable<int|string, mixed> $array
|
||||
*/
|
||||
public function toMatchArray($array): Expectation
|
||||
public function toMatchArray(iterable|object $array): Expectation
|
||||
{
|
||||
if (is_object($this->value) && method_exists($this->value, 'toArray')) {
|
||||
$valueAsArray = $this->value->toArray();
|
||||
@ -843,9 +807,9 @@ final class Expectation
|
||||
* Asserts that the value object matches a subset
|
||||
* of the properties of an given object.
|
||||
*
|
||||
* @param array<string, mixed>|object $object
|
||||
* @param iterable<string, mixed>|object $object
|
||||
*/
|
||||
public function toMatchObject($object): Expectation
|
||||
public function toMatchObject(iterable|object $object): Expectation
|
||||
{
|
||||
foreach ((array) $object as $property => $value) {
|
||||
Assert::assertTrue(property_exists($this->value, $property));
|
||||
@ -891,7 +855,7 @@ final class Expectation
|
||||
*
|
||||
* @param (Closure(Throwable): mixed)|string $exception
|
||||
*/
|
||||
public function toThrow($exception, string $exceptionMessage = null): Expectation
|
||||
public function toThrow(callable|string $exception, string $exceptionMessage = null): Expectation
|
||||
{
|
||||
$callback = NullClosure::create();
|
||||
|
||||
@ -938,10 +902,8 @@ final class Expectation
|
||||
|
||||
/**
|
||||
* Exports the given value.
|
||||
*
|
||||
* @param mixed $value
|
||||
*/
|
||||
private function export($value): string
|
||||
private function export(mixed $value): string
|
||||
{
|
||||
if ($this->exporter === null) {
|
||||
$this->exporter = new Exporter();
|
||||
@ -971,10 +933,8 @@ final class Expectation
|
||||
/**
|
||||
* Dynamically calls methods on the class without any arguments
|
||||
* or creates a new higher order expectation.
|
||||
*
|
||||
* @return Expectation|HigherOrderExpectation
|
||||
*/
|
||||
public function __get(string $name)
|
||||
public function __get(string $name): Expectation|OppositeExpectation|Each|HigherOrderExpectation
|
||||
{
|
||||
if (!method_exists($this, $name) && !static::hasExtend($name)) {
|
||||
return new HigherOrderExpectation($this, $this->retrieve($name, $this->value));
|
||||
|
||||
@ -22,97 +22,68 @@ use RuntimeException;
|
||||
*/
|
||||
final class TestCaseFactory
|
||||
{
|
||||
/**
|
||||
* Holds the test filename.
|
||||
*
|
||||
* @readonly
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $filename;
|
||||
|
||||
/**
|
||||
* Marks this test case as only.
|
||||
*
|
||||
* @readonly
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $only = false;
|
||||
|
||||
/**
|
||||
* Holds the test description.
|
||||
*
|
||||
* If the description is null, means that it
|
||||
* will be created with the given assertions.
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
public $description;
|
||||
public bool $only = false;
|
||||
|
||||
/**
|
||||
* Holds the test closure.
|
||||
*
|
||||
* @readonly
|
||||
*
|
||||
* @var Closure
|
||||
*/
|
||||
public $test;
|
||||
public Closure $test;
|
||||
|
||||
/**
|
||||
* Holds the dataset, if any.
|
||||
*
|
||||
* @var array<Closure|iterable<int|string, mixed>|string>
|
||||
*/
|
||||
public $datasets = [];
|
||||
public array $datasets = [];
|
||||
|
||||
/**
|
||||
* The FQN of the test case class.
|
||||
*
|
||||
* @var string
|
||||
* @var class-string
|
||||
*/
|
||||
public $class = TestCase::class;
|
||||
public string $class = TestCase::class;
|
||||
|
||||
/**
|
||||
* An array of FQN of the class traits.
|
||||
*
|
||||
* @var array <int, string>
|
||||
*/
|
||||
public $traits = [
|
||||
public array $traits = [
|
||||
Concerns\Testable::class,
|
||||
Concerns\Expectable::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* Holds the higher order messages
|
||||
* for the factory that are proxyble.
|
||||
*
|
||||
* @var HigherOrderMessageCollection
|
||||
* Holds the higher order messages for the factory that are proxyble.
|
||||
*/
|
||||
public $factoryProxies;
|
||||
public HigherOrderMessageCollection $factoryProxies;
|
||||
|
||||
/**
|
||||
* Holds the higher order messages that are proxyble.
|
||||
*
|
||||
* @var HigherOrderMessageCollection
|
||||
*/
|
||||
public $proxies;
|
||||
public HigherOrderMessageCollection $proxies;
|
||||
|
||||
/**
|
||||
* Holds the higher order messages that are chainable.
|
||||
*
|
||||
* @var HigherOrderMessageCollection
|
||||
*/
|
||||
public $chains;
|
||||
public HigherOrderMessageCollection $chains;
|
||||
|
||||
/**
|
||||
* Creates a new anonymous test case pending object.
|
||||
*/
|
||||
public function __construct(string $filename, string $description = null, Closure $closure = null)
|
||||
public function __construct(
|
||||
public string $filename,
|
||||
public ?string $description = null,
|
||||
Closure $closure = null)
|
||||
{
|
||||
$this->filename = $filename;
|
||||
$this->description = $description;
|
||||
$this->test = $closure ?? function (): void {
|
||||
$this->test = $closure ?? function (): void {
|
||||
if (Assert::getCount() === 0) {
|
||||
self::markTestIncomplete(); // @phpstan-ignore-line
|
||||
}
|
||||
@ -146,7 +117,7 @@ final class TestCaseFactory
|
||||
$chains->chain($this);
|
||||
|
||||
/* @phpstan-ignore-next-line */
|
||||
return call_user_func(Closure::bind($factoryTest, $this, get_class($this)), ...func_get_args());
|
||||
return call_user_func(Closure::bind($factoryTest, $this, $this::class), ...func_get_args());
|
||||
};
|
||||
|
||||
$className = $this->makeClassFromFilename($this->filename);
|
||||
@ -170,9 +141,7 @@ final class TestCaseFactory
|
||||
{
|
||||
if ('\\' === DIRECTORY_SEPARATOR) {
|
||||
// In case Windows, strtolower drive name, like in UsesCall.
|
||||
$filename = (string) preg_replace_callback('~^(?P<drive>[a-z]+:\\\)~i', function ($match): string {
|
||||
return strtolower($match['drive']);
|
||||
}, $filename);
|
||||
$filename = (string) preg_replace_callback('~^(?P<drive>[a-z]+:\\\)~i', fn ($match): string => strtolower($match['drive']), $filename);
|
||||
}
|
||||
|
||||
$filename = str_replace('\\\\', '\\', addslashes((string) realpath($filename)));
|
||||
@ -184,9 +153,7 @@ final class TestCaseFactory
|
||||
// Strip out any %-encoded octets.
|
||||
$relativePath = (string) preg_replace('|%[a-fA-F0-9][a-fA-F0-9]|', '', $relativePath);
|
||||
// Remove escaped quote sequences (maintain namespace)
|
||||
$relativePath = str_replace(array_map(function (string $quote): string {
|
||||
return sprintf('\\%s', $quote);
|
||||
}, ['\'', '"']), '', $relativePath);
|
||||
$relativePath = str_replace(array_map(fn (string $quote): string => sprintf('\\%s', $quote), ['\'', '"']), '', $relativePath);
|
||||
// Limit to A-Z, a-z, 0-9, '_', '-'.
|
||||
$relativePath = (string) preg_replace('/[^A-Za-z0-9\\\\]/', '', $relativePath);
|
||||
|
||||
@ -196,9 +163,7 @@ final class TestCaseFactory
|
||||
}
|
||||
|
||||
$hasPrintableTestCaseClassFQN = sprintf('\%s', HasPrintableTestCaseName::class);
|
||||
$traitsCode = sprintf('use %s;', implode(', ', array_map(function ($trait): string {
|
||||
return sprintf('\%s', $trait);
|
||||
}, $this->traits)));
|
||||
$traitsCode = sprintf('use %s;', implode(', ', array_map(fn ($trait): string => sprintf('\%s', $trait), $this->traits)));
|
||||
|
||||
$partsFQN = explode('\\', $classFQN);
|
||||
$className = array_pop($partsFQN);
|
||||
|
||||
@ -18,10 +18,8 @@ use PHPUnit\Framework\TestCase;
|
||||
* Creates a new expectation.
|
||||
*
|
||||
* @param mixed $value the Value
|
||||
*
|
||||
* @return Expectation|Extendable
|
||||
*/
|
||||
function expect($value = null)
|
||||
function expect($value = null): Expectation|Extendable
|
||||
{
|
||||
if (func_num_args() === 0) {
|
||||
return new Extendable(Expectation::class);
|
||||
@ -60,7 +58,7 @@ if (!function_exists('dataset')) {
|
||||
*
|
||||
* @param Closure|iterable<int|string, mixed> $dataset
|
||||
*/
|
||||
function dataset(string $name, $dataset): void
|
||||
function dataset(string $name, Closure|iterable $dataset): void
|
||||
{
|
||||
Datasets::set($name, $dataset);
|
||||
}
|
||||
|
||||
@ -17,39 +17,17 @@ final class HigherOrderExpectation
|
||||
use Expectable;
|
||||
use RetrievesValues;
|
||||
|
||||
/**
|
||||
* @var Expectation
|
||||
*/
|
||||
private $original;
|
||||
private Expectation|Each $expectation;
|
||||
|
||||
/**
|
||||
* @var Expectation|Each
|
||||
*/
|
||||
private $expectation;
|
||||
private bool $opposite = false;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $opposite = false;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $shouldReset = false;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $name;
|
||||
private bool $shouldReset = false;
|
||||
|
||||
/**
|
||||
* Creates a new higher order expectation.
|
||||
*
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function __construct(Expectation $original, $value)
|
||||
public function __construct(private Expectation $original, mixed $value)
|
||||
{
|
||||
$this->original = $original;
|
||||
$this->expectation = $this->expect($value);
|
||||
}
|
||||
|
||||
@ -72,7 +50,7 @@ final class HigherOrderExpectation
|
||||
*
|
||||
* @return Expectation<TValue>
|
||||
*/
|
||||
public function and($value): Expectation
|
||||
public function and(mixed $value): Expectation
|
||||
{
|
||||
return $this->expect($value);
|
||||
}
|
||||
@ -118,10 +96,8 @@ final class HigherOrderExpectation
|
||||
|
||||
/**
|
||||
* Retrieve the applicable value based on the current reset condition.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
private function getValue()
|
||||
private function getValue(): mixed
|
||||
{
|
||||
return $this->shouldReset ? $this->original->value : $this->expectation->value;
|
||||
}
|
||||
|
||||
@ -16,7 +16,6 @@ use function class_exists;
|
||||
use DOMDocument;
|
||||
use DOMElement;
|
||||
use Exception;
|
||||
use function get_class;
|
||||
use function method_exists;
|
||||
use Pest\Concerns\Testable;
|
||||
use PHPUnit\Framework\AssertionFailedError;
|
||||
@ -42,65 +41,50 @@ use function trim;
|
||||
*/
|
||||
final class JUnit extends Printer implements TestListener
|
||||
{
|
||||
/**
|
||||
* @var DOMDocument
|
||||
*/
|
||||
private $document;
|
||||
private DOMDocument $document;
|
||||
|
||||
private DOMElement $root;
|
||||
|
||||
/**
|
||||
* @var DOMElement
|
||||
* @var array<int, DOMElement>
|
||||
*/
|
||||
private $root;
|
||||
|
||||
/**
|
||||
* @var DOMElement[]
|
||||
*/
|
||||
private $testSuites = [];
|
||||
private array $testSuites = [];
|
||||
|
||||
/**
|
||||
* @var int[]
|
||||
*/
|
||||
private $testSuiteTests = [0];
|
||||
private array $testSuiteTests = [0];
|
||||
|
||||
/**
|
||||
* @var int[]
|
||||
*/
|
||||
private $testSuiteAssertions = [0];
|
||||
private array $testSuiteAssertions = [0];
|
||||
|
||||
/**
|
||||
* @var int[]
|
||||
*/
|
||||
private $testSuiteErrors = [0];
|
||||
private array $testSuiteErrors = [0];
|
||||
|
||||
/**
|
||||
* @var int[]
|
||||
*/
|
||||
private $testSuiteWarnings = [0];
|
||||
private array $testSuiteWarnings = [0];
|
||||
|
||||
/**
|
||||
* @var int[]
|
||||
*/
|
||||
private $testSuiteFailures = [0];
|
||||
private array $testSuiteFailures = [0];
|
||||
|
||||
/**
|
||||
* @var int[]
|
||||
*/
|
||||
private $testSuiteSkipped = [0];
|
||||
private array $testSuiteSkipped = [0];
|
||||
|
||||
/**
|
||||
* @var int[]|float[]
|
||||
*/
|
||||
private $testSuiteTimes = [0];
|
||||
private array $testSuiteTimes = [0];
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $testSuiteLevel = 0;
|
||||
private int $testSuiteLevel = 0;
|
||||
|
||||
/**
|
||||
* @var DOMElement|null
|
||||
*/
|
||||
private $currentTestCase;
|
||||
private ?DOMElement $currentTestCase = null;
|
||||
|
||||
public function __construct(string $out)
|
||||
{
|
||||
@ -190,7 +174,7 @@ final class JUnit extends Printer implements TestListener
|
||||
}
|
||||
|
||||
$testSuite->setAttribute('file', $fileName);
|
||||
} catch (ReflectionException $e) {
|
||||
} catch (ReflectionException) {
|
||||
// @ignoreException
|
||||
}
|
||||
}
|
||||
@ -313,7 +297,7 @@ final class JUnit extends Printer implements TestListener
|
||||
$testCase->setAttribute('class', $test->getPrintableTestCaseName());
|
||||
$testCase->setAttribute('classname', str_replace('\\', '.', $test->getPrintableTestCaseName()));
|
||||
// @phpstan-ignore-next-line
|
||||
$testCase->setAttribute('file', $test->__getFileName());
|
||||
$testCase->setAttribute('file', $test->__getFilename());
|
||||
}
|
||||
|
||||
$this->currentTestCase = $testCase;
|
||||
@ -409,7 +393,7 @@ final class JUnit extends Printer implements TestListener
|
||||
if ($t instanceof ExceptionWrapper) {
|
||||
$fault->setAttribute('type', $t->getClassName());
|
||||
} else {
|
||||
$fault->setAttribute('type', get_class($t));
|
||||
$fault->setAttribute('type', $t::class);
|
||||
}
|
||||
|
||||
$this->currentTestCase->appendChild($fault);
|
||||
|
||||
@ -16,9 +16,9 @@ use PHPUnit\Framework\TestResult;
|
||||
use PHPUnit\Framework\TestSuite;
|
||||
use PHPUnit\Framework\Warning;
|
||||
use PHPUnit\TextUI\DefaultResultPrinter;
|
||||
use PHPUnit\TextUI\XmlConfiguration\Logging\TeamCity as BaseTeamCity;
|
||||
use function round;
|
||||
use function str_replace;
|
||||
use function strlen;
|
||||
use Throwable;
|
||||
|
||||
final class TeamCity extends DefaultResultPrinter
|
||||
@ -34,22 +34,19 @@ final class TeamCity extends DefaultResultPrinter
|
||||
private const TEST_STARTED = 'testStarted';
|
||||
private const TEST_FINISHED = 'testFinished';
|
||||
|
||||
/** @var int */
|
||||
private $flowId;
|
||||
private ?int $flowId = null;
|
||||
|
||||
/** @var bool */
|
||||
private $isSummaryTestCountPrinted = false;
|
||||
private bool $isSummaryTestCountPrinted = false;
|
||||
|
||||
/** @var \PHPUnit\Util\Log\TeamCity */
|
||||
private $phpunitTeamCity;
|
||||
private BaseTeamCity $phpunitTeamCity;
|
||||
|
||||
/**
|
||||
* @param resource|string|null $out
|
||||
* Creates a new printer instance.
|
||||
*/
|
||||
public function __construct($out, bool $verbose, string $colors)
|
||||
public function __construct(resource|string|null $out, bool $verbose, string $colors)
|
||||
{
|
||||
parent::__construct($out, $verbose, $colors);
|
||||
$this->phpunitTeamCity = new \PHPUnit\Util\Log\TeamCity($out, $verbose, $colors);
|
||||
$this->phpunitTeamCity = new BaseTeamCity($out, $verbose, $colors);
|
||||
|
||||
$this->logo();
|
||||
}
|
||||
@ -74,9 +71,7 @@ final class TeamCity extends DefaultResultPrinter
|
||||
'passed' => ['count' => $this->successfulTestCount($result), 'color' => 'fg-green'],
|
||||
];
|
||||
|
||||
$filteredResults = array_filter($results, function ($item): bool {
|
||||
return $item['count'] > 0;
|
||||
});
|
||||
$filteredResults = array_filter($results, fn ($item): bool => $item['count'] > 0);
|
||||
|
||||
foreach ($filteredResults as $key => $info) {
|
||||
$this->writeWithColor($info['color'], $info['count'] . " $key", false);
|
||||
@ -203,7 +198,7 @@ final class TeamCity extends DefaultResultPrinter
|
||||
*/
|
||||
private static function isPestTestSuite(TestSuite $suite): bool
|
||||
{
|
||||
return strncmp($suite->getName(), 'P\\', strlen('P\\')) === 0;
|
||||
return str_starts_with($suite->getName(), 'P\\');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -14,17 +14,12 @@ use SebastianBergmann\Exporter\Exporter;
|
||||
*/
|
||||
final class OppositeExpectation
|
||||
{
|
||||
/**
|
||||
* @var Expectation
|
||||
*/
|
||||
private $original;
|
||||
|
||||
/**
|
||||
* Creates a new opposite expectation.
|
||||
*/
|
||||
public function __construct(Expectation $original)
|
||||
public function __construct(private Expectation $original)
|
||||
{
|
||||
$this->original = $original;
|
||||
// ..
|
||||
}
|
||||
|
||||
/**
|
||||
@ -37,7 +32,7 @@ final class OppositeExpectation
|
||||
foreach ($keys as $key) {
|
||||
try {
|
||||
$this->original->toHaveKey($key);
|
||||
} catch (ExpectationFailedException $e) {
|
||||
} catch (ExpectationFailedException) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -57,7 +52,7 @@ final class OppositeExpectation
|
||||
try {
|
||||
/* @phpstan-ignore-next-line */
|
||||
$this->original->{$name}(...$arguments);
|
||||
} catch (ExpectationFailedException $e) {
|
||||
} catch (ExpectationFailedException) {
|
||||
return $this->original;
|
||||
}
|
||||
|
||||
@ -73,7 +68,7 @@ final class OppositeExpectation
|
||||
try {
|
||||
/* @phpstan-ignore-next-line */
|
||||
$this->original->{$name};
|
||||
} catch (ExpectationFailedException $e) {
|
||||
} catch (ExpectationFailedException) {
|
||||
return $this->original;
|
||||
}
|
||||
|
||||
@ -90,10 +85,8 @@ final class OppositeExpectation
|
||||
{
|
||||
$exporter = new Exporter();
|
||||
|
||||
$toString = function ($argument) use ($exporter): string {
|
||||
return $exporter->shortenedExport($argument);
|
||||
};
|
||||
$toString = fn ($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(function ($argument) use ($toString): string { return $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 ($argument): string => $toString($argument), $arguments))));
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,42 +16,24 @@ use Pest\TestSuite;
|
||||
*/
|
||||
final class AfterEachCall
|
||||
{
|
||||
/**
|
||||
* Holds the test suite.
|
||||
*
|
||||
* @var TestSuite
|
||||
*/
|
||||
private $testSuite;
|
||||
|
||||
/**
|
||||
* Holds the filename.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $filename;
|
||||
|
||||
/**
|
||||
* Holds the before each closure.
|
||||
*
|
||||
* @var Closure
|
||||
*/
|
||||
private $closure;
|
||||
private Closure $closure;
|
||||
|
||||
/**
|
||||
* Holds calls that should be proxied.
|
||||
*
|
||||
* @var HigherOrderMessageCollection
|
||||
*/
|
||||
private $proxies;
|
||||
private HigherOrderMessageCollection $proxies;
|
||||
|
||||
/**
|
||||
* Creates a new instance of before each call.
|
||||
*/
|
||||
public function __construct(TestSuite $testSuite, string $filename, Closure $closure = null)
|
||||
{
|
||||
$this->testSuite = $testSuite;
|
||||
$this->filename = $filename;
|
||||
$this->closure = $closure instanceof Closure ? $closure : NullClosure::create();
|
||||
public function __construct(
|
||||
private TestSuite $testSuite,
|
||||
private string $filename, Closure $closure = null
|
||||
) {
|
||||
$this->closure = $closure instanceof Closure ? $closure : NullClosure::create();
|
||||
|
||||
$this->proxies = new HigherOrderMessageCollection();
|
||||
}
|
||||
|
||||
@ -16,42 +16,25 @@ use Pest\TestSuite;
|
||||
*/
|
||||
final class BeforeEachCall
|
||||
{
|
||||
/**
|
||||
* Holds the test suite.
|
||||
*
|
||||
* @var TestSuite
|
||||
*/
|
||||
private $testSuite;
|
||||
|
||||
/**
|
||||
* Holds the filename.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $filename;
|
||||
|
||||
/**
|
||||
* Holds the before each closure.
|
||||
*
|
||||
* @var Closure
|
||||
*/
|
||||
private $closure;
|
||||
private \Closure $closure;
|
||||
|
||||
/**
|
||||
* Holds calls that should be proxied.
|
||||
*
|
||||
* @var HigherOrderMessageCollection
|
||||
*/
|
||||
private $proxies;
|
||||
private HigherOrderMessageCollection $proxies;
|
||||
|
||||
/**
|
||||
* Creates a new instance of before each call.
|
||||
*/
|
||||
public function __construct(TestSuite $testSuite, string $filename, Closure $closure = null)
|
||||
{
|
||||
$this->testSuite = $testSuite;
|
||||
$this->filename = $filename;
|
||||
$this->closure = $closure instanceof Closure ? $closure : NullClosure::create();
|
||||
public function __construct(
|
||||
private TestSuite $testSuite,
|
||||
private string $filename,
|
||||
Closure $closure = null
|
||||
) {
|
||||
$this->closure = $closure instanceof Closure ? $closure : NullClosure::create();
|
||||
|
||||
$this->proxies = new HigherOrderMessageCollection();
|
||||
}
|
||||
|
||||
@ -19,40 +19,30 @@ use SebastianBergmann\Exporter\Exporter;
|
||||
*/
|
||||
final class TestCall
|
||||
{
|
||||
/**
|
||||
* Holds the test suite.
|
||||
*
|
||||
* @readonly
|
||||
*
|
||||
* @var TestSuite
|
||||
*/
|
||||
private $testSuite;
|
||||
|
||||
/**
|
||||
* Holds the test case factory.
|
||||
*
|
||||
* @readonly
|
||||
*
|
||||
* @var TestCaseFactory
|
||||
*/
|
||||
private $testCaseFactory;
|
||||
private TestCaseFactory $testCaseFactory;
|
||||
|
||||
/**
|
||||
* If test call is descriptionLess.
|
||||
*
|
||||
* @readonly
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $descriptionLess = false;
|
||||
private bool $descriptionLess = false;
|
||||
|
||||
/**
|
||||
* Creates a new instance of a pending test call.
|
||||
*/
|
||||
public function __construct(TestSuite $testSuite, string $filename, string $description = null, Closure $closure = null)
|
||||
{
|
||||
public function __construct(
|
||||
private TestSuite $testSuite,
|
||||
string $filename,
|
||||
string $description = null,
|
||||
Closure $closure = null
|
||||
) {
|
||||
$this->testCaseFactory = new TestCaseFactory($filename, $description, $closure);
|
||||
$this->testSuite = $testSuite;
|
||||
$this->descriptionLess = $description === null;
|
||||
}
|
||||
|
||||
@ -83,12 +73,12 @@ final class TestCall
|
||||
*
|
||||
* @param (callable(): bool)|bool $condition
|
||||
*/
|
||||
public function throwsIf($condition, string $exception, string $exceptionMessage = null): TestCall
|
||||
public function throwsIf(callable|bool $condition, string $exception, string $exceptionMessage = null): TestCall
|
||||
{
|
||||
$condition = is_callable($condition)
|
||||
? $condition
|
||||
: static function () use ($condition): bool {
|
||||
return (bool) $condition; // @phpstan-ignore-line
|
||||
return $condition; // @phpstan-ignore-line
|
||||
};
|
||||
|
||||
if ($condition()) {
|
||||
@ -149,10 +139,8 @@ final class TestCall
|
||||
|
||||
/**
|
||||
* Skips the current test.
|
||||
*
|
||||
* @param Closure|bool|string $conditionOrMessage
|
||||
*/
|
||||
public function skip($conditionOrMessage = true, string $message = ''): TestCall
|
||||
public function skip(Closure|bool|string $conditionOrMessage = true, string $message = ''): TestCall
|
||||
{
|
||||
$condition = is_string($conditionOrMessage)
|
||||
? NullClosure::create()
|
||||
@ -160,9 +148,7 @@ final class TestCall
|
||||
|
||||
$condition = is_callable($condition)
|
||||
? $condition
|
||||
: function () use ($condition) { /* @phpstan-ignore-line */
|
||||
return $condition;
|
||||
};
|
||||
: fn () => $condition;
|
||||
|
||||
$message = is_string($conditionOrMessage)
|
||||
? $conditionOrMessage
|
||||
|
||||
@ -24,46 +24,32 @@ final class UsesCall
|
||||
*
|
||||
* @var array<int, Closure>
|
||||
*/
|
||||
private $hooks = [];
|
||||
|
||||
/**
|
||||
* Holds the class and traits.
|
||||
*
|
||||
* @var array<int, string>
|
||||
*/
|
||||
private $classAndTraits;
|
||||
|
||||
/**
|
||||
* Holds the base dirname here the uses call was performed.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $filename;
|
||||
private array $hooks = [];
|
||||
|
||||
/**
|
||||
* Holds the targets of the uses.
|
||||
*
|
||||
* @var array<int, string>
|
||||
*/
|
||||
private $targets;
|
||||
private array $targets;
|
||||
|
||||
/**
|
||||
* Holds the groups of the uses.
|
||||
*
|
||||
* @var array<int, string>
|
||||
*/
|
||||
private $groups = [];
|
||||
private array $groups = [];
|
||||
|
||||
/**
|
||||
* Creates a new instance of a pending test uses.
|
||||
*
|
||||
* @param array<int, string> $classAndTraits
|
||||
*/
|
||||
public function __construct(string $filename, array $classAndTraits)
|
||||
{
|
||||
$this->classAndTraits = $classAndTraits;
|
||||
$this->filename = $filename;
|
||||
$this->targets = [$filename];
|
||||
public function __construct(
|
||||
private string $filename,
|
||||
private array $classAndTraits
|
||||
) {
|
||||
$this->targets = [$filename];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -76,14 +62,12 @@ final class UsesCall
|
||||
$startChar = DIRECTORY_SEPARATOR;
|
||||
|
||||
if ('\\' === DIRECTORY_SEPARATOR || preg_match('~\A[A-Z]:(?![^/\\\\])~i', $path) > 0) {
|
||||
$path = (string) preg_replace_callback('~^(?P<drive>[a-z]+:\\\)~i', function ($match): string {
|
||||
return strtolower($match['drive']);
|
||||
}, $path);
|
||||
$path = (string) preg_replace_callback('~^(?P<drive>[a-z]+:\\\)~i', fn ($match): string => strtolower($match['drive']), $path);
|
||||
|
||||
$startChar = strtolower((string) preg_replace('~^([a-z]+:\\\).*$~i', '$1', __DIR__));
|
||||
}
|
||||
|
||||
return 0 === strpos($path, $startChar)
|
||||
return str_starts_with($path, $startChar)
|
||||
? $path
|
||||
: implode(DIRECTORY_SEPARATOR, [
|
||||
dirname($this->filename),
|
||||
|
||||
@ -14,7 +14,7 @@ final class Plugin
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public static $callables = [];
|
||||
public static array $callables = [];
|
||||
|
||||
/**
|
||||
* Lazy loads an `uses` call on the context of plugins.
|
||||
|
||||
@ -29,31 +29,30 @@ final class Coverage implements AddsOutput, HandlesArguments
|
||||
|
||||
/**
|
||||
* Whether should show the coverage or not.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $coverage = false;
|
||||
public bool $coverage = false;
|
||||
|
||||
/**
|
||||
* The minimum coverage.
|
||||
*
|
||||
* @var float
|
||||
*/
|
||||
public $coverageMin = 0.0;
|
||||
public float $coverageMin = 0.0;
|
||||
|
||||
/**
|
||||
* @var OutputInterface
|
||||
* Creates a new Plugin instance.
|
||||
*/
|
||||
private $output;
|
||||
|
||||
public function __construct(OutputInterface $output)
|
||||
public function __construct(private OutputInterface $output)
|
||||
{
|
||||
$this->output = $output;
|
||||
// ..
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int, string> $originals
|
||||
*
|
||||
* @return array<int, string>
|
||||
*/
|
||||
public function handleArguments(array $originals): array
|
||||
{
|
||||
$arguments = array_merge([''], 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) {
|
||||
if ($original === sprintf('--%s', $option) || Str::startsWith($original, sprintf('--%s=', $option))) {
|
||||
return true;
|
||||
@ -61,7 +60,7 @@ final class Coverage implements AddsOutput, HandlesArguments
|
||||
}
|
||||
|
||||
return false;
|
||||
})));
|
||||
}))];
|
||||
|
||||
$originals = array_flip($originals);
|
||||
foreach ($arguments as $argument) {
|
||||
@ -75,9 +74,9 @@ final class Coverage implements AddsOutput, HandlesArguments
|
||||
|
||||
$input = new ArgvInput($arguments, new InputDefinition($inputs));
|
||||
if ((bool) $input->getOption(self::COVERAGE_OPTION)) {
|
||||
$this->coverage = true;
|
||||
$originals[] = '--coverage-php';
|
||||
$originals[] = \Pest\Support\Coverage::getPath();
|
||||
$this->coverage = true;
|
||||
$originals[] = '--coverage-php';
|
||||
$originals[] = \Pest\Support\Coverage::getPath();
|
||||
}
|
||||
|
||||
if ($input->getOption(self::MIN_OPTION) !== null) {
|
||||
|
||||
@ -21,17 +21,10 @@ final class Environment implements HandlesArguments
|
||||
*/
|
||||
public const LOCAL = 'local';
|
||||
|
||||
/**
|
||||
* @var \Pest\Plugins\Environment|null
|
||||
*/
|
||||
private static $instance;
|
||||
|
||||
/**
|
||||
* The current environment.
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
private static $name;
|
||||
private static ?string $name = null;
|
||||
|
||||
/**
|
||||
* Allows to handle custom command line arguments.
|
||||
|
||||
@ -28,23 +28,14 @@ final class Init implements HandlesArguments
|
||||
'ExampleTest.php' => 'tests/ExampleTest.php',
|
||||
];
|
||||
|
||||
/**
|
||||
* @var OutputInterface
|
||||
*/
|
||||
private $output;
|
||||
|
||||
/**
|
||||
* @var TestSuite
|
||||
*/
|
||||
private $testSuite;
|
||||
|
||||
/**
|
||||
* Creates a new Plugin instance.
|
||||
*/
|
||||
public function __construct(TestSuite $testSuite, OutputInterface $output)
|
||||
{
|
||||
$this->testSuite = $testSuite;
|
||||
$this->output = $output;
|
||||
public function __construct(
|
||||
private TestSuite $testSuite,
|
||||
private OutputInterface $output
|
||||
) {
|
||||
// ..
|
||||
}
|
||||
|
||||
public function handleArguments(array $arguments): array
|
||||
|
||||
@ -13,17 +13,13 @@ use Symfony\Component\Console\Output\OutputInterface;
|
||||
*/
|
||||
final class Version implements HandlesArguments
|
||||
{
|
||||
/**
|
||||
* @var OutputInterface
|
||||
*/
|
||||
private $output;
|
||||
|
||||
/**
|
||||
* Creates a new instance of the plugin.
|
||||
*/
|
||||
public function __construct(OutputInterface $output)
|
||||
{
|
||||
$this->output = $output;
|
||||
public function __construct(
|
||||
private OutputInterface $output
|
||||
) {
|
||||
// ..
|
||||
}
|
||||
|
||||
public function handleArguments(array $arguments): array
|
||||
|
||||
@ -17,7 +17,7 @@ final class AfterAllRepository
|
||||
/**
|
||||
* @var array<string, Closure>
|
||||
*/
|
||||
private $state = [];
|
||||
private array $state = [];
|
||||
|
||||
/**
|
||||
* Runs the given closure for each after all.
|
||||
|
||||
@ -18,7 +18,7 @@ final class AfterEachRepository
|
||||
/**
|
||||
* @var array<string, Closure>
|
||||
*/
|
||||
private $state = [];
|
||||
private array $state = [];
|
||||
|
||||
/**
|
||||
* Sets a after each closure.
|
||||
|
||||
@ -17,7 +17,7 @@ final class BeforeAllRepository
|
||||
/**
|
||||
* @var array<string, Closure>
|
||||
*/
|
||||
private $state = [];
|
||||
private array $state = [];
|
||||
|
||||
/**
|
||||
* Runs one before all closure, and unsets it from the repository.
|
||||
|
||||
@ -16,7 +16,7 @@ final class BeforeEachRepository
|
||||
/**
|
||||
* @var array<string, Closure>
|
||||
*/
|
||||
private $state = [];
|
||||
private array $state = [];
|
||||
|
||||
/**
|
||||
* Sets a before each closure.
|
||||
|
||||
@ -30,12 +30,12 @@ final class TestRepository
|
||||
/**
|
||||
* @var array<string, TestCaseFactory>
|
||||
*/
|
||||
private $state = [];
|
||||
private array $state = [];
|
||||
|
||||
/**
|
||||
* @var array<string, array<int, array<int, string|Closure>>>
|
||||
*/
|
||||
private $uses = [];
|
||||
private array $uses = [];
|
||||
|
||||
/**
|
||||
* Counts the number of test cases.
|
||||
@ -54,9 +54,7 @@ final class TestRepository
|
||||
{
|
||||
$testsWithOnly = $this->testsUsingOnly();
|
||||
|
||||
return array_values(array_map(function (TestCaseFactory $factory): string {
|
||||
return $factory->filename;
|
||||
}, count($testsWithOnly) > 0 ? $testsWithOnly : $this->state));
|
||||
return array_values(array_map(fn (TestCaseFactory $factory): string => $factory->filename, count($testsWithOnly) > 0 ? $testsWithOnly : $this->state));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -64,9 +62,7 @@ final class TestRepository
|
||||
*/
|
||||
public function build(TestSuite $testSuite, callable $each): void
|
||||
{
|
||||
$startsWith = function (string $target, string $directory): bool {
|
||||
return Str::startsWith($target, $directory . DIRECTORY_SEPARATOR);
|
||||
};
|
||||
$startsWith = fn (string $target, string $directory): bool => Str::startsWith($target, $directory . DIRECTORY_SEPARATOR);
|
||||
|
||||
foreach ($this->uses as $path => $uses) {
|
||||
[$classOrTraits, $groups, $hooks] = $uses;
|
||||
@ -123,9 +119,7 @@ final class TestRepository
|
||||
return [];
|
||||
}
|
||||
|
||||
return array_filter($this->state, function ($testFactory): bool {
|
||||
return $testFactory->only;
|
||||
});
|
||||
return array_filter($this->state, fn ($testFactory): bool => $testFactory->only);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -147,8 +141,8 @@ final class TestRepository
|
||||
foreach ($paths as $path) {
|
||||
if (array_key_exists($path, $this->uses)) {
|
||||
$this->uses[$path] = [
|
||||
array_merge($this->uses[$path][0], $classOrTraits),
|
||||
array_merge($this->uses[$path][1], $groups),
|
||||
[...$this->uses[$path][0], ...$classOrTraits],
|
||||
[...$this->uses[$path][1], ...$groups],
|
||||
$this->uses[$path][2] + $hooks, // NOTE: array_merge will destroy numeric indices
|
||||
];
|
||||
} else {
|
||||
|
||||
@ -17,6 +17,6 @@ final class EnsureConfigurationDefaults implements ConfiguredSubscriber
|
||||
*/
|
||||
public function notify(Configured $event): void
|
||||
{
|
||||
$configuration = $event->configuration();
|
||||
// TODO...
|
||||
}
|
||||
}
|
||||
|
||||
@ -18,7 +18,7 @@ final class EnsureTestsAreLoaded implements LoadedSubscriber
|
||||
/**
|
||||
* The current test suite, if any.
|
||||
*/
|
||||
private static ?TestSuite $testSuite;
|
||||
private static ?TestSuite $testSuite = null;
|
||||
|
||||
/**
|
||||
* Runs the subscriber.
|
||||
@ -31,7 +31,7 @@ final class EnsureTestsAreLoaded implements LoadedSubscriber
|
||||
|
||||
$testSuite = \Pest\TestSuite::getInstance();
|
||||
$testSuite->tests->build($testSuite, function (TestCase $testCase) use (&$testSuites): void {
|
||||
$testCaseClass = get_class($testCase);
|
||||
$testCaseClass = $testCase::class;
|
||||
if (!array_key_exists($testCaseClass, $testSuites)) {
|
||||
$testSuites[$testCaseClass] = [];
|
||||
}
|
||||
|
||||
@ -15,9 +15,8 @@ final class Arr
|
||||
{
|
||||
/**
|
||||
* @param array<mixed> $array
|
||||
* @param string|int $key
|
||||
*/
|
||||
public static function has(array $array, $key): bool
|
||||
public static function has(array $array, string|int $key): bool
|
||||
{
|
||||
$key = (string) $key;
|
||||
|
||||
@ -38,12 +37,11 @@ final class Arr
|
||||
|
||||
/**
|
||||
* @param array<mixed> $array
|
||||
* @param string|int $key
|
||||
* @param null $default
|
||||
*
|
||||
* @return array|mixed|null
|
||||
*/
|
||||
public static function get(array $array, $key, $default = null)
|
||||
public static function get(array $array, string|int $key, $default = null)
|
||||
{
|
||||
$key = (string) $key;
|
||||
|
||||
@ -51,7 +49,7 @@ final class Arr
|
||||
return $array[$key];
|
||||
}
|
||||
|
||||
if (strpos($key, '.') === false) {
|
||||
if (!str_contains($key, '.')) {
|
||||
return $array[$key] ?? $default;
|
||||
}
|
||||
|
||||
|
||||
@ -26,7 +26,6 @@ final class Backtrace
|
||||
$current = null;
|
||||
|
||||
foreach (debug_backtrace(self::BACKTRACE_OPTIONS) as $trace) {
|
||||
|
||||
if (Str::endsWith($trace[self::FILE], 'overrides/Runner/TestSuiteLoader.php')) {
|
||||
break;
|
||||
}
|
||||
|
||||
@ -18,9 +18,9 @@ final class ChainableClosure
|
||||
{
|
||||
return function () use ($closure, $next): void {
|
||||
/* @phpstan-ignore-next-line */
|
||||
call_user_func_array(Closure::bind($closure, $this, get_class($this)), func_get_args());
|
||||
call_user_func_array(Closure::bind($closure, $this, $this::class), func_get_args());
|
||||
/* @phpstan-ignore-next-line */
|
||||
call_user_func_array(Closure::bind($next, $this, get_class($this)), func_get_args());
|
||||
call_user_func_array(Closure::bind($next, $this, $this::class), func_get_args());
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -13,15 +13,12 @@ use ReflectionParameter;
|
||||
*/
|
||||
final class Container
|
||||
{
|
||||
/**
|
||||
* @var self
|
||||
*/
|
||||
private static $instance;
|
||||
private static ?Container $instance = null;
|
||||
|
||||
/**
|
||||
* @var array<string, mixed>
|
||||
*/
|
||||
private $instances = [];
|
||||
private array $instances = [];
|
||||
|
||||
/**
|
||||
* Gets a new or already existing container.
|
||||
|
||||
@ -162,7 +162,7 @@ final class Coverage
|
||||
|
||||
$lastKey = count($array) - 1;
|
||||
|
||||
if (array_key_exists($lastKey, $array) && strpos($array[$lastKey], '..') !== false) {
|
||||
if (array_key_exists($lastKey, $array) && str_contains($array[$lastKey], '..')) {
|
||||
[$from] = explode('..', $array[$lastKey]);
|
||||
$array[$lastKey] = $line > $from ? sprintf('%s..%s', $from, $line) : sprintf('%s..%s', $line, $from);
|
||||
|
||||
|
||||
@ -8,19 +8,13 @@ use Closure;
|
||||
|
||||
final class Extendable
|
||||
{
|
||||
/**
|
||||
* The extendable class.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $extendableClass;
|
||||
|
||||
/**
|
||||
* Creates a new extendable instance.
|
||||
*/
|
||||
public function __construct(string $extendableClass)
|
||||
{
|
||||
$this->extendableClass = $extendableClass;
|
||||
public function __construct(
|
||||
private string $extendableClass
|
||||
) {
|
||||
// ..
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -6,8 +6,6 @@ namespace Pest\Support;
|
||||
|
||||
use Closure;
|
||||
use Pest\Expectation;
|
||||
use Pest\PendingObjects\TestCall;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
@ -15,13 +13,11 @@ use PHPUnit\Framework\TestCase;
|
||||
final class HigherOrderCallables
|
||||
{
|
||||
/**
|
||||
* @var object
|
||||
* Creates a new Higher Order Callables instances.
|
||||
*/
|
||||
private $target;
|
||||
|
||||
public function __construct(object $target)
|
||||
public function __construct(private object $target)
|
||||
{
|
||||
$this->target = $target;
|
||||
// ..
|
||||
}
|
||||
|
||||
/**
|
||||
@ -33,7 +29,7 @@ final class HigherOrderCallables
|
||||
*
|
||||
* @return Expectation<TValue>
|
||||
*/
|
||||
public function expect($value)
|
||||
public function expect(mixed $value): Expectation
|
||||
{
|
||||
return new Expectation($value instanceof Closure ? Reflection::bindCallableWithData($value) : $value);
|
||||
}
|
||||
@ -47,17 +43,15 @@ final class HigherOrderCallables
|
||||
*
|
||||
* @return Expectation<TValue>
|
||||
*/
|
||||
public function and($value)
|
||||
public function and(mixed $value)
|
||||
{
|
||||
return $this->expect($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tap into the test case to perform an action and return the test case.
|
||||
*
|
||||
* @return TestCall|TestCase|object
|
||||
*/
|
||||
public function tap(callable $callable)
|
||||
public function tap(callable $callable): object
|
||||
{
|
||||
Reflection::bindCallableWithData($callable);
|
||||
|
||||
|
||||
@ -15,68 +15,31 @@ final class HigherOrderMessage
|
||||
{
|
||||
public const UNDEFINED_METHOD = 'Method %s does not exist';
|
||||
|
||||
/**
|
||||
* The filename where the function was originally called.
|
||||
*
|
||||
* @readonly
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $filename;
|
||||
|
||||
/**
|
||||
* The line where the function was originally called.
|
||||
*
|
||||
* @readonly
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $line;
|
||||
|
||||
/**
|
||||
* The method or property name to access.
|
||||
*
|
||||
* @readonly
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $name;
|
||||
|
||||
/**
|
||||
* The arguments.
|
||||
*
|
||||
* @var array<int, mixed>|null
|
||||
*
|
||||
* @readonly
|
||||
*/
|
||||
public $arguments;
|
||||
|
||||
/**
|
||||
* An optional condition that will determine if the message will be executed.
|
||||
*
|
||||
* @var callable(): bool|null
|
||||
* @var (callable(): bool)|null
|
||||
*/
|
||||
public $condition = null;
|
||||
public $condition;
|
||||
|
||||
/**
|
||||
* Creates a new higher order message.
|
||||
*
|
||||
* @param array<int, mixed>|null $arguments
|
||||
*/
|
||||
public function __construct(string $filename, int $line, string $methodName, $arguments)
|
||||
{
|
||||
$this->filename = $filename;
|
||||
$this->line = $line;
|
||||
$this->name = $methodName;
|
||||
$this->arguments = $arguments;
|
||||
public function __construct(
|
||||
public string $filename,
|
||||
public int $line,
|
||||
public string $name,
|
||||
public ?array $arguments
|
||||
) {
|
||||
// ..
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-throws the given `$throwable` with the good line and filename.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function call(object $target)
|
||||
public function call(object $target): mixed
|
||||
{
|
||||
/* @phpstan-ignore-next-line */
|
||||
if (is_callable($this->condition) && call_user_func(Closure::bind($this->condition, $target)) === false) {
|
||||
@ -91,7 +54,8 @@ final class HigherOrderMessage
|
||||
try {
|
||||
return is_array($this->arguments)
|
||||
? Reflection::call($target, $this->name, $this->arguments)
|
||||
: $target->{$this->name}; /* @phpstan-ignore-line */
|
||||
: $target->{$this->name};
|
||||
/* @phpstan-ignore-line */
|
||||
} catch (Throwable $throwable) {
|
||||
Reflection::setPropertyValue($throwable, 'file', $this->filename);
|
||||
Reflection::setPropertyValue($throwable, 'line', $this->line);
|
||||
@ -122,10 +86,8 @@ final class HigherOrderMessage
|
||||
|
||||
/**
|
||||
* Determines whether or not there exists a higher order callable with the message name.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function hasHigherOrderCallable()
|
||||
private function hasHigherOrderCallable(): bool
|
||||
{
|
||||
return in_array($this->name, get_class_methods(HigherOrderCallables::class), true);
|
||||
}
|
||||
@ -133,7 +95,7 @@ final class HigherOrderMessage
|
||||
private static function getUndefinedMethodMessage(object $target, string $methodName): string
|
||||
{
|
||||
if (\PHP_MAJOR_VERSION >= 8) {
|
||||
return sprintf(sprintf(self::UNDEFINED_METHOD, sprintf('%s::%s()', get_class($target), $methodName)));
|
||||
return sprintf(sprintf(self::UNDEFINED_METHOD, sprintf('%s::%s()', $target::class, $methodName)));
|
||||
}
|
||||
|
||||
return sprintf(self::UNDEFINED_METHOD, $methodName);
|
||||
|
||||
@ -12,7 +12,7 @@ final class HigherOrderMessageCollection
|
||||
/**
|
||||
* @var array<int, HigherOrderMessage>
|
||||
*/
|
||||
private $messages = [];
|
||||
private array $messages = [];
|
||||
|
||||
/**
|
||||
* Adds a new higher order message to the collection.
|
||||
@ -63,9 +63,7 @@ final class HigherOrderMessageCollection
|
||||
{
|
||||
return array_reduce(
|
||||
$this->messages,
|
||||
static function (int $total, HigherOrderMessage $message) use ($name): int {
|
||||
return $total + (int) ($name === $message->name);
|
||||
},
|
||||
static fn (int $total, HigherOrderMessage $message): int => $total + (int) ($name === $message->name),
|
||||
0,
|
||||
);
|
||||
}
|
||||
|
||||
@ -15,19 +15,13 @@ final class HigherOrderTapProxy
|
||||
{
|
||||
private const UNDEFINED_PROPERTY = 'Undefined property: P\\';
|
||||
|
||||
/**
|
||||
* The target being tapped.
|
||||
*
|
||||
* @var TestCase
|
||||
*/
|
||||
public $target;
|
||||
|
||||
/**
|
||||
* Create a new tap proxy instance.
|
||||
*/
|
||||
public function __construct(TestCase $target)
|
||||
{
|
||||
$this->target = $target;
|
||||
public function __construct(
|
||||
public TestCase $target
|
||||
) {
|
||||
// ..
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -193,9 +193,7 @@ final class Reflection
|
||||
}
|
||||
|
||||
$arguments[$parameter->getName()] = implode('|', array_map(
|
||||
static function (ReflectionNamedType $type): string {
|
||||
return $type->getName();
|
||||
},
|
||||
static fn (ReflectionNamedType $type): string => $type->getName(),
|
||||
($types instanceof ReflectionNamedType)
|
||||
? [$types] // NOTE: normalize as list of to handle unions
|
||||
: $types->getTypes(),
|
||||
|
||||
@ -33,7 +33,7 @@ final class Str
|
||||
*/
|
||||
public static function startsWith(string $target, string $search): bool
|
||||
{
|
||||
return substr($target, 0, strlen($search)) === $search;
|
||||
return str_starts_with($target, $search);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -19,71 +19,51 @@ final class TestSuite
|
||||
{
|
||||
/**
|
||||
* Holds the current test case.
|
||||
*
|
||||
* @var TestCase|null
|
||||
*/
|
||||
public $test;
|
||||
public ?TestCase $test = null;
|
||||
|
||||
/**
|
||||
* Holds the tests repository.
|
||||
*
|
||||
* @var TestRepository
|
||||
*/
|
||||
public $tests;
|
||||
public TestRepository $tests;
|
||||
|
||||
/**
|
||||
* Holds the before each repository.
|
||||
*
|
||||
* @var BeforeEachRepository
|
||||
*/
|
||||
public $beforeEach;
|
||||
public BeforeEachRepository $beforeEach;
|
||||
|
||||
/**
|
||||
* Holds the before all repository.
|
||||
*
|
||||
* @var BeforeAllRepository
|
||||
*/
|
||||
public $beforeAll;
|
||||
public BeforeAllRepository $beforeAll;
|
||||
|
||||
/**
|
||||
* Holds the after each repository.
|
||||
*
|
||||
* @var AfterEachRepository
|
||||
*/
|
||||
public $afterEach;
|
||||
public AfterEachRepository $afterEach;
|
||||
|
||||
/**
|
||||
* Holds the after all repository.
|
||||
*
|
||||
* @var AfterAllRepository
|
||||
*/
|
||||
public $afterAll;
|
||||
public AfterAllRepository $afterAll;
|
||||
|
||||
/**
|
||||
* Holds the root path.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $rootPath;
|
||||
|
||||
/**
|
||||
* Holds the test path.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $testPath;
|
||||
public string $rootPath;
|
||||
|
||||
/**
|
||||
* Holds an instance of the test suite.
|
||||
*
|
||||
* @var TestSuite
|
||||
*/
|
||||
private static $instance;
|
||||
private static ?TestSuite $instance = null;
|
||||
|
||||
/**
|
||||
* Creates a new instance of the test suite.
|
||||
*/
|
||||
public function __construct(string $rootPath, string $testPath)
|
||||
public function __construct(string $rootPath, /**
|
||||
* Holds the test path.
|
||||
*/
|
||||
public string $testPath)
|
||||
{
|
||||
$this->beforeAll = new BeforeAllRepository();
|
||||
$this->beforeEach = new BeforeEachRepository();
|
||||
@ -92,7 +72,6 @@ final class TestSuite
|
||||
$this->afterAll = new AfterAllRepository();
|
||||
|
||||
$this->rootPath = (string) realpath($rootPath);
|
||||
$this->testPath = $testPath;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user