From e601e6df31c876fde223323c248b810854b21f24 Mon Sep 17 00:00:00 2001 From: avinash Date: Tue, 7 Apr 2026 18:12:54 +0530 Subject: [PATCH] fix: preserve full error message in not() expectation failures When using not() expectations with custom error messages, the message was truncated because throwExpectationFailedException() passed all arguments through shortenedExport() which limits strings to ~40 chars. Uses the full export() method for arguments instead of shortenedExport() so custom error messages are displayed in their entirety. Fixes #1533 --- src/Expectations/OppositeExpectation.php | 6 ++---- src/Support/Exporter.php | 13 +++++++++++++ tests/Unit/Expectations/OppositeExpectation.php | 14 ++++++++++++++ 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/src/Expectations/OppositeExpectation.php b/src/Expectations/OppositeExpectation.php index 22162b5a..4f99c89f 100644 --- a/src/Expectations/OppositeExpectation.php +++ b/src/Expectations/OppositeExpectation.php @@ -798,13 +798,11 @@ final readonly class OppositeExpectation $exporter = Exporter::default(); - $toString = fn (mixed $argument): string => $exporter->shortenedExport($argument); - throw new ExpectationFailedException(sprintf( 'Expecting %s not %s %s.', - $toString($this->original->value), + $exporter->shortenedExport($this->original->value), strtolower((string) preg_replace('/(? $toString($argument), $arguments)), + implode(' ', array_map(fn (mixed $argument): string => $exporter->export($argument), $arguments)), )); } diff --git a/src/Support/Exporter.php b/src/Support/Exporter.php index 44367c08..6fd89c53 100644 --- a/src/Support/Exporter.php +++ b/src/Support/Exporter.php @@ -86,4 +86,17 @@ final readonly class Exporter return (string) preg_replace(array_keys($map), array_values($map), $this->exporter->shortenedExport($value)); } + + /** + * Exports a value into a full single-line string without truncation. + */ + public function export(mixed $value): string + { + $map = [ + '#\\\n\s*#' => '', + '# Object \(\.{3}\)#' => '', + ]; + + return (string) preg_replace(array_keys($map), array_values($map), $this->exporter->export($value)); + } } diff --git a/tests/Unit/Expectations/OppositeExpectation.php b/tests/Unit/Expectations/OppositeExpectation.php index 448ebf6d..856a38e6 100644 --- a/tests/Unit/Expectations/OppositeExpectation.php +++ b/tests/Unit/Expectations/OppositeExpectation.php @@ -14,3 +14,17 @@ it('throw expectation failed exception with array argument', function (): void { $expectation->throwExpectationFailedException('toBe', ['bar']); })->throws(ExpectationFailedException::class, "Expecting 'foo' not to be 'bar'."); + +it('does not truncate long string arguments in error message', function (): void { + $expectation = new OppositeExpectation(expect('foo')); + + $longMessage = 'Very long error message. Very long error message. Very long error message.'; + + $expectation->throwExpectationFailedException('toBe', [$longMessage]); +})->throws(ExpectationFailedException::class, 'Very long error message. Very long error message. Very long error message.'); + +it('does not truncate custom error message when using not()', function (): void { + $longMessage = 'This is a very detailed custom error message that should not be truncated in the output.'; + + expect(true)->not()->toBeTrue($longMessage); +})->throws(ExpectationFailedException::class, 'This is a very detailed custom error message that should not be truncated in the output.');