From 75a9b8e94f9e74a6cf377e02b0b472eff0b1f2bd Mon Sep 17 00:00:00 2001 From: Henrique Moody Date: Wed, 18 Dec 2024 19:42:34 +0100 Subject: [PATCH] Overwrite file and line in ValidationException Because of how PHP works, when we instantiate an Exception object, the `file` and `line` properties are the file and line where we created the object. That's a desirable behaviour, but there's no value for a user to know that we created an instance of `ValidationException` in the `Validator` class. This commit will overwrite the file and line in the `ValidationException` to where the method `assert()` was called. Note that when running `check()` it will still point to `Validator`, but I decided not to change it, as the method `check()` got deprecated. --- library/Exceptions/ValidationException.php | 6 ++++ .../ValidationExceptionStackTraceTest.php | 28 +++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 tests/feature/ValidationExceptionStackTraceTest.php diff --git a/library/Exceptions/ValidationException.php b/library/Exceptions/ValidationException.php index 970c8605b..7343cc10a 100644 --- a/library/Exceptions/ValidationException.php +++ b/library/Exceptions/ValidationException.php @@ -11,6 +11,8 @@ use InvalidArgumentException; +use function realpath; + final class ValidationException extends InvalidArgumentException implements Exception { /** @param array $messages */ @@ -19,6 +21,10 @@ public function __construct( private readonly string $fullMessage, private readonly array $messages, ) { + if (realpath($this->file) === realpath(__DIR__ . '/../Validator.php')) { + $this->file = $this->getTrace()[0]['file'] ?? $this->file; + $this->line = $this->getTrace()[0]['line'] ?? $this->line; + } parent::__construct($message); } diff --git a/tests/feature/ValidationExceptionStackTraceTest.php b/tests/feature/ValidationExceptionStackTraceTest.php new file mode 100644 index 000000000..6238111fe --- /dev/null +++ b/tests/feature/ValidationExceptionStackTraceTest.php @@ -0,0 +1,28 @@ + + * SPDX-License-Identifier: MIT + */ + +declare(strict_types=1); + +use Respect\Validation\Exceptions\ValidationException; + +test('Should overwrite stack trace when in Validator', function (): void { + try { + v::intType()->assert('string'); + } catch (ValidationException $e) { + expect($e->getFile())->toBe(__FILE__); + expect($e->getLine())->toBe(__LINE__ - 3); + } +}); + +test('Should not overwrite stack trace when created manually', function (): void { + try { + throw new ValidationException('message', 'fullMessage', ['id' => 'message']); + } catch (ValidationException $e) { + expect($e->getFile())->toBe(__FILE__); + expect($e->getLine())->toBe(__LINE__ - 3); + } +});