From 936e07756ba471c77ffb36c77bb357da964ce8ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Vo=C5=99=C3=AD=C5=A1ek?= Date: Sat, 25 Nov 2023 00:34:03 +0100 Subject: [PATCH] Replace phpunit ResultPrinter with self describing Exception (#396) --- phpunit.xml.dist | 2 +- src/Exception.php | 15 ++++++- src/Phpunit/ResultPrinter.php | 65 --------------------------- tests/ExceptionTest.php | 22 +++++++++ tests/Phpunit/ResultPrinterTest.php | 69 ----------------------------- 5 files changed, 37 insertions(+), 136 deletions(-) delete mode 100644 src/Phpunit/ResultPrinter.php delete mode 100644 tests/Phpunit/ResultPrinterTest.php diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 76399a52..77389849 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,4 +1,4 @@ - + tests diff --git a/src/Exception.php b/src/Exception.php index 508fc963..0a273418 100644 --- a/src/Exception.php +++ b/src/Exception.php @@ -4,12 +4,14 @@ namespace Atk4\Core; +use Atk4\Core\ExceptionRenderer\RendererAbstract; use Atk4\Core\Translator\ITranslatorAdapter; +use PHPUnit\Framework\SelfDescribing; /** * Base exception of all Agile Toolkit exceptions. */ -class Exception extends \Exception +class Exception extends \Exception implements SelfDescribing { use WarnDynamicPropertyTrait; @@ -55,6 +57,17 @@ public function setMessage(string $message): self return $this; } + public function toString(): string + { + $res = static::class . ': ' . $this->getMessage() . "\n"; + foreach ($this->getParams() as $param => $value) { + $valueStr = RendererAbstract::toSafeString($value, true); + $res .= ' ' . $param . ': ' . str_replace("\n", "\n" . ' ', $valueStr) . "\n"; + } + + return $res; + } + /** * Return exception message using color sequences. * diff --git a/src/Phpunit/ResultPrinter.php b/src/Phpunit/ResultPrinter.php deleted file mode 100644 index 9c173524..00000000 --- a/src/Phpunit/ResultPrinter.php +++ /dev/null @@ -1,65 +0,0 @@ -thrownException(); - if ($e instanceof ExceptionWrapper) { - $this->write($this->phpunitExceptionWrapperToString($e)); - - return; - } - - parent::printDefectTrace($defect); - } - - /** - * @see based on https://github.com/sebastianbergmann/phpunit/blob/899db927169682058ed8875c3d0c7f30c1fa4ed2/src/Framework/ExceptionWrapper.php#L49 - */ - private function phpunitExceptionWrapperToString(ExceptionWrapper $e): string - { - $string = TestFailure::exceptionToString($e); - - if (is_a($e->getClassName(), Exception::class, true)) { - if ($e->getOriginalException() !== null) { // original exception is not available when run with process isolation - $string .= $this->atkExceptionParamsToString($e->getOriginalException()); // @phpstan-ignore-line - } - } - - $trace = Filter::getFilteredStacktrace($e); - if ($trace) { - $string .= "\n" . $trace; - } - - if ($e->getPreviousWrapped()) { - $string .= "\nCaused by\n" . $this->phpunitExceptionWrapperToString($e->getPreviousWrapped()); - } - - return $string; - } - - private function atkExceptionParamsToString(Exception $e): string - { - $string = ''; - foreach ($e->getParams() as $param => $value) { - $valueStr = RendererAbstract::toSafeString($value, true); - $string .= ' ' . $param . ': ' . str_replace("\n", "\n" . ' ', $valueStr) . "\n"; - } - - return $string; - } -} diff --git a/tests/ExceptionTest.php b/tests/ExceptionTest.php index 2deae986..ed58715f 100644 --- a/tests/ExceptionTest.php +++ b/tests/ExceptionTest.php @@ -123,6 +123,28 @@ public function testSolution2(): void self::assertMatchesRegularExpression('~2nd Solution~', $ret); } + public function testPhpunitSelfDescribing(): void + { + $m = (new Exception('My exception', 0)) + ->addMoreInfo('x', 'foo') + ->addMoreInfo('y', ['bar' => 2.4, [], [[1]]]); + + self::assertSame( + <<<'EOF' + Atk4\Core\Exception: My exception + x: 'foo' + y: [ + 'bar': 2.4, + 0: [], + 1: [ + ... + ] + ] + EOF . "\n", // NL in the string is not parsed by Netbeans, see https://github.com/apache/netbeans/issues/4345 + $m->toString() + ); + } + public function testExceptionFallback(): void { $m = new ExceptionTestThrowError('test', 2); diff --git a/tests/Phpunit/ResultPrinterTest.php b/tests/Phpunit/ResultPrinterTest.php deleted file mode 100644 index 8f21b9a7..00000000 --- a/tests/Phpunit/ResultPrinterTest.php +++ /dev/null @@ -1,69 +0,0 @@ - $resultPrinterClass - */ - private function printAndReturnDefectTrace($resultPrinterClass, \Throwable $exception): string - { - $defect = new TestFailure($this, $exception); - $stream = fopen('php://memory', 'w+'); - $printer = new $resultPrinterClass($stream); - \Closure::bind(static fn () => $printer->printDefectTrace($defect), null, $resultPrinterClass)(); - fseek($stream, 0); - - return stream_get_contents($stream); - } - - public function testBasic(): void - { - $innerException = new \Error('Inner Exception'); - $exception = (new Exception('My exception', 0, $innerException)) - ->addMoreInfo('x', 'foo') - ->addMoreInfo('y', ['bar' => 2.4, [], [[1]]]); - - $resNotWrapped = $this->printAndReturnDefectTrace(ResultPrinter::class, $exception); - self::assertStringContainsString((string) $exception, $resNotWrapped); - self::assertStringContainsString((string) $innerException, $resNotWrapped); - - $res = $this->printAndReturnDefectTrace(ResultPrinter::class, new ExceptionWrapper($exception)); - self::assertTrue(strlen($res) < strlen($resNotWrapped)); - if (\PHP_MAJOR_VERSION < 8) { - // phpvfscomposer:// is not correctly filtered from stacktrace - // by PHPUnit\Util\Filter::getFilteredStacktrace() method - return; - } - self::assertSame( - <<<'EOF' - Atk4\Core\Exception: My exception - x: 'foo' - y: [ - 'bar': 2.4, - 0: [], - 1: [ - ... - ] - ] - - self.php:32 - - Caused by - Error: Inner Exception - - self.php:31 - EOF . "\n", // NL in the string is not parsed by Netbeans, see https://github.com/apache/netbeans/issues/4345 - str_replace(__FILE__, 'self.php', $res) - ); - } -}