From 5110733225423eb1d7ee5c31174fa5120d0bfc38 Mon Sep 17 00:00:00 2001 From: Dustin Wilson Date: Sun, 30 Oct 2022 21:51:27 -0500 Subject: [PATCH] More improvements and testing --- composer.json | 7 +- composer.lock | 66 ++++++- lib/Catcher.php | 116 +++++++++---- lib/Catcher/HTMLHandler.php | 2 +- lib/Catcher/Handler.php | 14 +- lib/Catcher/HandlerOutput.php | 2 +- lib/Catcher/JSONHandler.php | 2 +- lib/Catcher/PlainTextHandler.php | 6 +- lib/Catcher/ThrowableController.php | 2 +- lib/Error.php | 2 +- tests/bootstrap.php | 2 +- tests/cases/TestCatcher.php | 255 ++++++++++++++++++++++------ 12 files changed, 366 insertions(+), 110 deletions(-) diff --git a/composer.json b/composer.json index 86a14c0..b6a7392 100644 --- a/composer.json +++ b/composer.json @@ -5,8 +5,7 @@ "license": "MIT", "autoload": { "psr-4": { - "MensBeam\\Framework\\": "lib/", - "MensBeam\\Framework\\Test\\": "test/" + "MensBeam\\Foundation\\": "lib/" } }, "authors": [ @@ -24,6 +23,8 @@ }, "require-dev": { "mensbeam/html-dom": "^1.0", - "phpunit/phpunit": "^9.5" + "phpunit/phpunit": "^9.5", + "spatie/fork": "^1.1", + "nikic/php-parser": "^4.15" } } diff --git a/composer.lock b/composer.lock index b672f3e..747a3a9 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "5ef411a51a50b5ff413533ba6957c586", + "content-hash": "6e9aedba10b2f2d0dc2c92f4b391e116", "packages": [ { "name": "psr/log", @@ -2072,6 +2072,70 @@ ], "time": "2020-09-28T06:39:44+00:00" }, + { + "name": "spatie/fork", + "version": "1.1.2", + "source": { + "type": "git", + "url": "https://github.com/spatie/fork.git", + "reference": "d0232e94926c89e3bba7abbff8385140619bd826" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/fork/zipball/d0232e94926c89e3bba7abbff8385140619bd826", + "reference": "d0232e94926c89e3bba7abbff8385140619bd826", + "shasum": "" + }, + "require": { + "ext-pcntl": "*", + "ext-sockets": "*", + "php": "^8.0" + }, + "require-dev": { + "nesbot/carbon": "^2.47", + "phpunit/phpunit": "^9.5", + "spatie/ray": "^1.10" + }, + "type": "library", + "autoload": { + "psr-4": { + "Spatie\\Fork\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Brent Roose", + "email": "brent@spatie.be", + "role": "Developer" + }, + { + "name": "Freek Van der Herten", + "email": "freek@spatie.be", + "role": "Developer" + } + ], + "description": "A lightweight solution for running code concurrently in PHP", + "homepage": "https://github.com/spatie/fork", + "keywords": [ + "fork", + "spatie" + ], + "support": { + "issues": "https://github.com/spatie/fork/issues", + "source": "https://github.com/spatie/fork/tree/1.1.2" + }, + "funding": [ + { + "url": "https://github.com/spatie", + "type": "github" + } + ], + "time": "2022-10-03T13:44:48+00:00" + }, { "name": "symfony/css-selector", "version": "v5.4.11", diff --git a/lib/Catcher.php b/lib/Catcher.php index 5e6cde5..2c8984a 100644 --- a/lib/Catcher.php +++ b/lib/Catcher.php @@ -6,8 +6,8 @@ */ declare(strict_types=1); -namespace MensBeam\Framework; -use MensBeam\Framework\Catcher\{ +namespace MensBeam\Foundation; +use MensBeam\Foundation\Catcher\{ Handler, PlainTextHandler, ThrowableController, @@ -23,6 +23,10 @@ class Catcher { protected array $handlers = []; /** Flag set when the shutdown handler is run */ protected bool $isShuttingDown = false; + /** Flag set when the class has registered error, exception, and shutdown handlers */ + protected bool $registered = false; + /** The last throwable handled by Catcher */ + protected ?\Throwable $lastThrowable = null; @@ -33,10 +37,7 @@ class Catcher { } $this->pushHandler(...$handlers); - - set_error_handler([ $this, 'handleError' ]); - set_exception_handler([ $this, 'handleThrowable' ]); - register_shutdown_function([ $this, 'handleShutdown' ]); + $this->register(); } @@ -45,31 +46,49 @@ class Catcher { return $this->handlers; } + public function getLastThrowable(): \Throwable { + return $this->lastThrowable; + } + + public function isRegistered(): bool { + return $this->registered; + } + + public function popHandler(): Handler { + if (count($this->handlers) === 1) { + throw new \Exception("Popping the last handler will cause the Catcher to have zero handlers; there must be at least one\n"); + } + + return array_pop($this->handlers); + } + public function pushHandler(Handler ...$handlers): void { + if (count($handlers) === 0) { + throw new \ArgumentCountError(__METHOD__ . "expects at least 1 argument, 0 given\n"); + } + + $prev = []; foreach ($handlers as $h) { - if (in_array($h, $this->handlers, true)) { + if (in_array($h, $this->handlers, true) || in_array($h, $prev, true)) { trigger_error("Handlers must be unique; skipping\n", \E_USER_WARNING); continue; } + $prev[] = $h; $this->handlers[] = $h; } } - public function removeHandler(Handler ...$handlers): void { - foreach ($handlers as $h) { - foreach ($this->handlers as $k => $hh) { - if ($h === $hh) { - if (count($this->handlers) === 1) { - throw new \Exception("Removing handler will cause the Catcher to have zero handlers; there must be at least one\n"); - } - - unset($this->handlers[$k]); - $this->handlers = array_values($this->handlers); - continue 2; - } - } + public function register(): bool { + if ($this->registered) { + return false; } + + set_error_handler([ $this, 'handleError' ]); + set_exception_handler([ $this, 'handleThrowable' ]); + register_shutdown_function([ $this, 'handleShutdown' ]); + $this->registered = true; + return true; } public function setHandlers(Handler ...$handlers): void { @@ -77,15 +96,41 @@ class Catcher { $this->pushHandler(...$handlers); } + public function shiftHandler(): Handler { + if (count($this->handlers) === 1) { + throw new \Exception("Shifting the last handler will cause the Catcher to have zero handlers; there must be at least one\n"); + } + + return array_shift($this->handlers); + } + + public function unregister(): bool { + if (!$this->registered) { + return false; + } + + restore_error_handler(); + restore_exception_handler(); + $this->registered = false; + return true; + } + public function unshiftHandler(Handler ...$handlers): void { + if (count($handlers) === 0) { + throw new \ArgumentCountError(__METHOD__ . "expects at least 1 argument, 0 given\n"); + } + $modified = false; + $prev = []; foreach ($handlers as $v => $h) { - if (in_array($h, $this->handlers, true)) { + if (in_array($h, $this->handlers, true) || in_array($h, $prev, true)) { trigger_error("Handlers must be unique; skipping\n", \E_USER_WARNING); unset($handlers[$v]); $modified = true; continue; } + + $prev[] = $h; } if ($modified) { $handlers = array_values($handlers); @@ -127,7 +172,7 @@ class Catcher { $controller = new ThrowableController($throwable); foreach ($this->handlers as $h) { $output = $h->handle($controller); - if ($output->outputCode & Handler::OUTPUT_NOW) { + if ($output->outputCode & Handler::NOW) { $h->dispatch(); } @@ -138,18 +183,20 @@ class Catcher { } if ( + $this->isShuttingDown || + $controlCode === Handler::EXIT || $throwable instanceof \Exception || ($throwable instanceof Error && in_array($throwable->getCode(), [ \E_ERROR, \E_PARSE, \E_CORE_ERROR, \E_COMPILE_ERROR, \E_USER_ERROR ])) || - $throwable instanceof \Error + (!$throwable instanceof Error && $throwable instanceof \Error) ) { foreach ($this->handlers as $h) { $h->dispatch(); } - exit($throwable->getCode()); - } elseif ($controlCode === Handler::EXIT) { exit($throwable->getCode()); } + + $this->lastThrowable = $throwable; } /** @@ -157,19 +204,14 @@ class Catcher { * * @internal */ - public function handleShutdown() { - $this->isShuttingDown = true; - if ($error = error_get_last()) { - if (in_array($error['type'], [ \E_ERROR, \E_PARSE, \E_CORE_ERROR, \E_CORE_WARNING, \E_COMPILE_ERROR, \E_COMPILE_WARNING ])) { - $this->handleError($error['type'], $error['message'], $error['file'], $error['line']); - } + public function handleShutdown(): void { + if (!$this->registered) { + return; } - } - - public function __destruct() { - restore_error_handler(); - restore_exception_handler(); - register_shutdown_function(fn() => false); + $this->isShuttingDown = true; + if ($error = error_get_last() && in_array($error['type'], [ \E_ERROR, \E_PARSE, \E_CORE_ERROR, \E_CORE_WARNING, \E_COMPILE_ERROR, \E_COMPILE_WARNING ])) { + $this->handleError($error['type'], $error['message'], $error['file'], $error['line']); + } } } \ No newline at end of file diff --git a/lib/Catcher/HTMLHandler.php b/lib/Catcher/HTMLHandler.php index 8136879..01b0bab 100644 --- a/lib/Catcher/HTMLHandler.php +++ b/lib/Catcher/HTMLHandler.php @@ -6,7 +6,7 @@ */ declare(strict_types=1); -namespace MensBeam\Framework\Catcher; +namespace MensBeam\Foundation\Catcher; class HTMLHandler extends Handler { diff --git a/lib/Catcher/Handler.php b/lib/Catcher/Handler.php index 3d32e82..5343887 100644 --- a/lib/Catcher/Handler.php +++ b/lib/Catcher/Handler.php @@ -6,7 +6,7 @@ */ declare(strict_types=1); -namespace MensBeam\Framework\Catcher; +namespace MensBeam\Foundation\Catcher; abstract class Handler { @@ -19,8 +19,8 @@ abstract class Handler { // Output constants public const OUTPUT = 16; - public const OUTPUT_NOW = 32; - public const SILENT = 64; + public const SILENT = 32; + public const NOW = 64; protected ThrowableController $controller; @@ -164,11 +164,9 @@ abstract class Handler { $code = self::OUTPUT; if ($this->_silent) { $code = self::SILENT; - if ($this->_forceOutputNow) { - $code |= self::OUTPUT_NOW; - } - } elseif ($this->_forceOutputNow) { - $code = self::OUTPUT_NOW; + } + if ($this->_forceOutputNow) { + $code |= self::NOW; } return $code; diff --git a/lib/Catcher/HandlerOutput.php b/lib/Catcher/HandlerOutput.php index 6a39c77..68399fe 100644 --- a/lib/Catcher/HandlerOutput.php +++ b/lib/Catcher/HandlerOutput.php @@ -6,7 +6,7 @@ */ declare(strict_types=1); -namespace MensBeam\Framework\Catcher; +namespace MensBeam\Foundation\Catcher; class HandlerOutput { diff --git a/lib/Catcher/JSONHandler.php b/lib/Catcher/JSONHandler.php index 4694e7d..fcd71bb 100644 --- a/lib/Catcher/JSONHandler.php +++ b/lib/Catcher/JSONHandler.php @@ -6,7 +6,7 @@ */ declare(strict_types=1); -namespace MensBeam\Framework\Catcher; +namespace MensBeam\Foundation\Catcher; use \Psr\Log\LoggerInterface; diff --git a/lib/Catcher/PlainTextHandler.php b/lib/Catcher/PlainTextHandler.php index d18b7ee..4878b31 100644 --- a/lib/Catcher/PlainTextHandler.php +++ b/lib/Catcher/PlainTextHandler.php @@ -6,7 +6,7 @@ */ declare(strict_types=1); -namespace MensBeam\Framework\Catcher; +namespace MensBeam\Foundation\Catcher; use \Psr\Log\LoggerInterface; @@ -21,6 +21,8 @@ class PlainTextHandler extends Handler { protected string $_timeFormat = '[H:i:s]'; + + protected function dispatchCallback(): void { foreach ($this->outputBuffer as $o) { if ($o->outputCode & self::SILENT) { @@ -89,7 +91,7 @@ class PlainTextHandler extends Handler { } $outputCode = $this->getOutputCode(); - return new HandlerOutput($this->getControlCode(), ($outputCode === self::OUTPUT && \PHP_SAPI === 'CLI') ? self::OUTPUT_NOW : $outputCode, $output); + return new HandlerOutput($this->getControlCode(), (\PHP_SAPI === 'cli') ? $outputCode | self::NOW : $outputCode, $output); } diff --git a/lib/Catcher/ThrowableController.php b/lib/Catcher/ThrowableController.php index c523dc3..fbbe780 100644 --- a/lib/Catcher/ThrowableController.php +++ b/lib/Catcher/ThrowableController.php @@ -6,7 +6,7 @@ */ declare(strict_types=1); -namespace MensBeam\Framework\Catcher; +namespace MensBeam\Foundation\Catcher; class ThrowableController { diff --git a/lib/Error.php b/lib/Error.php index 85abb4f..4d4d4d9 100644 --- a/lib/Error.php +++ b/lib/Error.php @@ -6,7 +6,7 @@ */ declare(strict_types=1); -namespace MensBeam\Framework; +namespace MensBeam\Foundation; class Error extends \Error { public function __construct(string $message = '', int $code = 0, ?string $file = null, ?int $line = line, ?\Throwable $previous = null) { diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 700f046..4455739 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -4,7 +4,7 @@ * See LICENSE and AUTHORS files for details */ declare(strict_types=1); -namespace MensBeam\Framework; +namespace MensBeam\Foundation; ini_set('memory_limit', '-1'); ini_set('zend.assertions', '1'); diff --git a/tests/cases/TestCatcher.php b/tests/cases/TestCatcher.php index eaeef3a..5b85e7a 100644 --- a/tests/cases/TestCatcher.php +++ b/tests/cases/TestCatcher.php @@ -6,53 +6,87 @@ */ declare(strict_types=1); -namespace MensBeam\Framework\TestCase; -use MensBeam\Framework\Catcher; -use MensBeam\Framework\Catcher\{ +namespace MensBeam\Foundation\Catcher\TestCase; +use MensBeam\Foundation\Catcher; +use MensBeam\Foundation\Catcher\{ PlainTextHandler, HTMLHandler, JSONHandler }; +use Spatie\Fork\Fork; class TestCatcher extends \PHPUnit\Framework\TestCase { /** - * @covers \MensBeam\Framework\Catcher::__construct() + * @covers \MensBeam\Foundation\Catcher::__construct * - * @covers \MensBeam\Framework\Catcher::getHandlers() - * @covers \MensBeam\Framework\Catcher::pushHandler() - * @covers \MensBeam\Framework\Catcher::__destruct() - * @covers \MensBeam\Framework\Catcher\Handler::__construct() + * @covers \MensBeam\Foundation\Catcher::getHandlers + * @covers \MensBeam\Foundation\Catcher::pushHandler + * @covers \MensBeam\Foundation\Catcher::register + * @covers \MensBeam\Foundation\Catcher::unregister + * @covers \MensBeam\Foundation\Catcher\Handler::__construct + * @covers \MensBeam\Foundation\Catcher\HTMLHandler::__construct */ public function testMethod___construct(): void { $c = new Catcher(); - $this->assertSame('MensBeam\Framework\Catcher', $c::class); + $this->assertSame('MensBeam\Foundation\Catcher', $c::class); $this->assertEquals(1, count($c->getHandlers())); $this->assertSame(PlainTextHandler::class, $c->getHandlers()[0]::class); - $c->__destruct(); + $c->unregister(); $c = new Catcher( new PlainTextHandler(), new HTMLHandler(), new JSONHandler() ); - $this->assertSame('MensBeam\Framework\Catcher', $c::class); + $this->assertSame('MensBeam\Foundation\Catcher', $c::class); $this->assertEquals(3, count($c->getHandlers())); $h = $c->getHandlers(); $this->assertSame(PlainTextHandler::class, $h[0]::class); $this->assertSame(HTMLHandler::class, $h[1]::class); $this->assertSame(JSONHandler::class, $h[2]::class); - $c->__destruct(); + $c->unregister(); } /** - * @covers \MensBeam\Framework\Catcher::pushHandler() + * @covers \MensBeam\Foundation\Catcher::getLastThrowable * - * @covers \MensBeam\Framework\Catcher::__construct() - * @covers \MensBeam\Framework\Catcher::__destruct() - * @covers \MensBeam\Framework\Catcher\Handler::__construct() + * @covers \MensBeam\Foundation\Catcher::__construct + * @covers \MensBeam\Foundation\Catcher::handleError + * @covers \MensBeam\Foundation\Catcher::handleThrowable + * @covers \MensBeam\Foundation\Catcher::pushHandler + * @covers \MensBeam\Foundation\Catcher::register + * @covers \MensBeam\Foundation\Catcher::unregister + * @covers \MensBeam\Foundation\Error::__construct + * @covers \MensBeam\Foundation\Catcher\Handler::__construct + * @covers \MensBeam\Foundation\Catcher\Handler::dispatch + * @covers \MensBeam\Foundation\Catcher\Handler::getControlCode + * @covers \MensBeam\Foundation\Catcher\Handler::getOutputCode + * @covers \MensBeam\Foundation\Catcher\Handler::handle + * @covers \MensBeam\Foundation\Catcher\HandlerOutput::__construct + * @covers \MensBeam\Foundation\Catcher\PlainTextHandler::dispatchCallback + * @covers \MensBeam\Foundation\Catcher\PlainTextHandler::handleCallback + * @covers \MensBeam\Foundation\Catcher\PlainTextHandler::serializeThrowable + * @covers \MensBeam\Foundation\Catcher\ThrowableController::__construct + * @covers \MensBeam\Foundation\Catcher\ThrowableController::getPrevious + * @covers \MensBeam\Foundation\Catcher\ThrowableController::getThrowable */ - public function testMethod_pushHandler__warning(): void { + public function testMethod_getLastThrowable(): void { + $c = new Catcher(new PlainTextHandler([ 'silent' => true ])); + trigger_error('Ook!', \E_USER_WARNING); + $this->assertEquals(\E_USER_WARNING, $c->getLastThrowable()->getCode()); + $c->unregister(); + } + + /** + * @covers \MensBeam\Foundation\Catcher::pushHandler + * + * @covers \MensBeam\Foundation\Catcher::__construct + * @covers \MensBeam\Foundation\Catcher::register + * @covers \MensBeam\Foundation\Catcher::unregister + * @covers \MensBeam\Foundation\Catcher\Handler::__construct + */ + public function testMethod_pushHandler(): void { $e = null; set_error_handler(function($errno) use (&$e) { $e = $errno; @@ -60,55 +94,89 @@ class TestCatcher extends \PHPUnit\Framework\TestCase { $h = new PlainTextHandler(); $c = new Catcher($h, $h); - $c->__destruct(); + $c->unregister(); + $this->assertEquals(\E_USER_WARNING, $e); + $e = null; - restore_error_handler(); + $c = new Catcher(); + $c->unregister(); + $c->pushHandler($h, $h); $this->assertEquals(\E_USER_WARNING, $e); + + restore_error_handler(); + + $c = new Catcher(); + $c->unregister(); + + $e = null; + try { + $c->pushHandler(); + } catch (\Throwable $t) { + $e = $t::class; + } finally { + $this->assertSame(\ArgumentCountError::class, $e); + } } /** - * @covers \MensBeam\Framework\Catcher::removeHandler() + * @covers \MensBeam\Foundation\Catcher::popHandler * - * @covers \MensBeam\Framework\Catcher::__construct() - * @covers \MensBeam\Framework\Catcher::__destruct() - * @covers \MensBeam\Framework\Catcher::getHandlers() - * @covers \MensBeam\Framework\Catcher::removeHandler() - * @covers \MensBeam\Framework\Catcher\Handler::__construct() + * @covers \MensBeam\Foundation\Catcher::__construct + * @covers \MensBeam\Foundation\Catcher::pushHandler + * @covers \MensBeam\Foundation\Catcher::register + * @covers \MensBeam\Foundation\Catcher::unregister + * @covers \MensBeam\Foundation\Catcher\Handler::__construct + * @covers \MensBeam\Foundation\Catcher\HTMLHandler::__construct */ - public function testMethod_removeHandler(): void { - $h = new HTMLHandler(); - $c = new Catcher( + public function testMethod_popHandler(): void { + $h = [ + new HTMLHandler(), new PlainTextHandler(), - $h - ); - $this->assertEquals(2, count($c->getHandlers())); - $c->removeHandler($h); - $this->assertEquals(1, count($c->getHandlers())); - $c->__destruct(); + new JSONHandler() + ]; + $c = new Catcher(...$h); + $hh = $c->popHandler(); + $this->assertSame($h[2], $hh); + $hh = $c->popHandler(); + $this->assertSame($h[1], $hh); $e = null; try { - $h = [ - new PlainTextHandler(), - new HTMLHandler(), - ]; - $c = new Catcher(...$h); - $c->removeHandler(...$h); + $c->popHandler(); } catch (\Throwable $t) { $e = $t::class; } finally { - $c->__destruct(); + $c->unregister(); $this->assertSame(\Exception::class, $e); } } /** - * @covers \MensBeam\Framework\Catcher::setHandlers() + * @covers \MensBeam\Foundation\Catcher::isRegistered + * + * @covers \MensBeam\Foundation\Catcher::__construct + * @covers \MensBeam\Foundation\Catcher::pushHandler + * @covers \MensBeam\Foundation\Catcher::register + * @covers \MensBeam\Foundation\Catcher::unregister + * @covers \MensBeam\Foundation\Catcher\Handler::__construct + */ + public function testMethod_register(): void { + $c = new Catcher(); + $this->assertTrue($c->isRegistered()); + $this->assertFalse($c->register()); + $c->unregister(); + $this->assertFalse($c->isRegistered()); + } + + /** + * @covers \MensBeam\Foundation\Catcher::setHandlers * - * @covers \MensBeam\Framework\Catcher::__construct() - * @covers \MensBeam\Framework\Catcher::__destruct() - * @covers \MensBeam\Framework\Catcher::getHandlers() - * @covers \MensBeam\Framework\Catcher\Handler::__construct() + * @covers \MensBeam\Foundation\Catcher::__construct + * @covers \MensBeam\Foundation\Catcher::getHandlers + * @covers \MensBeam\Foundation\Catcher::pushHandler + * @covers \MensBeam\Foundation\Catcher::register + * @covers \MensBeam\Foundation\Catcher::unregister + * @covers \MensBeam\Foundation\Catcher\Handler::__construct */ public function testMethod_setHandlers(): void { $c = new Catcher(); @@ -116,15 +184,66 @@ class TestCatcher extends \PHPUnit\Framework\TestCase { $h = $c->getHandlers(); $this->assertEquals(1, count($h)); $this->assertSame(PlainTextHandler::class, $h[0]::class); - $c->__destruct(); + $c->unregister(); } /** - * @covers \MensBeam\Framework\Catcher::unshiftHandler() + * @covers \MensBeam\Foundation\Catcher::shiftHandler * - * @covers \MensBeam\Framework\Catcher::__construct() - * @covers \MensBeam\Framework\Catcher::__destruct() - * @covers \MensBeam\Framework\Catcher\Handler::__construct() + * @covers \MensBeam\Foundation\Catcher::__construct + * @covers \MensBeam\Foundation\Catcher::pushHandler + * @covers \MensBeam\Foundation\Catcher::register + * @covers \MensBeam\Foundation\Catcher::unregister + * @covers \MensBeam\Foundation\Catcher\Handler::__construct + * @covers \MensBeam\Foundation\Catcher\HTMLHandler::__construct + */ + public function testMethod_shiftHandler(): void { + $h = [ + new HTMLHandler(), + new PlainTextHandler(), + new JSONHandler() + ]; + $c = new Catcher(...$h); + $c->unregister(); + $hh = $c->shiftHandler(); + $this->assertSame($h[0], $hh); + $hh = $c->shiftHandler(); + $this->assertSame($h[1], $hh); + + $e = null; + try { + $c->shiftHandler(); + } catch (\Throwable $t) { + $e = $t::class; + } finally { + $this->assertSame(\Exception::class, $e); + } + } + + /** + * @covers \MensBeam\Foundation\Catcher::unregister + * + * @covers \MensBeam\Foundation\Catcher::__construct + * @covers \MensBeam\Foundation\Catcher::pushHandler + * @covers \MensBeam\Foundation\Catcher::register + * @covers \MensBeam\Foundation\Catcher\Handler::__construct + */ + public function testMethod_unregister(): void { + $c = new Catcher(); + $c->unregister(); + $this->assertFalse($c->unregister()); + } + + /** + * @covers \MensBeam\Foundation\Catcher::unshiftHandler + * + * @covers \MensBeam\Foundation\Catcher::__construct + * @covers \MensBeam\Foundation\Catcher::getHandlers + * @covers \MensBeam\Foundation\Catcher::pushHandler + * @covers \MensBeam\Foundation\Catcher::register + * @covers \MensBeam\Foundation\Catcher::unregister + * @covers \MensBeam\Foundation\Catcher\Handler::__construct + * @covers \MensBeam\Foundation\Catcher\HTMLHandler::__construct */ public function testMethod_unshiftHandler(): void { $c = new Catcher(new PlainTextHandler()); @@ -142,9 +261,39 @@ class TestCatcher extends \PHPUnit\Framework\TestCase { }); $c->unshiftHandler($h[0]); - $c->__destruct(); + $this->assertEquals(\E_USER_WARNING, $e); + $e = null; + $h = new PlainTextHandler(); + $c->unshiftHandler($h, $h); + $this->assertEquals(\E_USER_WARNING, $e); restore_error_handler(); - $this->assertEquals(\E_USER_WARNING, $e); + $c->unregister(); + + $c = new Catcher(); + $c->unregister(); + + $e = null; + try { + $c->unshiftHandler(); + } catch (\Throwable $t) { + $e = $t::class; + } finally { + $this->assertSame(\ArgumentCountError::class, $e); + } } + + /** + * @covers \MensBeam\Foundation\Catcher::handleError() + * + * @covers \MensBeam\Foundation\Catcher::__construct() + * @covers \MensBeam\Foundation\Catcher::handleThrowable() + * @covers \MensBeam\Foundation\Catcher::register() + * @covers \MensBeam\Foundation\Catcher\Handler::__construct() + */ + /*public function testMethod_handleError(): void { + $c = new Catcher(new PlainTextHandler([ 'silent' => true ])); + trigger_error('Ook!', \E_USER_WARNING); + $this->assertEquals(\E_USER_WARNING, $c->getLastThrowable()->getCode()); + }*/ } \ No newline at end of file