diff --git a/src/Arguments.php b/src/Arguments.php index 3631d6a..297f587 100644 --- a/src/Arguments.php +++ b/src/Arguments.php @@ -18,6 +18,7 @@ use Chevere\Parameter\Interfaces\ArgumentsInterface; use Chevere\Parameter\Interfaces\CastInterface; use Chevere\Parameter\Interfaces\ParametersInterface; +use Chevere\Parameter\Traits\ExceptionErrorMessageTrait; use InvalidArgumentException; use OutOfBoundsException; use ReflectionClass; @@ -27,6 +28,8 @@ final class Arguments implements ArgumentsInterface { + use ExceptionErrorMessageTrait; + private ParametersInterface $iterable; /** @@ -244,18 +247,20 @@ private function assertArgument(string $name, mixed $argument): void $this->arguments[$name] = $parameter->__invoke($argument); } catch (TypeError $e) { throw new TypeError( - $this->getExceptionMessage($name, $e) + $this->getExceptionPropertyMessage($name, $e) ); } catch (Throwable $e) { throw new InvalidArgumentException( - $this->getExceptionMessage($name, $e) + $this->getExceptionPropertyMessage($name, $e) ); } } - private function getExceptionMessage(string $property, Throwable $e): string + private function getExceptionPropertyMessage(string $property, Throwable $e): string { - return "[{$property}]: {$e->getMessage()}"; + $message = $this->getExceptionMessage($e); + + return "[{$property}]: {$message}"; } private function handleParameters(): void diff --git a/src/IterableParameter.php b/src/IterableParameter.php index e9174d7..c884af2 100644 --- a/src/IterableParameter.php +++ b/src/IterableParameter.php @@ -17,6 +17,7 @@ use Chevere\Parameter\Interfaces\ParameterInterface; use Chevere\Parameter\Interfaces\TypeInterface; use Chevere\Parameter\Traits\ArrayParameterTrait; +use Chevere\Parameter\Traits\ExceptionErrorMessageTrait; use Chevere\Parameter\Traits\ParameterTrait; use InvalidArgumentException; use Throwable; @@ -26,6 +27,7 @@ final class IterableParameter implements IterableParameterInterface { use ParameterTrait; use ArrayParameterTrait; + use ExceptionErrorMessageTrait; /** * @var iterable @@ -56,8 +58,8 @@ public function __invoke(iterable $value): iterable ); } $iterable = ' *iterable'; - $iterableKey = '_K' . $iterable; - $iterableValue = '_V' . $iterable; + $iterableKey = 'K' . $iterable; + $iterableValue = 'V' . $iterable; try { foreach ($value as $k => $v) { @@ -65,17 +67,7 @@ public function __invoke(iterable $value): iterable assertNamedArgument($iterableValue, $this->value, $v); } } catch (Throwable $e) { - $message = $e->getMessage(); - $strstr = strstr($message, ':', false); - if (! is_string($strstr)) { - $strstr = $message; // @codeCoverageIgnore - } else { - $strstr = substr($strstr, 2); - } - $calledIn = strpos($strstr, ', called in'); - $message = $calledIn - ? substr($strstr, 0, $calledIn) - : $strstr; + $message = $this->getExceptionMessage($e, ': '); throw new InvalidArgumentException($message); } diff --git a/src/ReflectionParameterTyped.php b/src/ReflectionParameterTyped.php index 9f69f7b..fcdb3ef 100644 --- a/src/ReflectionParameterTyped.php +++ b/src/ReflectionParameterTyped.php @@ -39,6 +39,7 @@ public function __construct( $attribute = reflectedParameterAttribute($reflection); $parameter = $attribute->parameter(); } catch (Throwable) { + // Do nothing } if ($this->reflection->isDefaultValueAvailable() && method_exists($parameter, 'withDefault') diff --git a/src/Traits/ExceptionErrorMessageTrait.php b/src/Traits/ExceptionErrorMessageTrait.php new file mode 100644 index 0000000..ba40ee7 --- /dev/null +++ b/src/Traits/ExceptionErrorMessageTrait.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Chevere\Parameter\Traits; + +use Throwable; + +trait ExceptionErrorMessageTrait +{ + private function getExceptionMessage( + Throwable $e, + string $needle = '::__invoke(): ', + ): string { + $message = $e->getMessage(); + $strstr = strstr($message, $needle, false); + if (! is_string($strstr)) { + $strstr = $message; // @codeCoverageIgnore + } else { + $strstr = substr($strstr, strlen($needle)); + } + $calledIn = strpos($strstr, ', called in'); + + return $calledIn + ? substr($strstr, 0, $calledIn) + : $strstr; + } +} diff --git a/src/UnionParameter.php b/src/UnionParameter.php index 5fa3f7b..a0029e8 100644 --- a/src/UnionParameter.php +++ b/src/UnionParameter.php @@ -18,8 +18,8 @@ use Chevere\Parameter\Interfaces\TypeInterface; use Chevere\Parameter\Interfaces\UnionParameterInterface; use Chevere\Parameter\Traits\ArrayParameterTrait; +use Chevere\Parameter\Traits\ExceptionErrorMessageTrait; use Chevere\Parameter\Traits\ParameterAssertArrayTypeTrait; -use Chevere\Parameter\Traits\ParameterErrorMessageTrait; use Chevere\Parameter\Traits\ParameterTrait; use InvalidArgumentException; use LogicException; @@ -31,7 +31,7 @@ final class UnionParameter implements UnionParameterInterface use ParameterTrait; use ArrayParameterTrait; use ParameterAssertArrayTypeTrait; - use ParameterErrorMessageTrait; + use ExceptionErrorMessageTrait; private mixed $default = null; @@ -113,17 +113,7 @@ private function getParameterError( Throwable $e ): string { $type = $parameter::class; - $message = $e->getMessage(); - $strstr = strstr($message, '::__invoke():', false); - if (! is_string($strstr)) { - $message = $message; // @codeCoverageIgnore - } else { - $message = substr($strstr, 14); - } - $calledIn = strpos($message, ', called in'); - $message = $calledIn - ? substr($message, 0, $calledIn) - : $message; + $message = $this->getExceptionMessage($e); return <<: {$message} diff --git a/tests/ArgumentsIterableTest.php b/tests/ArgumentsIterableTest.php index 44d60da..988d2b8 100644 --- a/tests/ArgumentsIterableTest.php +++ b/tests/ArgumentsIterableTest.php @@ -206,7 +206,7 @@ public function testIterableArrayConflict(array $args): void K: string() ); $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessageMatches('/^\[_V \*iterable\]\:.*/'); + $this->expectExceptionMessageMatches('/^\[V \*iterable\]\:.*/'); $parameter($args); } } diff --git a/tests/ArrayParameterTest.php b/tests/ArrayParameterTest.php index 406105c..a325762 100644 --- a/tests/ArrayParameterTest.php +++ b/tests/ArrayParameterTest.php @@ -13,6 +13,7 @@ namespace Chevere\Tests; +use ArgumentCountError; use Chevere\Parameter\ArrayParameter; use Chevere\Parameter\Interfaces\IntParameterInterface; use Chevere\Parameter\Interfaces\StringParameterInterface; @@ -52,12 +53,14 @@ public function testWithDefault(): void $default = [ 'test' => 1, ]; - $withDefault = $parameter->withDefault($default); + $with = $parameter->withDefault($default); + $this->assertNotSame($parameter, $with); + $this->assertSame($default, $with->default()); (new ParameterHelper())->testWithParameterDefault( primitive: 'array', parameter: $parameter, default: $default, - parameterWithDefault: $withDefault + parameterWithDefault: $with ); $this->assertSame([ 'type' => 'array#map', @@ -68,7 +71,10 @@ public function testWithDefault(): void 'required' => true, ] + $int->schema(), ], - ], $withDefault->schema()); + ], $with->schema()); + $this->expectException(ArgumentCountError::class); + $this->expectExceptionMessage('Missing required argument(s): `test`'); + $parameter->withDefault([]); } public function testWithRequired(): void diff --git a/tests/Attribute/FunctionReturnAttrTest.php b/tests/Attribute/FunctionReturnAttrTest.php index a0f7516..f0cd52e 100644 --- a/tests/Attribute/FunctionReturnAttrTest.php +++ b/tests/Attribute/FunctionReturnAttrTest.php @@ -41,7 +41,7 @@ public function testUsesAttr(): void ], ]; $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('[role]: [tenants]: [_V *iterable]: Argument value provided `6` is greater than `5`'); + $this->expectExceptionMessage('[role]: [tenants]: [V *iterable]: Argument value provided `6` is greater than `5`'); usesAttr($value); } diff --git a/tests/IterableParameterTest.php b/tests/IterableParameterTest.php index 542e8fb..9eb60c9 100644 --- a/tests/IterableParameterTest.php +++ b/tests/IterableParameterTest.php @@ -153,6 +153,34 @@ public function testInvoke(): void $parameter([]); } + public function testKeyError(): void + { + $parameter = iterable(K: int(), V: string()); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage( + << 'foo', + ]); + } + + public function testValueError(): void + { + $parameter = iterable(K: int(), V: string()); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage( + << 100, + ]); + } + public function testWithDefault(): void { $value = [10, '10'];