diff --git a/src/exceptions.php b/src/exceptions.php index d2075fd6dcbfa8b50576d8d456c73cd6024bfb3a..b5d141456e57b6ee5624f7ce13243462037507bd 100644 --- a/src/exceptions.php +++ b/src/exceptions.php @@ -28,7 +28,7 @@ final class FunctionSignatureAssertionError extends \AssertionError { public static function wrongNumberOrArguments(\ReflectionFunction $reflection, int $numberOfParameters, int $actualCount): self { - return new self($reflection, "Given wrong number of parameters. Expected $numberOfParameters, $actualCount given."); + return new self($reflection, "Wrong number of arguments in given function. Expected $numberOfParameters, $actualCount given."); } @@ -52,20 +52,23 @@ final class FunctionSignatureAssertionError extends \AssertionError { public static function parameterNullability(\ReflectionFunction $functionReflection, \ReflectionParameter $param, bool $expectedNullable, bool $actuallyNullable): self { + $paramIndex = $param->getPosition() + 1; // 0-based indexes are not human-readable return new self( $functionReflection, $expectedNullable - ? "Function should have parameter {$param->getName()} nullable but it is not." - : "Function should have parameter {$param->getName()} required but it is not." + ? "Parameter #{$paramIndex} (\${$param->getName()}) is expected to be nullable. But it is required." + : "Parameter #{$paramIndex} (\${$param->getName()}) is expected to be required. But it is nullable." ); + } public static function wrongParameterType(\ReflectionFunction $functionReflection, \ReflectionParameter $parameterReflection, string $expectedParameterType, \ReflectionType $actualParameterType): self { + $paramIndex = ($parameterReflection->getPosition() + 1); return new self( $functionReflection, - "Wrong parameter type given in function {$parameterReflection}. {$expectedParameterType} expected. {$actualParameterType} defined in function." + "Given function parameter #{$paramIndex} \${$parameterReflection->getName()} has type {$parameterReflection->getType()}. However this parameter is expected to be {$expectedParameterType}." ); } @@ -75,8 +78,8 @@ final class FunctionSignatureAssertionError extends \AssertionError { return new self( $reflectionFunction, $expectingNullable - ? 'Wrong return type nullability. Expecting nullable, but was required.' - : 'Wrong return type nullability. Expecting required, but was nullable.' + ? 'Return-type is expected to be nullable. But it is required.' + : 'Return-type is expected to be required. But it is nullable.' ); } @@ -85,7 +88,7 @@ final class FunctionSignatureAssertionError extends \AssertionError { { return new self( $reflection, - "Expected return type of type '$expectedReturnType', but function declares '$actualReturnType'" + "Expected return type of type '$expectedReturnType', but given function declares '$actualReturnType'." ); } }; diff --git a/tests/fn.assertSignature.allNullable.phpt b/tests/fn.assertSignature.allNullable.phpt index a89737a44f4ad7b3bbc46fa619c00dba3f30fed3..139840883f904623d2eec7c77bacd2d321751045 100644 --- a/tests/fn.assertSignature.allNullable.phpt +++ b/tests/fn.assertSignature.allNullable.phpt @@ -3,30 +3,56 @@ namespace MyTestNamespace; require __DIR__ . '/bootstrap.php'; require __DIR__ . '/testClasses.php'; use function Grifart\AssertFunction\{assertSignature, nullable, params}; +use Grifart\AssertFunction\FunctionSignatureAssertionError; use Tester\Assert; +$place = 'tests/' . basename(__FILE__) . ':' . (__LINE__ +2) . ' '; $fn = function(?T1 $t1, ?T2 $t2): ?T3 {return new T3;}; + +// Correct signature assertion assertSignature($fn, params(nullable(T1::class), nullable(T2::class)), nullable(T3::class)); // parameter is nullable, non-nullable is expected -Assert::exception(function () use ($fn) { // 1st param - assertSignature($fn, params(T1::class, nullable(T2::class)), nullable(T3::class)); -}, \AssertionError::class /* todo: assert message */); +Assert::exception( + function () use ($fn) { // 1st param + assertSignature($fn, params(T1::class, nullable(T2::class)), nullable(T3::class)); + }, + FunctionSignatureAssertionError::class, + $place . 'Parameter #1 ($t1) is expected to be required. But it is nullable.' +); -Assert::exception(function () use ($fn) { // 2nd param - assertSignature($fn, params(nullable(T1::class), T2::class), nullable(T3::class)); -}, \AssertionError::class /* todo: assert message */); +Assert::exception( + function () use ($fn) { // 2nd param + assertSignature($fn, params(nullable(T1::class), T2::class), nullable(T3::class)); + }, + FunctionSignatureAssertionError::class, + $place . 'Parameter #2 ($t2) is expected to be required. But it is nullable.' +); -Assert::exception(function () use ($fn) { // return type - assertSignature($fn, params(nullable(T1::class), nullable(T2::class)), T3::class); -}, \AssertionError::class /* todo: assert message */); +Assert::exception( + function () use ($fn) { // return type + assertSignature($fn, params(nullable(T1::class), nullable(T2::class)), T3::class); + }, + FunctionSignatureAssertionError::class, + $place . 'Return-type is expected to be required. But it is nullable.' +); // Wrong return type -Assert::exception(function () use ($fn) { - assertSignature($fn, params(nullable(T1::class), nullable(T2::class)), nullable(T2::class)); -}, \AssertionError::class /* todo: assert message */); +Assert::exception( + function () use ($fn) { + assertSignature($fn, params(nullable(T1::class), nullable(T2::class)), nullable(T2::class)); + }, + FunctionSignatureAssertionError::class, + $place . "Expected return type of type '" . T2::class . "', " + . "but given function declares '" . T3::class . "'." +); // Wrong parameter type -Assert::exception(function () use ($fn) { - assertSignature($fn, params(nullable(T1::class), nullable(T1::class)), nullable(T3::class)); -}, \AssertionError::class /* todo: assert message */); +Assert::exception( + function () use ($fn) { + assertSignature($fn, params(nullable(T1::class), nullable(T1::class)), nullable(T3::class)); + }, + FunctionSignatureAssertionError::class, + $place . 'Given function parameter #2 $t2 has type ' . T2::class . '. ' + . 'However this parameter is expected to be ' . T1::class . '.' +); diff --git a/tests/fn.assertSignature.allRequired.phpt b/tests/fn.assertSignature.allRequired.phpt index 227e440ed9990d932cb4f0806215bca4fa3ced36..5f1b0a1c13898da6ca6d52b150eeb352ad5fb538 100644 --- a/tests/fn.assertSignature.allRequired.phpt +++ b/tests/fn.assertSignature.allRequired.phpt @@ -3,22 +3,33 @@ namespace MyTestNamespace; require __DIR__ . '/bootstrap.php'; require __DIR__ . '/testClasses.php'; use function Grifart\AssertFunction\{assertSignature, nullable, params}; +use Grifart\AssertFunction\FunctionSignatureAssertionError; use Tester\Assert; +$place = 'tests/' . basename(__FILE__) . ':' . (__LINE__ +2) . ' '; $f1 = function(T1 $t1, T2 $t2): T3 {return new T3;}; // Positive scenario assertSignature($f1, params(T1::class, T2::class), T3::class); -assertSignature($f1, [T1::class, T2::class], T3::class); // alternative syntax +assertSignature($f1, [T1::class, T2::class], T3::class); // alternative shorter less-self explaining syntax -// Optional by accident: parameter -Assert::exception(function () use ($f1) { - assertSignature($f1, params(nullable(T1::class), T2::class), T3::class); -}, \AssertionError::class); +// Requires optional parameter, function has required +Assert::exception( + function () use ($f1) { + assertSignature($f1, params(nullable(T1::class), T2::class), T3::class); + }, + FunctionSignatureAssertionError::class, + $place . 'Parameter #1 ($t1) is expected to be nullable. ' + . 'But it is required.' +); -// Optional by accident: return type -Assert::exception(function () use ($f1) { - assertSignature($f1, params(T1::class, T2::class), nullable(T3::class)); -// assertFunction($f1, [params(T1::class, T2::class) => nullable(T3::class)]); -}, \AssertionError::class); +// Requires optional return type, function has required +Assert::exception( + function () use ($f1) { + assertSignature($f1, params(T1::class, T2::class), nullable(T3::class)); + }, + FunctionSignatureAssertionError::class, + $place . 'Return-type is expected to be nullable. ' + . 'But it is required.' +); diff --git a/tests/fn.assertSignature.wrongNumberOfArguments.phpt b/tests/fn.assertSignature.wrongNumberOfArguments.phpt index af4f1471833a0ae6a290c121fa38ea6578002e3a..8b6667c99e302ec34afe4e05ebe05a353f6b2ce7 100644 --- a/tests/fn.assertSignature.wrongNumberOfArguments.phpt +++ b/tests/fn.assertSignature.wrongNumberOfArguments.phpt @@ -2,9 +2,13 @@ namespace MyTestNamespace; require __DIR__ . '/bootstrap.php'; require __DIR__ . '/testClasses.php'; -use function Grifart\AssertFunction\{assertSignature, nullable, params}; +use Grifart\AssertFunction\FunctionSignatureAssertionError; use Tester\Assert; -$position = 'tests/fn.assertSignature.wrongNumberOfArguments.phpt:9'; +use function Grifart\AssertFunction\{ + assertSignature, params +}; + +$position = 'tests/' . basename(__FILE__) . ':' . (__LINE__ + 2); $f1 = function(T1 $t1, T2 $t2): T3 {return new T3;}; @@ -13,14 +17,14 @@ Assert::exception( function () use ($f1) { assertSignature($f1, params(T1::class), T3::class); }, - \AssertionError::class, - "$position Given wrong number of parameters. Expected 1, 2 given." + FunctionSignatureAssertionError::class, + "$position Wrong number of arguments in given function. Expected 1, 2 given." ); Assert::exception( function () use ($f1) { assertSignature($f1, params(T1::class, T2::class, T1::class), T3::class); }, - \AssertionError::class, - "$position Given wrong number of parameters. Expected 3, 2 given." + FunctionSignatureAssertionError::class, + "$position Wrong number of arguments in given function. Expected 3, 2 given." );