Improved generics for higher order

This commit is contained in:
luke
2021-11-27 18:48:58 +00:00
parent c49700dd47
commit beb14ce5f4
9 changed files with 212 additions and 35 deletions

View File

@ -9,7 +9,6 @@ parameters:
- src - src
checkMissingIterableValueType: true checkMissingIterableValueType: true
checkGenericClassInNonGenericObjectType: false
reportUnmatchedIgnoredErrors: true reportUnmatchedIgnoredErrors: true
ignoreErrors: ignoreErrors:

View File

@ -14,6 +14,8 @@ trait RetrievesValues
* *
* Safely retrieve the value at the given key from an object or array. * Safely retrieve the value at the given key from an object or array.
* *
* @template TRetrievableValue
*
* @param array<string, TRetrievableValue>|object $value * @param array<string, TRetrievableValue>|object $value
* @param TRetrievableValue|null $default * @param TRetrievableValue|null $default
* *

View File

@ -7,7 +7,9 @@ namespace Pest;
/** /**
* @internal * @internal
* *
* @mixin Expectation * @template TEachValue
*
* @mixin Expectation<TEachValue>
*/ */
final class Each final class Each
{ {
@ -15,14 +17,21 @@ final class Each
/** /**
* Creates an expectation on each item of the iterable "value". * Creates an expectation on each item of the iterable "value".
*
* @param Expectation<TEachValue> $original
*/ */
public function __construct(private Expectation $original) public function __construct(private Expectation $original)
{ {
// ..
} }
/** /**
* Creates a new expectation. * Creates a new expectation.
*
* @template TValue
*
* @param TValue $value
*
* @return Expectation<TValue>
*/ */
public function and(mixed $value): Expectation public function and(mixed $value): Expectation
{ {
@ -31,6 +40,8 @@ final class Each
/** /**
* Creates the opposite expectation for the value. * Creates the opposite expectation for the value.
*
* @return self<TEachValue>
*/ */
public function not(): Each public function not(): Each
{ {
@ -43,6 +54,8 @@ final class Each
* Dynamically calls methods on the class with the given arguments on each item. * Dynamically calls methods on the class with the given arguments on each item.
* *
* @param array<int|string, mixed> $arguments * @param array<int|string, mixed> $arguments
*
* @return self<TEachValue>
*/ */
public function __call(string $name, array $arguments): Each public function __call(string $name, array $arguments): Each
{ {
@ -58,6 +71,8 @@ final class Each
/** /**
* Dynamically calls methods on the class without any arguments on each item. * Dynamically calls methods on the class without any arguments on each item.
*
* @return self<TEachValue>
*/ */
public function __get(string $name): Each public function __get(string $name): Each
{ {

View File

@ -46,18 +46,18 @@ final class Expectation
* *
* @param TValue $value * @param TValue $value
*/ */
public function __construct( public function __construct(public mixed $value)
public mixed $value {
) {
// ..
} }
/** /**
* Creates a new expectation. * Creates a new expectation.
* *
* @param TValue $value * @template TAndValue
* *
* @return Expectation<TValue> * @param TAndValue $value
*
* @return self<TAndValue>
*/ */
public function and(mixed $value): Expectation public function and(mixed $value): Expectation
{ {
@ -66,6 +66,8 @@ final class Expectation
/** /**
* Creates a new expectation with the decoded JSON value. * Creates a new expectation with the decoded JSON value.
*
* @return self<mixed>
*/ */
public function json(): Expectation public function json(): Expectation
{ {
@ -94,6 +96,8 @@ final class Expectation
/** /**
* Send the expectation value to Ray along with all given arguments. * Send the expectation value to Ray along with all given arguments.
*
* @return self<TValue>
*/ */
public function ray(mixed ...$arguments): self public function ray(mixed ...$arguments): self
{ {
@ -106,6 +110,8 @@ final class Expectation
/** /**
* Creates the opposite expectation for the value. * Creates the opposite expectation for the value.
*
* @return OppositeExpectation<TValue>
*/ */
public function not(): OppositeExpectation public function not(): OppositeExpectation
{ {
@ -114,6 +120,8 @@ final class Expectation
/** /**
* Creates an expectation on each item of the iterable "value". * Creates an expectation on each item of the iterable "value".
*
* @return Each<TValue>
*/ */
public function each(callable $callback = null): Each public function each(callable $callback = null): Each
{ {
@ -135,7 +143,9 @@ final class Expectation
* *
* @template TSequenceValue * @template TSequenceValue
* *
* @param (callable(self, self): void)|TSequenceValue ...$callbacks * @param (callable(self<TValue>, self<string|int>): void)|TSequenceValue ...$callbacks
*
* @return self<TValue>
*/ */
public function sequence(mixed ...$callbacks): Expectation public function sequence(mixed ...$callbacks): Expectation
{ {
@ -177,15 +187,13 @@ final class Expectation
* @template TMatchSubject of array-key * @template TMatchSubject of array-key
* *
* @param (callable(): TMatchSubject)|TMatchSubject $subject * @param (callable(): TMatchSubject)|TMatchSubject $subject
* @param array<TMatchSubject, (callable(Expectation<TValue>): mixed)|TValue> $expressions * @param array<TMatchSubject, (callable(self<TValue>): mixed)|TValue> $expressions
*
* @return self<TValue>
*/ */
public function match(mixed $subject, array $expressions): Expectation public function match(mixed $subject, array $expressions): Expectation
{ {
$subject = is_callable($subject) $subject = $subject instanceof Closure ? $subject() : $subject;
? $subject
: fn () => $subject;
$subject = $subject();
$matched = false; $matched = false;
@ -218,6 +226,8 @@ final class Expectation
* *
* @param (callable(): bool)|bool $condition * @param (callable(): bool)|bool $condition
* @param callable(Expectation<TValue>): mixed $callback * @param callable(Expectation<TValue>): mixed $callback
*
* @return self<TValue>
*/ */
public function unless(callable|bool $condition, callable $callback): Expectation public function unless(callable|bool $condition, callable $callback): Expectation
{ {
@ -234,7 +244,9 @@ final class Expectation
* Apply the callback if the given "condition" is truthy. * 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 * @param callable(self<TValue>): mixed $callback
*
* @return self<TValue>
*/ */
public function when(callable|bool $condition, callable $callback): Expectation public function when(callable|bool $condition, callable $callback): Expectation
{ {
@ -255,6 +267,8 @@ final class Expectation
* Asserts that two variables have the same type and * Asserts that two variables have the same type and
* value. Used on objects, it asserts that two * value. Used on objects, it asserts that two
* variables reference the same object. * variables reference the same object.
*
* @return self<TValue>
*/ */
public function toBe(mixed $expected): Expectation public function toBe(mixed $expected): Expectation
{ {
@ -265,6 +279,8 @@ final class Expectation
/** /**
* Asserts that the value is empty. * Asserts that the value is empty.
*
* @return self<TValue>
*/ */
public function toBeEmpty(): Expectation public function toBeEmpty(): Expectation
{ {
@ -275,6 +291,8 @@ final class Expectation
/** /**
* Asserts that the value is true. * Asserts that the value is true.
*
* @return self<TValue>
*/ */
public function toBeTrue(): Expectation public function toBeTrue(): Expectation
{ {
@ -285,6 +303,8 @@ final class Expectation
/** /**
* Asserts that the value is truthy. * Asserts that the value is truthy.
*
* @return self<TValue>
*/ */
public function toBeTruthy(): Expectation public function toBeTruthy(): Expectation
{ {
@ -295,6 +315,8 @@ final class Expectation
/** /**
* Asserts that the value is false. * Asserts that the value is false.
*
* @return self<TValue>
*/ */
public function toBeFalse(): Expectation public function toBeFalse(): Expectation
{ {
@ -305,6 +327,8 @@ final class Expectation
/** /**
* Asserts that the value is falsy. * Asserts that the value is falsy.
*
* @return self<TValue>
*/ */
public function toBeFalsy(): Expectation public function toBeFalsy(): Expectation
{ {
@ -315,6 +339,8 @@ final class Expectation
/** /**
* Asserts that the value is greater than $expected. * Asserts that the value is greater than $expected.
*
* @return self<TValue>
*/ */
public function toBeGreaterThan(int|float $expected): Expectation public function toBeGreaterThan(int|float $expected): Expectation
{ {
@ -325,6 +351,8 @@ final class Expectation
/** /**
* Asserts that the value is greater than or equal to $expected. * Asserts that the value is greater than or equal to $expected.
*
* @return self<TValue>
*/ */
public function toBeGreaterThanOrEqual(int|float $expected): Expectation public function toBeGreaterThanOrEqual(int|float $expected): Expectation
{ {
@ -335,6 +363,8 @@ final class Expectation
/** /**
* Asserts that the value is less than or equal to $expected. * Asserts that the value is less than or equal to $expected.
*
* @return self<TValue>
*/ */
public function toBeLessThan(int|float $expected): Expectation public function toBeLessThan(int|float $expected): Expectation
{ {
@ -345,6 +375,8 @@ final class Expectation
/** /**
* Asserts that the value is less than $expected. * Asserts that the value is less than $expected.
*
* @return self<TValue>
*/ */
public function toBeLessThanOrEqual(int|float $expected): Expectation public function toBeLessThanOrEqual(int|float $expected): Expectation
{ {
@ -355,6 +387,8 @@ final class Expectation
/** /**
* Asserts that $needle is an element of the value. * Asserts that $needle is an element of the value.
*
* @return self<TValue>
*/ */
public function toContain(mixed ...$needles): Expectation public function toContain(mixed ...$needles): Expectation
{ {
@ -377,6 +411,8 @@ final class Expectation
* Asserts that the value starts with $expected. * Asserts that the value starts with $expected.
* *
* @param non-empty-string $expected * @param non-empty-string $expected
*
* @return self<TValue>
*/ */
public function toStartWith(string $expected): Expectation public function toStartWith(string $expected): Expectation
{ {
@ -393,6 +429,8 @@ final class Expectation
* Asserts that the value ends with $expected. * Asserts that the value ends with $expected.
* *
* @param non-empty-string $expected * @param non-empty-string $expected
*
* @return self<TValue>
*/ */
public function toEndWith(string $expected): Expectation public function toEndWith(string $expected): Expectation
{ {
@ -407,6 +445,8 @@ final class Expectation
/** /**
* Asserts that $number matches value's Length. * Asserts that $number matches value's Length.
*
* @return self<TValue>
*/ */
public function toHaveLength(int $number): Expectation public function toHaveLength(int $number): Expectation
{ {
@ -437,6 +477,8 @@ final class Expectation
/** /**
* Asserts that $count matches the number of elements of the value. * Asserts that $count matches the number of elements of the value.
*
* @return self<TValue>
*/ */
public function toHaveCount(int $count): Expectation public function toHaveCount(int $count): Expectation
{ {
@ -451,6 +493,8 @@ final class Expectation
/** /**
* Asserts that the value contains the property $name. * Asserts that the value contains the property $name.
*
* @return self<TValue>
*/ */
public function toHaveProperty(string $name, mixed $value = null): Expectation public function toHaveProperty(string $name, mixed $value = null): Expectation
{ {
@ -471,6 +515,8 @@ final class Expectation
* Asserts that the value contains the provided properties $names. * Asserts that the value contains the provided properties $names.
* *
* @param iterable<array-key, string> $names * @param iterable<array-key, string> $names
*
* @return self<TValue>
*/ */
public function toHaveProperties(iterable $names): Expectation public function toHaveProperties(iterable $names): Expectation
{ {
@ -483,6 +529,8 @@ final class Expectation
/** /**
* Asserts that two variables have the same value. * Asserts that two variables have the same value.
*
* @return self<TValue>
*/ */
public function toEqual(mixed $expected): Expectation public function toEqual(mixed $expected): Expectation
{ {
@ -499,6 +547,8 @@ final class Expectation
* are sorted before they are compared. When $expected and $this->value * are sorted before they are compared. When $expected and $this->value
* are objects, each object is converted to an array containing all * are objects, each object is converted to an array containing all
* private, protected and public attributes. * private, protected and public attributes.
*
* @return self<TValue>
*/ */
public function toEqualCanonicalizing(mixed $expected): Expectation public function toEqualCanonicalizing(mixed $expected): Expectation
{ {
@ -510,6 +560,8 @@ final class Expectation
/** /**
* Asserts that the absolute difference between the value and $expected * Asserts that the absolute difference between the value and $expected
* is lower than $delta. * is lower than $delta.
*
* @return self<TValue>
*/ */
public function toEqualWithDelta(mixed $expected, float $delta): Expectation public function toEqualWithDelta(mixed $expected, float $delta): Expectation
{ {
@ -522,6 +574,8 @@ final class Expectation
* Asserts that the value is one of the given values. * Asserts that the value is one of the given values.
* *
* @param iterable<int|string, mixed> $values * @param iterable<int|string, mixed> $values
*
* @return self<TValue>
*/ */
public function toBeIn(iterable $values): Expectation public function toBeIn(iterable $values): Expectation
{ {
@ -532,6 +586,8 @@ final class Expectation
/** /**
* Asserts that the value is infinite. * Asserts that the value is infinite.
*
* @return self<TValue>
*/ */
public function toBeInfinite(): Expectation public function toBeInfinite(): Expectation
{ {
@ -544,6 +600,8 @@ final class Expectation
* Asserts that the value is an instance of $class. * Asserts that the value is an instance of $class.
* *
* @param class-string $class * @param class-string $class
*
* @return self<TValue>
*/ */
public function toBeInstanceOf(string $class): Expectation public function toBeInstanceOf(string $class): Expectation
{ {
@ -554,6 +612,8 @@ final class Expectation
/** /**
* Asserts that the value is an array. * Asserts that the value is an array.
*
* @return self<TValue>
*/ */
public function toBeArray(): Expectation public function toBeArray(): Expectation
{ {
@ -564,6 +624,8 @@ final class Expectation
/** /**
* Asserts that the value is of type bool. * Asserts that the value is of type bool.
*
* @return self<TValue>
*/ */
public function toBeBool(): Expectation public function toBeBool(): Expectation
{ {
@ -574,6 +636,8 @@ final class Expectation
/** /**
* Asserts that the value is of type callable. * Asserts that the value is of type callable.
*
* @return self<TValue>
*/ */
public function toBeCallable(): Expectation public function toBeCallable(): Expectation
{ {
@ -584,6 +648,8 @@ final class Expectation
/** /**
* Asserts that the value is of type float. * Asserts that the value is of type float.
*
* @return self<TValue>
*/ */
public function toBeFloat(): Expectation public function toBeFloat(): Expectation
{ {
@ -594,6 +660,8 @@ final class Expectation
/** /**
* Asserts that the value is of type int. * Asserts that the value is of type int.
*
* @return self<TValue>
*/ */
public function toBeInt(): Expectation public function toBeInt(): Expectation
{ {
@ -604,6 +672,8 @@ final class Expectation
/** /**
* Asserts that the value is of type iterable. * Asserts that the value is of type iterable.
*
* @return self<TValue>
*/ */
public function toBeIterable(): Expectation public function toBeIterable(): Expectation
{ {
@ -614,6 +684,8 @@ final class Expectation
/** /**
* Asserts that the value is of type numeric. * Asserts that the value is of type numeric.
*
* @return self<TValue>
*/ */
public function toBeNumeric(): Expectation public function toBeNumeric(): Expectation
{ {
@ -624,6 +696,8 @@ final class Expectation
/** /**
* Asserts that the value is of type object. * Asserts that the value is of type object.
*
* @return self<TValue>
*/ */
public function toBeObject(): Expectation public function toBeObject(): Expectation
{ {
@ -634,6 +708,8 @@ final class Expectation
/** /**
* Asserts that the value is of type resource. * Asserts that the value is of type resource.
*
* @return self<TValue>
*/ */
public function toBeResource(): Expectation public function toBeResource(): Expectation
{ {
@ -644,6 +720,8 @@ final class Expectation
/** /**
* Asserts that the value is of type scalar. * Asserts that the value is of type scalar.
*
* @return self<TValue>
*/ */
public function toBeScalar(): Expectation public function toBeScalar(): Expectation
{ {
@ -654,6 +732,8 @@ final class Expectation
/** /**
* Asserts that the value is of type string. * Asserts that the value is of type string.
*
* @return self<TValue>
*/ */
public function toBeString(): Expectation public function toBeString(): Expectation
{ {
@ -664,6 +744,8 @@ final class Expectation
/** /**
* Asserts that the value is a JSON string. * Asserts that the value is a JSON string.
*
* @return self<TValue>
*/ */
public function toBeJson(): Expectation public function toBeJson(): Expectation
{ {
@ -677,6 +759,8 @@ final class Expectation
/** /**
* Asserts that the value is NAN. * Asserts that the value is NAN.
*
* @return self<TValue>
*/ */
public function toBeNan(): Expectation public function toBeNan(): Expectation
{ {
@ -687,6 +771,8 @@ final class Expectation
/** /**
* Asserts that the value is null. * Asserts that the value is null.
*
* @return self<TValue>
*/ */
public function toBeNull(): Expectation public function toBeNull(): Expectation
{ {
@ -697,6 +783,8 @@ final class Expectation
/** /**
* Asserts that the value array has the provided $key. * Asserts that the value array has the provided $key.
*
* @return self<TValue>
*/ */
public function toHaveKey(string|int $key, mixed $value = null): Expectation public function toHaveKey(string|int $key, mixed $value = null): Expectation
{ {
@ -725,6 +813,8 @@ final class Expectation
* Asserts that the value array has the provided $keys. * Asserts that the value array has the provided $keys.
* *
* @param array<int, int|string> $keys * @param array<int, int|string> $keys
*
* @return self<TValue>
*/ */
public function toHaveKeys(array $keys): Expectation public function toHaveKeys(array $keys): Expectation
{ {
@ -737,6 +827,8 @@ final class Expectation
/** /**
* Asserts that the value is a directory. * Asserts that the value is a directory.
*
* @return self<TValue>
*/ */
public function toBeDirectory(): Expectation public function toBeDirectory(): Expectation
{ {
@ -751,6 +843,8 @@ final class Expectation
/** /**
* Asserts that the value is a directory and is readable. * Asserts that the value is a directory and is readable.
*
* @return self<TValue>
*/ */
public function toBeReadableDirectory(): Expectation public function toBeReadableDirectory(): Expectation
{ {
@ -765,6 +859,8 @@ final class Expectation
/** /**
* Asserts that the value is a directory and is writable. * Asserts that the value is a directory and is writable.
*
* @return self<TValue>
*/ */
public function toBeWritableDirectory(): Expectation public function toBeWritableDirectory(): Expectation
{ {
@ -779,6 +875,8 @@ final class Expectation
/** /**
* Asserts that the value is a file. * Asserts that the value is a file.
*
* @return self<TValue>
*/ */
public function toBeFile(): Expectation public function toBeFile(): Expectation
{ {
@ -793,6 +891,8 @@ final class Expectation
/** /**
* Asserts that the value is a file and is readable. * Asserts that the value is a file and is readable.
*
* @return self<TValue>
*/ */
public function toBeReadableFile(): Expectation public function toBeReadableFile(): Expectation
{ {
@ -807,6 +907,8 @@ final class Expectation
/** /**
* Asserts that the value is a file and is writable. * Asserts that the value is a file and is writable.
*
* @return self<TValue>
*/ */
public function toBeWritableFile(): Expectation public function toBeWritableFile(): Expectation
{ {
@ -822,6 +924,8 @@ final class Expectation
* Asserts that the value array matches the given array subset. * Asserts that the value array matches the given array subset.
* *
* @param iterable<int|string, mixed> $array * @param iterable<int|string, mixed> $array
*
* @return self<TValue>
*/ */
public function toMatchArray(iterable|object $array): Expectation public function toMatchArray(iterable|object $array): Expectation
{ {
@ -853,6 +957,8 @@ final class Expectation
* of the properties of an given object. * of the properties of an given object.
* *
* @param iterable<string, mixed>|object $object * @param iterable<string, mixed>|object $object
*
* @return self<TValue>
*/ */
public function toMatchObject(iterable|object $object): Expectation public function toMatchObject(iterable|object $object): Expectation
{ {
@ -881,6 +987,8 @@ final class Expectation
/** /**
* Asserts that the value matches a regular expression. * Asserts that the value matches a regular expression.
*
* @return self<TValue>
*/ */
public function toMatch(string $expression): Expectation public function toMatch(string $expression): Expectation
{ {
@ -894,6 +1002,8 @@ final class Expectation
/** /**
* Asserts that the value matches a constraint. * Asserts that the value matches a constraint.
*
* @return self<TValue>
*/ */
public function toMatchConstraint(Constraint $constraint): Expectation public function toMatchConstraint(Constraint $constraint): Expectation
{ {
@ -906,6 +1016,8 @@ final class Expectation
* Asserts that executing value throws an exception. * Asserts that executing value throws an exception.
* *
* @param (Closure(Throwable): mixed)|string $exception * @param (Closure(Throwable): mixed)|string $exception
*
* @return self<TValue>
*/ */
public function toThrow(callable|string $exception, string $exceptionMessage = null): Expectation public function toThrow(callable|string $exception, string $exceptionMessage = null): Expectation
{ {
@ -970,7 +1082,7 @@ final class Expectation
* *
* @param array<int, mixed> $parameters * @param array<int, mixed> $parameters
* *
* @return HigherOrderExpectation|mixed * @return HigherOrderExpectation<TValue, mixed>|self<TValue>|mixed
*/ */
public function __call(string $method, array $parameters) public function __call(string $method, array $parameters)
{ {
@ -985,6 +1097,8 @@ final class Expectation
/** /**
* Dynamically calls methods on the class without any arguments * Dynamically calls methods on the class without any arguments
* or creates a new higher order expectation. * or creates a new higher order expectation.
*
* @return self<TValue>|OppositeExpectation<TValue>|Each<TValue>|HigherOrderExpectation<TValue, mixed>
*/ */
public function __get(string $name): Expectation|OppositeExpectation|Each|HigherOrderExpectation public function __get(string $name): Expectation|OppositeExpectation|Each|HigherOrderExpectation
{ {

View File

@ -18,7 +18,11 @@ if (!function_exists('expect')) {
/** /**
* Creates a new expectation. * Creates a new expectation.
* *
* @param mixed $value the Value * @template TValue
*
* @param TValue $value the Value
*
* @return Expectation<TValue>|Extendable
*/ */
function expect($value = null): Expectation|Extendable function expect($value = null): Expectation|Extendable
{ {

View File

@ -4,19 +4,23 @@ declare(strict_types=1);
namespace Pest; namespace Pest;
use Pest\Concerns\Expectable;
use Pest\Concerns\RetrievesValues; use Pest\Concerns\RetrievesValues;
/** /**
* @internal * @internal
* *
* @mixin Expectation * @template TOriginalValue
* @template TValue
*
* @mixin Expectation<TOriginalValue>
*/ */
final class HigherOrderExpectation final class HigherOrderExpectation
{ {
use Expectable;
use RetrievesValues; use RetrievesValues;
/**
* @var Expectation<TValue>|Each<TValue>
*/
private Expectation|Each $expectation; private Expectation|Each $expectation;
private bool $opposite = false; private bool $opposite = false;
@ -25,6 +29,9 @@ final class HigherOrderExpectation
/** /**
* Creates a new higher order expectation. * Creates a new higher order expectation.
*
* @param Expectation<TOriginalValue> $original
* @param TValue $value
*/ */
public function __construct(private Expectation $original, mixed $value) public function __construct(private Expectation $original, mixed $value)
{ {
@ -33,6 +40,8 @@ final class HigherOrderExpectation
/** /**
* Creates the opposite expectation for the value. * Creates the opposite expectation for the value.
*
* @return self<TOriginalValue, TValue>
*/ */
public function not(): HigherOrderExpectation public function not(): HigherOrderExpectation
{ {
@ -41,14 +50,28 @@ final class HigherOrderExpectation
return $this; return $this;
} }
/**
* Creates a new Expectation.
*
* @template TExpectValue
*
* @param TExpectValue $value
*
* @return Expectation<TExpectValue>
*/
public function expect(mixed $value): Expectation
{
return new Expectation($value);
}
/** /**
* Creates a new expectation. * Creates a new expectation.
* *
* @template TValue * @template TExpectValue
* *
* @param TValue $value * @param TExpectValue $value
* *
* @return Expectation<TValue> * @return Expectation<TExpectValue>
*/ */
public function and(mixed $value): Expectation public function and(mixed $value): Expectation
{ {
@ -59,6 +82,8 @@ final class HigherOrderExpectation
* Dynamically calls methods on the class with the given arguments. * Dynamically calls methods on the class with the given arguments.
* *
* @param array<int, mixed> $arguments * @param array<int, mixed> $arguments
*
* @return self<TOriginalValue, mixed>|self<TOriginalValue, TValue>
*/ */
public function __call(string $name, array $arguments): self public function __call(string $name, array $arguments): self
{ {
@ -72,6 +97,8 @@ final class HigherOrderExpectation
/** /**
* Accesses properties in the value or in the expectation. * Accesses properties in the value or in the expectation.
*
* @return self<TOriginalValue, mixed>|self<TOriginalValue, TValue>
*/ */
public function __get(string $name): self public function __get(string $name): self
{ {
@ -99,6 +126,8 @@ final class HigherOrderExpectation
/** /**
* Retrieve the applicable value based on the current reset condition. * Retrieve the applicable value based on the current reset condition.
*
* @return TOriginalValue|TValue
*/ */
private function getValue(): mixed private function getValue(): mixed
{ {
@ -109,6 +138,8 @@ final class HigherOrderExpectation
* Performs the given assertion with the current expectation. * Performs the given assertion with the current expectation.
* *
* @param array<int, mixed> $arguments * @param array<int, mixed> $arguments
*
* @return self<TOriginalValue, TValue>
*/ */
private function performAssertion(string $name, array $arguments): self private function performAssertion(string $name, array $arguments): self
{ {

View File

@ -10,29 +10,34 @@ use SebastianBergmann\Exporter\Exporter;
/** /**
* @internal * @internal
* *
* @mixin Expectation * @template TValue
*
* @mixin Expectation<TValue>
*/ */
final class OppositeExpectation final class OppositeExpectation
{ {
/** /**
* Creates a new opposite expectation. * Creates a new opposite expectation.
*
* @param Expectation<TValue> $original
*/ */
public function __construct(private Expectation $original) public function __construct(private Expectation $original)
{ {
// ..
} }
/** /**
* Asserts that the value array not has the provided $keys. * Asserts that the value array not has the provided $keys.
* *
* @param array<int, int|string> $keys * @param array<int, int|string> $keys
*
* @return Expectation<TValue>
*/ */
public function toHaveKeys(array $keys): Expectation public function toHaveKeys(array $keys): Expectation
{ {
foreach ($keys as $key) { foreach ($keys as $key) {
try { try {
$this->original->toHaveKey($key); $this->original->toHaveKey($key);
} catch (ExpectationFailedException $exception) { } catch (ExpectationFailedException) {
continue; continue;
} }
@ -47,14 +52,14 @@ final class OppositeExpectation
* *
* @param array<int, mixed> $arguments * @param array<int, mixed> $arguments
* *
* @return Expectation|never * @return Expectation<TValue>|Expectation<mixed>|never
*/ */
public function __call(string $name, array $arguments): Expectation public function __call(string $name, array $arguments): Expectation
{ {
try { try {
/* @phpstan-ignore-next-line */ /* @phpstan-ignore-next-line */
$this->original->{$name}(...$arguments); $this->original->{$name}(...$arguments);
} catch (ExpectationFailedException $exception) { } catch (ExpectationFailedException) {
return $this->original; return $this->original;
} }
@ -64,13 +69,13 @@ final class OppositeExpectation
/** /**
* Handle dynamic properties gets into the original expectation. * Handle dynamic properties gets into the original expectation.
* *
* @return Expectation|never * @return Expectation<TValue>|Expectation<mixed>|never
*/ */
public function __get(string $name): Expectation public function __get(string $name): Expectation
{ {
try { try {
$this->original->{$name}; // @phpstan-ignore-line $this->original->{$name}; // @phpstan-ignore-line
} catch (ExpectationFailedException $exception) { // @phpstan-ignore-line } catch (ExpectationFailedException) { // @phpstan-ignore-line
return $this->original; return $this->original;
} }

View File

@ -38,6 +38,10 @@ final class HigherOrderMessage
/** /**
* Re-throws the given `$throwable` with the good line and filename. * Re-throws the given `$throwable` with the good line and filename.
*
* @template TValue of object
*
* @param TValue $target
*/ */
public function call(object $target): mixed public function call(object $target): mixed
{ {
@ -59,7 +63,7 @@ final class HigherOrderMessage
Reflection::setPropertyValue($throwable, 'line', $this->line); Reflection::setPropertyValue($throwable, 'line', $this->line);
if ($throwable->getMessage() === self::getUndefinedMethodMessage($target, $this->name)) { if ($throwable->getMessage() === self::getUndefinedMethodMessage($target, $this->name)) {
/** @var ReflectionClass $reflection */ /** @var ReflectionClass<TValue> $reflection */
$reflection = new ReflectionClass($target); $reflection = new ReflectionClass($target);
/* @phpstan-ignore-next-line */ /* @phpstan-ignore-next-line */
$reflection = $reflection->getParentClass() ?: $reflection; $reflection = $reflection->getParentClass() ?: $reflection;

View File

@ -118,11 +118,14 @@ final class Reflection
/** /**
* Sets the property value of the given object. * Sets the property value of the given object.
* *
* @param mixed $value * @template TValue of object
*
* @param TValue $object
* @param mixed $value
*/ */
public static function setPropertyValue(object $object, string $property, $value): void public static function setPropertyValue(object $object, string $property, $value): void
{ {
/** @var ReflectionClass $reflectionClass */ /** @var ReflectionClass<TValue> $reflectionClass */
$reflectionClass = new ReflectionClass($object); $reflectionClass = new ReflectionClass($object);
$reflectionProperty = null; $reflectionProperty = null;