From 60fd72cd1a1e4e53b9af87e00a8c27687c6b5385 Mon Sep 17 00:00:00 2001 From: Igor Scheller Date: Tue, 31 Oct 2017 13:40:13 +0100 Subject: Added service providers --- .../Exceptions/ExceptionsServiceProviderTest.php | 39 ++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 tests/Unit/Exceptions/ExceptionsServiceProviderTest.php (limited to 'tests/Unit/Exceptions/ExceptionsServiceProviderTest.php') diff --git a/tests/Unit/Exceptions/ExceptionsServiceProviderTest.php b/tests/Unit/Exceptions/ExceptionsServiceProviderTest.php new file mode 100644 index 00000000..26eddb75 --- /dev/null +++ b/tests/Unit/Exceptions/ExceptionsServiceProviderTest.php @@ -0,0 +1,39 @@ +getMockBuilder(ExceptionHandler::class) + ->getMock(); + + /** @var PHPUnit_Framework_MockObject_MockObject|Application $app */ + $app = $this->getMockBuilder(Application::class) + ->setMethods(['make', 'instance']) + ->getMock(); + + $app->expects($this->once()) + ->method('make') + ->with(ExceptionHandler::class) + ->willReturn($exceptionHandler); + + $app->expects($this->once()) + ->method('instance') + ->with('error.handler', $exceptionHandler); + + $serviceProvider = new ExceptionsServiceProvider($app); + $serviceProvider->register(); + } +} -- cgit v1.2.3-54-g00ecf From 411ea5bb6d0ecf32e6c989a99fac120502db9fe9 Mon Sep 17 00:00:00 2001 From: Igor Scheller Date: Tue, 31 Oct 2017 14:15:19 +0100 Subject: Refactored service provider tests --- tests/Unit/Config/ConfigServiceProviderTest.php | 35 +++++----------------- .../Unit/Database/DatabaseServiceProviderTest.php | 34 +++++++-------------- .../Exceptions/ExceptionsServiceProviderTest.php | 20 ++++--------- tests/Unit/Logger/LoggerServiceProviderTest.php | 20 ++++--------- tests/Unit/Routing/RoutingServiceProviderTest.php | 20 ++++--------- tests/Unit/ServiceProviderTest.php | 31 ++++++++++++------- 6 files changed, 55 insertions(+), 105 deletions(-) (limited to 'tests/Unit/Exceptions/ExceptionsServiceProviderTest.php') diff --git a/tests/Unit/Config/ConfigServiceProviderTest.php b/tests/Unit/Config/ConfigServiceProviderTest.php index 26128e79..96ac8704 100644 --- a/tests/Unit/Config/ConfigServiceProviderTest.php +++ b/tests/Unit/Config/ConfigServiceProviderTest.php @@ -5,10 +5,10 @@ namespace Engelsystem\Test\Config; use Engelsystem\Application; use Engelsystem\Config\Config; use Engelsystem\Config\ConfigServiceProvider; -use PHPUnit\Framework\TestCase; +use Engelsystem\Test\Unit\ServiceProviderTest; use PHPUnit_Framework_MockObject_MockObject; -class ConfigServiceProviderTest extends TestCase +class ConfigServiceProviderTest extends ServiceProviderTest { /** * @covers \Engelsystem\Config\ConfigServiceProvider::register() @@ -19,34 +19,15 @@ class ConfigServiceProviderTest extends TestCase $config = $this->getMockBuilder(Config::class) ->getMock(); - /** @var PHPUnit_Framework_MockObject_MockObject|Application $app */ - $app = $this->getMockBuilder(Application::class) - ->setMethods(['make', 'instance', 'get']) - ->getMock(); + $app = $this->getApp(['make', 'instance', 'get']); Application::setInstance($app); - $app->expects($this->once()) - ->method('make') - ->with(Config::class) - ->willReturn($config); - - $app->expects($this->once()) - ->method('instance') - ->with('config', $config); - - $app->expects($this->atLeastOnce()) - ->method('get') - ->with('path.config') - ->willReturn(__DIR__ . '/../../../config'); - - $config->expects($this->exactly(2)) - ->method('set') - ->withAnyParameters(); + $this->setExpects($app, 'make', [Config::class], $config); + $this->setExpects($app, 'instance', ['config', $config]); + $this->setExpects($app, 'get', ['path.config'], __DIR__ . '/../../../config', $this->atLeastOnce()); - $config->expects($this->once()) - ->method('get') - ->with(null) - ->willReturn([]); + $this->setExpects($config, 'set', null, null, $this->exactly(2)); + $this->setExpects($config, 'get', [null], []); $serviceProvider = new ConfigServiceProvider($app); $serviceProvider->register(); diff --git a/tests/Unit/Database/DatabaseServiceProviderTest.php b/tests/Unit/Database/DatabaseServiceProviderTest.php index d0e3e164..d61f5ae7 100644 --- a/tests/Unit/Database/DatabaseServiceProviderTest.php +++ b/tests/Unit/Database/DatabaseServiceProviderTest.php @@ -2,14 +2,13 @@ namespace Engelsystem\Test\Database; -use Engelsystem\Application; use Engelsystem\Config\Config; use Engelsystem\Database\DatabaseServiceProvider; +use Engelsystem\Test\Unit\ServiceProviderTest; use Exception; -use PHPUnit\Framework\TestCase; use PHPUnit_Framework_MockObject_MockObject; -class DatabaseServiceProviderTest extends TestCase +class DatabaseServiceProviderTest extends ServiceProviderTest { /** * @covers \Engelsystem\Database\DatabaseServiceProvider::register() @@ -21,29 +20,18 @@ class DatabaseServiceProviderTest extends TestCase $config = $this->getMockBuilder(Config::class) ->getMock(); - /** @var PHPUnit_Framework_MockObject_MockObject|Application $app */ - $app = $this->getMockBuilder(Application::class) - ->setMethods(['get']) - ->getMock(); - - $app->expects($this->once()) - ->method('get') - ->with('config') - ->willReturn($config); - - $config->expects($this->atLeastOnce()) - ->method('get') - ->with('database') - ->willReturn([ - 'host' => 'localhost', - 'db' => 'database', - 'user' => 'user', - 'pw' => 'password', - ]); + $app = $this->getApp(['get']); - $serviceProvider = new DatabaseServiceProvider($app); + $this->setExpects($app, 'get', ['config'], $config); + $this->setExpects($config, 'get', ['database'], [ + 'host' => 'localhost', + 'db' => 'database', + 'user' => 'user', + 'pw' => 'password', + ], $this->atLeastOnce()); $this->expectException(Exception::class); + $serviceProvider = new DatabaseServiceProvider($app); $serviceProvider->register(); } } diff --git a/tests/Unit/Exceptions/ExceptionsServiceProviderTest.php b/tests/Unit/Exceptions/ExceptionsServiceProviderTest.php index 26eddb75..fc48d39e 100644 --- a/tests/Unit/Exceptions/ExceptionsServiceProviderTest.php +++ b/tests/Unit/Exceptions/ExceptionsServiceProviderTest.php @@ -2,13 +2,12 @@ namespace Engelsystem\Test\Exceptions; -use Engelsystem\Application; use Engelsystem\Exceptions\ExceptionsServiceProvider; use Engelsystem\Exceptions\Handler as ExceptionHandler; -use PHPUnit\Framework\TestCase; +use Engelsystem\Test\Unit\ServiceProviderTest; use PHPUnit_Framework_MockObject_MockObject; -class ExceptionsServiceProviderTest extends TestCase +class ExceptionsServiceProviderTest extends ServiceProviderTest { /** * @covers \Engelsystem\Exceptions\ExceptionsServiceProvider::register() @@ -19,19 +18,10 @@ class ExceptionsServiceProviderTest extends TestCase $exceptionHandler = $this->getMockBuilder(ExceptionHandler::class) ->getMock(); - /** @var PHPUnit_Framework_MockObject_MockObject|Application $app */ - $app = $this->getMockBuilder(Application::class) - ->setMethods(['make', 'instance']) - ->getMock(); - - $app->expects($this->once()) - ->method('make') - ->with(ExceptionHandler::class) - ->willReturn($exceptionHandler); + $app = $this->getApp(); - $app->expects($this->once()) - ->method('instance') - ->with('error.handler', $exceptionHandler); + $this->setExpects($app, 'make', [ExceptionHandler::class], $exceptionHandler); + $this->setExpects($app, 'instance', ['error.handler', $exceptionHandler]); $serviceProvider = new ExceptionsServiceProvider($app); $serviceProvider->register(); diff --git a/tests/Unit/Logger/LoggerServiceProviderTest.php b/tests/Unit/Logger/LoggerServiceProviderTest.php index 5143d236..66f63cf4 100644 --- a/tests/Unit/Logger/LoggerServiceProviderTest.php +++ b/tests/Unit/Logger/LoggerServiceProviderTest.php @@ -2,14 +2,13 @@ namespace Engelsystem\Test\Logger; -use Engelsystem\Application; use Engelsystem\Logger\EngelsystemLogger; use Engelsystem\Logger\LoggerServiceProvider; -use PHPUnit\Framework\TestCase; +use Engelsystem\Test\Unit\ServiceProviderTest; use PHPUnit_Framework_MockObject_MockObject; use Psr\Log\LoggerInterface; -class LoggerServiceProviderTest extends TestCase +class LoggerServiceProviderTest extends ServiceProviderTest { /** * @covers \Engelsystem\Logger\LoggerServiceProvider::register() @@ -20,19 +19,10 @@ class LoggerServiceProviderTest extends TestCase $logger = $this->getMockBuilder(EngelsystemLogger::class) ->getMock(); - /** @var PHPUnit_Framework_MockObject_MockObject|Application $app */ - $app = $this->getMockBuilder(Application::class) - ->setMethods(['make', 'instance', 'bind']) - ->getMock(); - - $app->expects($this->once()) - ->method('make') - ->with(EngelsystemLogger::class) - ->willReturn($logger); + $app = $this->getApp(['make', 'instance', 'bind']); - $app->expects($this->once()) - ->method('instance') - ->with('logger', $logger); + $this->setExpects($app, 'make', [EngelsystemLogger::class], $logger); + $this->setExpects($app, 'instance', ['logger', $logger]); $app->expects($this->atLeastOnce()) ->method('bind') diff --git a/tests/Unit/Routing/RoutingServiceProviderTest.php b/tests/Unit/Routing/RoutingServiceProviderTest.php index 4f1cd5fc..bb2a1d65 100644 --- a/tests/Unit/Routing/RoutingServiceProviderTest.php +++ b/tests/Unit/Routing/RoutingServiceProviderTest.php @@ -2,13 +2,12 @@ namespace Engelsystem\Test\Routing; -use Engelsystem\Application; use Engelsystem\Routing\RoutingServiceProvider; use Engelsystem\Routing\UrlGenerator; -use PHPUnit\Framework\TestCase; +use Engelsystem\Test\Unit\ServiceProviderTest; use PHPUnit_Framework_MockObject_MockObject; -class RoutingServiceProviderTest extends TestCase +class RoutingServiceProviderTest extends ServiceProviderTest { /** * @covers \Engelsystem\Routing\RoutingServiceProvider::register() @@ -19,19 +18,10 @@ class RoutingServiceProviderTest extends TestCase $urlGenerator = $this->getMockBuilder(UrlGenerator::class) ->getMock(); - /** @var PHPUnit_Framework_MockObject_MockObject|Application $app */ - $app = $this->getMockBuilder(Application::class) - ->setMethods(['make', 'instance']) - ->getMock(); - - $app->expects($this->once()) - ->method('make') - ->with(UrlGenerator::class) - ->willReturn($urlGenerator); + $app = $this->getApp(); - $app->expects($this->once()) - ->method('instance') - ->with('routing.urlGenerator', $urlGenerator); + $this->setExpects($app, 'make', [UrlGenerator::class], $urlGenerator); + $this->setExpects($app, 'instance', ['routing.urlGenerator', $urlGenerator]); $serviceProvider = new RoutingServiceProvider($app); $serviceProvider->register(); diff --git a/tests/Unit/ServiceProviderTest.php b/tests/Unit/ServiceProviderTest.php index be843742..dc58a65e 100644 --- a/tests/Unit/ServiceProviderTest.php +++ b/tests/Unit/ServiceProviderTest.php @@ -4,33 +4,44 @@ namespace Engelsystem\Test\Unit; use Engelsystem\Application; use PHPUnit\Framework\TestCase; -use PHPUnit_Framework_MockObject_MockObject; +use PHPUnit_Framework_MockObject_Matcher_InvokedRecorder as InvokedRecorder; +use PHPUnit_Framework_MockObject_MockObject as MockObject; abstract class ServiceProviderTest extends TestCase { /** * @param array $methods - * @return Application|PHPUnit_Framework_MockObject_MockObject + * @return Application|MockObject */ protected function getApp($methods = ['make', 'instance']) { - /** @var PHPUnit_Framework_MockObject_MockObject|Application $app */ + /** @var MockObject|Application $app */ return $this->getMockBuilder(Application::class) ->setMethods($methods) ->getMock(); } /** - * @param PHPUnit_Framework_MockObject_MockObject $object - * @param string $method - * @param array $arguments - * @param mixed $return + * @param MockObject $object + * @param string $method + * @param array $arguments + * @param mixed $return + * @param InvokedRecorder $times */ - protected function setExpects($object, $method, $arguments, $return = null) + protected function setExpects($object, $method, $arguments = null, $return = null, $times = null) { - $invocation = $object->expects($this->once()) + if (is_null($times)) { + $times = $this->once(); + } + + $invocation = $object->expects($times) ->method($method); - call_user_func_array([$invocation, 'with'], $arguments); + + if (is_null($arguments)) { + $invocation->withAnyParameters(); + } else { + call_user_func_array([$invocation, 'with'], $arguments); + } if (!is_null($return)) { $invocation->willReturn($return); -- cgit v1.2.3-54-g00ecf From e15e86362585f5d00d118653232584ed0920e533 Mon Sep 17 00:00:00 2001 From: Igor Scheller Date: Tue, 31 Oct 2017 14:23:23 +0100 Subject: Added tests for base_path and config_path --- .../DatabaseServiceProviderConnectionTest.php | 2 +- tests/Feature/Logger/EngelsystemLoggerTest.php | 2 +- tests/Feature/Model/LogEntriesModelTest.php | 38 +++++++++++++++++++ tests/Feature/Model/RoomModelTest.php | 40 ++++++++++++++++++++ tests/Feature/model/LogEntriesModelTest.php | 38 ------------------- tests/Feature/model/RoomModelTest.php | 40 -------------------- tests/Unit/ApplicationTest.php | 2 +- tests/Unit/Config/ConfigServiceProviderTest.php | 2 +- tests/Unit/Config/ConfigTest.php | 2 +- .../Unit/Database/DatabaseServiceProviderTest.php | 2 +- .../Exceptions/ExceptionsServiceProviderTest.php | 2 +- tests/Unit/HelpersTest.php | 43 +++++++++++++++++++++- tests/Unit/Logger/LoggerServiceProviderTest.php | 2 +- tests/Unit/Renderer/HtmlEngineTest.php | 2 +- .../Unit/Renderer/RendererServiceProviderTest.php | 2 +- tests/Unit/Renderer/RendererTest.php | 6 ++- tests/Unit/Routing/RoutingServiceProviderTest.php | 2 +- tests/Unit/Routing/UrlGeneratorTest.php | 2 +- 18 files changed, 136 insertions(+), 93 deletions(-) create mode 100644 tests/Feature/Model/LogEntriesModelTest.php create mode 100644 tests/Feature/Model/RoomModelTest.php delete mode 100644 tests/Feature/model/LogEntriesModelTest.php delete mode 100644 tests/Feature/model/RoomModelTest.php (limited to 'tests/Unit/Exceptions/ExceptionsServiceProviderTest.php') diff --git a/tests/Feature/Database/DatabaseServiceProviderConnectionTest.php b/tests/Feature/Database/DatabaseServiceProviderConnectionTest.php index dd1ce729..636fba2e 100644 --- a/tests/Feature/Database/DatabaseServiceProviderConnectionTest.php +++ b/tests/Feature/Database/DatabaseServiceProviderConnectionTest.php @@ -1,6 +1,6 @@ assertNotFalse(LogEntry_create(LogLevel::WARNING, 'test_LogEntry_create')); + + // There should be one more log entry now + $this->assertEquals(count(LogEntries()), $count + 1); + } + + public function testClearAllLogEntries() + { + LogEntry_create(LogLevel::WARNING, 'test'); + $this->assertTrue(count(LogEntries()) > 0); + + $this->assertNotFalse(LogEntries_clear_all()); + $this->assertCount(0, LogEntries()); + } + + public function tearDown() + { + LogEntries_clear_all(); + } +} diff --git a/tests/Feature/Model/RoomModelTest.php b/tests/Feature/Model/RoomModelTest.php new file mode 100644 index 00000000..20b9e34d --- /dev/null +++ b/tests/Feature/Model/RoomModelTest.php @@ -0,0 +1,40 @@ +room_id = Room_create('test', false, true, ''); + } + + public function test_Room() + { + $this->create_Room(); + + $room = Room($this->room_id); + + $this->assertNotFalse($room); + $this->assertNotNull($room); + $this->assertEquals($room['Name'], 'test'); + + $this->assertNull(Room(-1)); + } + + public function tearDown() + { + if ($this->room_id != null) { + Room_delete($this->room_id); + } + } +} diff --git a/tests/Feature/model/LogEntriesModelTest.php b/tests/Feature/model/LogEntriesModelTest.php deleted file mode 100644 index 6d7b0ebc..00000000 --- a/tests/Feature/model/LogEntriesModelTest.php +++ /dev/null @@ -1,38 +0,0 @@ -assertNotFalse(LogEntry_create(LogLevel::WARNING, 'test_LogEntry_create')); - - // There should be one more log entry now - $this->assertEquals(count(LogEntries()), $count + 1); - } - - public function testClearAllLogEntries() - { - LogEntry_create(LogLevel::WARNING, 'test'); - $this->assertTrue(count(LogEntries()) > 0); - - $this->assertNotFalse(LogEntries_clear_all()); - $this->assertCount(0, LogEntries()); - } - - public function tearDown() - { - LogEntries_clear_all(); - } -} diff --git a/tests/Feature/model/RoomModelTest.php b/tests/Feature/model/RoomModelTest.php deleted file mode 100644 index 96be84a2..00000000 --- a/tests/Feature/model/RoomModelTest.php +++ /dev/null @@ -1,40 +0,0 @@ -room_id = Room_create('test', false, true, ''); - } - - public function test_Room() - { - $this->create_Room(); - - $room = Room($this->room_id); - - $this->assertNotFalse($room); - $this->assertNotNull($room); - $this->assertEquals($room['Name'], 'test'); - - $this->assertNull(Room(-1)); - } - - public function tearDown() - { - if ($this->room_id != null) { - Room_delete($this->room_id); - } - } -} diff --git a/tests/Unit/ApplicationTest.php b/tests/Unit/ApplicationTest.php index 78310134..f58483ea 100644 --- a/tests/Unit/ApplicationTest.php +++ b/tests/Unit/ApplicationTest.php @@ -1,6 +1,6 @@ assertEquals($class, app('some.name')); } + /** + * @covers \base_path() + */ + public function testBasePath() + { + /** @var MockObject|Application $app */ + $app = $this->getMockBuilder(Container::class) + ->getMock(); + Application::setInstance($app); + + $app->expects($this->atLeastOnce()) + ->method('get') + ->with('path') + ->willReturn('/foo/bar'); + + $this->assertEquals('/foo/bar', base_path()); + $this->assertEquals('/foo/bar/bla-foo.conf', base_path('bla-foo.conf')); + } + /** * @covers \config */ @@ -53,6 +73,25 @@ class HelpersTest extends TestCase $this->assertEquals(['user' => 'FooBar'], config('mail')); } + /** + * @covers \config_path() + */ + public function testConfigPath() + { + /** @var MockObject|Application $app */ + $app = $this->getMockBuilder(Container::class) + ->getMock(); + Application::setInstance($app); + + $app->expects($this->atLeastOnce()) + ->method('get') + ->with('path.config') + ->willReturn('/foo/conf'); + + $this->assertEquals('/foo/conf', config_path()); + $this->assertEquals('/foo/conf/bar.php', config_path('bar.php')); + } + /** * @covers \env */ @@ -146,7 +185,7 @@ class HelpersTest extends TestCase /** * @param string $alias * @param object $object - * @return Application|\PHPUnit_Framework_MockObject_MockObject + * @return Application|MockObject */ protected function getAppMock($alias, $object) { diff --git a/tests/Unit/Logger/LoggerServiceProviderTest.php b/tests/Unit/Logger/LoggerServiceProviderTest.php index 66f63cf4..cef95d5b 100644 --- a/tests/Unit/Logger/LoggerServiceProviderTest.php +++ b/tests/Unit/Logger/LoggerServiceProviderTest.php @@ -1,6 +1,6 @@ getMockForAbstractClass(EngineInterface::class); $nullRenderer->expects($this->atLeastOnce()) @@ -20,6 +22,7 @@ class RendererTest extends TestCase ->willReturn(false); $renderer->addRenderer($nullRenderer); + /** @var MockObject|EngineInterface $mockRenderer */ $mockRenderer = $this->getMockForAbstractClass(EngineInterface::class); $mockRenderer->expects($this->atLeastOnce()) @@ -42,6 +45,7 @@ class RendererTest extends TestCase { $renderer = new Renderer(); + /** @var MockObject|LoggerInterface $loggerMock */ $loggerMock = $this->getMockForAbstractClass(LoggerInterface::class); $loggerMock ->expects($this->once()) diff --git a/tests/Unit/Routing/RoutingServiceProviderTest.php b/tests/Unit/Routing/RoutingServiceProviderTest.php index bb2a1d65..dd9441eb 100644 --- a/tests/Unit/Routing/RoutingServiceProviderTest.php +++ b/tests/Unit/Routing/RoutingServiceProviderTest.php @@ -1,6 +1,6 @@ Date: Mon, 20 Nov 2017 17:08:05 +0100 Subject: Added ExceptionHandler Interface --- includes/engelsystem.php | 2 +- src/Exceptions/BasicHandler.php | 119 +++++++++++++++++++++ src/Exceptions/ExceptionsServiceProvider.php | 5 +- src/Exceptions/Handler.php | 112 ++----------------- .../Exceptions/ExceptionsServiceProviderTest.php | 6 +- tests/Unit/Exceptions/HandlerTest.php | 38 +++++++ 6 files changed, 173 insertions(+), 109 deletions(-) create mode 100644 src/Exceptions/BasicHandler.php create mode 100644 tests/Unit/Exceptions/HandlerTest.php (limited to 'tests/Unit/Exceptions/ExceptionsServiceProviderTest.php') diff --git a/includes/engelsystem.php b/includes/engelsystem.php index 97076895..688ce49f 100644 --- a/includes/engelsystem.php +++ b/includes/engelsystem.php @@ -2,7 +2,7 @@ use Engelsystem\Application; use Engelsystem\Config\Config; -use Engelsystem\Exceptions\Handler as ExceptionHandler; +use Engelsystem\Exceptions\BasicHandler as ExceptionHandler; /** * This file includes all needed functions, connects to the db etc. diff --git a/src/Exceptions/BasicHandler.php b/src/Exceptions/BasicHandler.php new file mode 100644 index 00000000..2ba960a2 --- /dev/null +++ b/src/Exceptions/BasicHandler.php @@ -0,0 +1,119 @@ +exceptionHandler($exception); + } + + /** + * @param Throwable $e + */ + public function exceptionHandler($e) + { + $this->handle( + $e->getCode(), + get_class($e) . ': ' . $e->getMessage(), + $e->getFile(), + $e->getLine(), + ['exception' => $e] + ); + } + + /** + * @param int $number + * @param string $string + * @param string $file + * @param int $line + * @param array $context + * @param array $trace + */ + protected function handle($number, $string, $file, $line, $context = [], $trace = []) + { + error_log(sprintf('Exception: Number: %s, String: %s, File: %s:%u, Context: %s', + $number, + $string, + $file, + $line, + json_encode($context) + )); + + $file = $this->stripBasePath($file); + + if ($this->environment == self::ENV_DEVELOPMENT) { + echo '
';
+            echo sprintf('%s: (%s)' . PHP_EOL, ucfirst($type), $number);
+            var_export([
+                'string'     => $string,
+                'file'       => $file . ':' . $line,
+                'context'    => $context,
+                'stacktrace' => $this->formatStackTrace($trace),
+            ]);
+            echo '
'; + die(); + } + + echo 'An unexpected error occurred, a team of untrained monkeys has been dispatched to deal with it.'; + die(); + } + + /** + * @param array $stackTrace + * @return array + */ + protected function formatStackTrace($stackTrace) + { + $return = []; + + foreach ($stackTrace as $trace) { + $path = ''; + $line = ''; + + if (isset($trace['file']) && isset($trace['line'])) { + $path = $this->stripBasePath($trace['file']); + $line = $trace['line']; + } + + $functionName = $trace['function']; + + $return[] = [ + 'file' => $path . ':' . $line, + $functionName => $trace['args'], + ]; + } + + return $return; + } + + /** + * @param string $path + * @return string + */ + protected function stripBasePath($path) + { + $basePath = realpath(__DIR__ . '/../..') . '/'; + return str_replace($basePath, '', $path); + } +} diff --git a/src/Exceptions/ExceptionsServiceProvider.php b/src/Exceptions/ExceptionsServiceProvider.php index 7755e1e7..8eeccf61 100644 --- a/src/Exceptions/ExceptionsServiceProvider.php +++ b/src/Exceptions/ExceptionsServiceProvider.php @@ -3,13 +3,14 @@ namespace Engelsystem\Exceptions; use Engelsystem\Container\ServiceProvider; -use Engelsystem\Exceptions\Handler as ExceptionHandler; class ExceptionsServiceProvider extends ServiceProvider { public function register() { - $errorHandler = $this->app->make(ExceptionHandler::class); + $errorHandler = $this->app->make(BasicHandler::class); + $errorHandler->register(); $this->app->instance('error.handler', $errorHandler); + $this->app->bind(Handler::class, 'error.handler'); } } diff --git a/src/Exceptions/Handler.php b/src/Exceptions/Handler.php index 95bcd132..cdf94e32 100644 --- a/src/Exceptions/Handler.php +++ b/src/Exceptions/Handler.php @@ -2,9 +2,7 @@ namespace Engelsystem\Exceptions; -use Throwable; - -class Handler +abstract class Handler { /** @var string */ protected $environment; @@ -20,122 +18,28 @@ class Handler public function __construct($environment = self::ENV_PRODUCTION) { $this->environment = $environment; - - set_error_handler([$this, 'errorHandler']); - set_exception_handler([$this, 'exceptionHandler']); - } - - /** - * @param int $number - * @param string $string - * @param string $file - * @param int $line - * @param array $context - */ - public function errorHandler($number, $string, $file, $line, $context) - { - $trace = array_reverse(debug_backtrace()); - - $this->handle('error', $number, $string, $file, $line, $context, $trace); } /** - * @param Throwable $e + * Activate the error handler */ - public function exceptionHandler($e) + public function register() { - $this->handle( - 'exception', - $e->getCode(), - get_class($e) . ': ' . $e->getMessage(), - $e->getFile(), - $e->getLine(), - ['exception' => $e] - ); - } - - /** - * @param string $type - * @param int $number - * @param string $string - * @param string $file - * @param int $line - * @param array $context - * @param array $trace - */ - protected function handle($type, $number, $string, $file, $line, $context = [], $trace = []) - { - error_log(sprintf('%s: Number: %s, String: %s, File: %s:%u, Context: %s', - $type, - $number, - $string, - $file, - $line, - json_encode($context) - )); - - $file = $this->stripBasePath($file); - - if ($this->environment == self::ENV_DEVELOPMENT) { - echo '
';
-            echo sprintf('%s: (%s)' . PHP_EOL, ucfirst($type), $number);
-            var_export([
-                'string'     => $string,
-                'file'       => $file . ':' . $line,
-                'context'    => $context,
-                'stacktrace' => $this->formatStackTrace($trace),
-            ]);
-            echo '
'; - die(); - } - - echo 'An unexpected error occurred, a team of untrained monkeys has been dispatched to deal with it.'; - die(); } /** - * @param array $stackTrace - * @return array + * @param string $environment */ - protected function formatStackTrace($stackTrace) + public function setEnvironment($environment) { - $return = []; - - foreach ($stackTrace as $trace) { - $path = ''; - $line = ''; - - if (isset($trace['file']) && isset($trace['line'])) { - $path = $this->stripBasePath($trace['file']); - $line = $trace['line']; - } - - $functionName = $trace['function']; - - $return[] = [ - 'file' => $path . ':' . $line, - $functionName => $trace['args'], - ]; - } - - return $return; + $this->environment = $environment; } /** - * @param string $path * @return string */ - protected function stripBasePath($path) + public function getEnvironment() { - $basePath = realpath(__DIR__ . '/../..') . '/'; - return str_replace($basePath, '', $path); - } - - /** - * @param string $environment - */ - public function setEnvironment($environment) - { - $this->environment = $environment; + return $this->environment; } } diff --git a/tests/Unit/Exceptions/ExceptionsServiceProviderTest.php b/tests/Unit/Exceptions/ExceptionsServiceProviderTest.php index 9c943d52..01fb2f11 100644 --- a/tests/Unit/Exceptions/ExceptionsServiceProviderTest.php +++ b/tests/Unit/Exceptions/ExceptionsServiceProviderTest.php @@ -2,8 +2,9 @@ namespace Engelsystem\Test\Unit\Exceptions; +use Engelsystem\Exceptions\BasicHandler as ExceptionHandler; use Engelsystem\Exceptions\ExceptionsServiceProvider; -use Engelsystem\Exceptions\Handler as ExceptionHandler; +use Engelsystem\Exceptions\Handler; use Engelsystem\Test\Unit\ServiceProviderTest; use PHPUnit_Framework_MockObject_MockObject; @@ -18,10 +19,11 @@ class ExceptionsServiceProviderTest extends ServiceProviderTest $exceptionHandler = $this->getMockBuilder(ExceptionHandler::class) ->getMock(); - $app = $this->getApp(); + $app = $this->getApp(['make', 'instance', 'bind']); $this->setExpects($app, 'make', [ExceptionHandler::class], $exceptionHandler); $this->setExpects($app, 'instance', ['error.handler', $exceptionHandler]); + $this->setExpects($app, 'bind', [Handler::class, 'error.handler']); $serviceProvider = new ExceptionsServiceProvider($app); $serviceProvider->register(); diff --git a/tests/Unit/Exceptions/HandlerTest.php b/tests/Unit/Exceptions/HandlerTest.php new file mode 100644 index 00000000..29759be7 --- /dev/null +++ b/tests/Unit/Exceptions/HandlerTest.php @@ -0,0 +1,38 @@ +getMockForAbstractClass(Handler::class); + $this->assertInstanceOf(Handler::class, $handler); + $handler->register(); + } + + /** + * @covers \Engelsystem\Exceptions\Handler::setEnvironment() + * @covers \Engelsystem\Exceptions\Handler::getEnvironment() + */ + public function testEnvironment() + { + /** @var Handler|Mock $handler */ + $handler = $this->getMockForAbstractClass(Handler::class); + + $handler->setEnvironment(Handler::ENV_DEVELOPMENT); + $this->assertEquals(Handler::ENV_DEVELOPMENT, $handler->getEnvironment()); + + $handler->setEnvironment(Handler::ENV_PRODUCTION); + $this->assertEquals(Handler::ENV_PRODUCTION, $handler->getEnvironment()); + } +} -- cgit v1.2.3-54-g00ecf From 25e434bce4986b48bd72729a55aa1096e5a76be3 Mon Sep 17 00:00:00 2001 From: Igor Scheller Date: Fri, 24 Nov 2017 15:08:43 +0100 Subject: Refactored ExceptionHandler --- composer.json | 4 +- includes/engelsystem.php | 6 +- src/Exceptions/BasicHandler.php | 119 --------------------- src/Exceptions/ExceptionsServiceProvider.php | 46 +++++++- src/Exceptions/Handler.php | 100 ++++++++++++++++- src/Exceptions/Handlers/HandlerInterface.php | 21 ++++ src/Exceptions/Handlers/Legacy.php | 42 ++++++++ src/Exceptions/Handlers/LegacyDevelopment.php | 57 ++++++++++ src/Exceptions/Handlers/Whoops.php | 85 +++++++++++++++ .../Exceptions/ExceptionsServiceProviderTest.php | 94 ++++++++++++++-- tests/Unit/Exceptions/HandlerTest.php | 108 ++++++++++++++++++- .../Exceptions/Handlers/LegacyDevelopmentTest.php | 35 ++++++ tests/Unit/Exceptions/Handlers/LegacyTest.php | 55 ++++++++++ tests/Unit/Exceptions/Handlers/WhoopsTest.php | 83 ++++++++++++++ 14 files changed, 715 insertions(+), 140 deletions(-) delete mode 100644 src/Exceptions/BasicHandler.php create mode 100644 src/Exceptions/Handlers/HandlerInterface.php create mode 100644 src/Exceptions/Handlers/Legacy.php create mode 100644 src/Exceptions/Handlers/LegacyDevelopment.php create mode 100644 src/Exceptions/Handlers/Whoops.php create mode 100644 tests/Unit/Exceptions/Handlers/LegacyDevelopmentTest.php create mode 100644 tests/Unit/Exceptions/Handlers/LegacyTest.php create mode 100644 tests/Unit/Exceptions/Handlers/WhoopsTest.php (limited to 'tests/Unit/Exceptions/ExceptionsServiceProviderTest.php') diff --git a/composer.json b/composer.json index a8f0b0d6..ed34ba03 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,9 @@ "twbs/bootstrap": "^3.3" }, "require-dev": { - "phpunit/phpunit": "^6.3" + "filp/whoops": "^2.1", + "phpunit/phpunit": "^6.3", + "symfony/var-dumper": "^3.3" }, "autoload": { "psr-4": { diff --git a/includes/engelsystem.php b/includes/engelsystem.php index 688ce49f..07abbb42 100644 --- a/includes/engelsystem.php +++ b/includes/engelsystem.php @@ -2,7 +2,8 @@ use Engelsystem\Application; use Engelsystem\Config\Config; -use Engelsystem\Exceptions\BasicHandler as ExceptionHandler; +use Engelsystem\Exceptions\Handler; +use Engelsystem\Exceptions\Handlers\HandlerInterface; /** * This file includes all needed functions, connects to the db etc. @@ -32,7 +33,8 @@ date_default_timezone_set($app->get('config')->get('timezone')); if (config('environment') == 'development') { $errorHandler = $app->get('error.handler'); - $errorHandler->setEnvironment(ExceptionHandler::ENV_DEVELOPMENT); + $errorHandler->setEnvironment(Handler::ENV_DEVELOPMENT); + $app->bind(HandlerInterface::class, 'error.handler.development'); ini_set('display_errors', true); error_reporting(E_ALL); } else { diff --git a/src/Exceptions/BasicHandler.php b/src/Exceptions/BasicHandler.php deleted file mode 100644 index 2ba960a2..00000000 --- a/src/Exceptions/BasicHandler.php +++ /dev/null @@ -1,119 +0,0 @@ -exceptionHandler($exception); - } - - /** - * @param Throwable $e - */ - public function exceptionHandler($e) - { - $this->handle( - $e->getCode(), - get_class($e) . ': ' . $e->getMessage(), - $e->getFile(), - $e->getLine(), - ['exception' => $e] - ); - } - - /** - * @param int $number - * @param string $string - * @param string $file - * @param int $line - * @param array $context - * @param array $trace - */ - protected function handle($number, $string, $file, $line, $context = [], $trace = []) - { - error_log(sprintf('Exception: Number: %s, String: %s, File: %s:%u, Context: %s', - $number, - $string, - $file, - $line, - json_encode($context) - )); - - $file = $this->stripBasePath($file); - - if ($this->environment == self::ENV_DEVELOPMENT) { - echo '
';
-            echo sprintf('%s: (%s)' . PHP_EOL, ucfirst($type), $number);
-            var_export([
-                'string'     => $string,
-                'file'       => $file . ':' . $line,
-                'context'    => $context,
-                'stacktrace' => $this->formatStackTrace($trace),
-            ]);
-            echo '
'; - die(); - } - - echo 'An unexpected error occurred, a team of untrained monkeys has been dispatched to deal with it.'; - die(); - } - - /** - * @param array $stackTrace - * @return array - */ - protected function formatStackTrace($stackTrace) - { - $return = []; - - foreach ($stackTrace as $trace) { - $path = ''; - $line = ''; - - if (isset($trace['file']) && isset($trace['line'])) { - $path = $this->stripBasePath($trace['file']); - $line = $trace['line']; - } - - $functionName = $trace['function']; - - $return[] = [ - 'file' => $path . ':' . $line, - $functionName => $trace['args'], - ]; - } - - return $return; - } - - /** - * @param string $path - * @return string - */ - protected function stripBasePath($path) - { - $basePath = realpath(__DIR__ . '/../..') . '/'; - return str_replace($basePath, '', $path); - } -} diff --git a/src/Exceptions/ExceptionsServiceProvider.php b/src/Exceptions/ExceptionsServiceProvider.php index 8eeccf61..a9bc2b17 100644 --- a/src/Exceptions/ExceptionsServiceProvider.php +++ b/src/Exceptions/ExceptionsServiceProvider.php @@ -3,14 +3,56 @@ namespace Engelsystem\Exceptions; use Engelsystem\Container\ServiceProvider; +use Engelsystem\Exceptions\Handlers\HandlerInterface; +use Engelsystem\Exceptions\Handlers\Legacy; +use Engelsystem\Exceptions\Handlers\LegacyDevelopment; +use Engelsystem\Exceptions\Handlers\Whoops; +use Whoops\Run as WhoopsRunner; class ExceptionsServiceProvider extends ServiceProvider { public function register() { - $errorHandler = $this->app->make(BasicHandler::class); - $errorHandler->register(); + $errorHandler = $this->app->make(Handler::class); + $this->addProductionHandler($errorHandler); + $this->addDevelopmentHandler($errorHandler); $this->app->instance('error.handler', $errorHandler); $this->app->bind(Handler::class, 'error.handler'); + $errorHandler->register(); + } + + public function boot() + { + /** @var Handler $handler */ + $handler = $this->app->get('error.handler'); + $request = $this->app->get('request'); + + $handler->setRequest($request); + } + + /** + * @param Handler $errorHandler + */ + protected function addProductionHandler($errorHandler) + { + $handler = $this->app->make(Legacy::class); + $this->app->instance('error.handler.production', $handler); + $errorHandler->setHandler(Handler::ENV_PRODUCTION, $handler); + $this->app->bind(HandlerInterface::class, 'error.handler.production'); + } + + /** + * @param Handler $errorHandler + */ + protected function addDevelopmentHandler($errorHandler) + { + $handler = $this->app->make(LegacyDevelopment::class); + + if (class_exists(WhoopsRunner::class)) { + $handler = $this->app->make(Whoops::class); + } + + $this->app->instance('error.handler.development', $handler); + $errorHandler->setHandler(Handler::ENV_DEVELOPMENT, $handler); } } diff --git a/src/Exceptions/Handler.php b/src/Exceptions/Handler.php index cdf94e32..ee15717a 100644 --- a/src/Exceptions/Handler.php +++ b/src/Exceptions/Handler.php @@ -2,18 +2,29 @@ namespace Engelsystem\Exceptions; -abstract class Handler +use Engelsystem\Exceptions\Handlers\HandlerInterface; +use Engelsystem\Http\Request; +use ErrorException; +use Throwable; + +class Handler { /** @var string */ protected $environment; + /** @var HandlerInterface[] */ + protected $handler = []; + + /** @var Request */ + protected $request; + const ENV_PRODUCTION = 'prod'; const ENV_DEVELOPMENT = 'dev'; /** * Handler constructor. * - * @param string $environment production|development + * @param string $environment prod|dev */ public function __construct($environment = self::ENV_PRODUCTION) { @@ -25,14 +36,47 @@ abstract class Handler */ public function register() { + set_error_handler([$this, 'errorHandler']); + set_exception_handler([$this, 'exceptionHandler']); } /** - * @param string $environment + * @param int $number + * @param string $message + * @param string $file + * @param int $line */ - public function setEnvironment($environment) + public function errorHandler($number, $message, $file, $line) { - $this->environment = $environment; + $exception = new ErrorException($message, 0, $number, $file, $line); + $this->exceptionHandler($exception); + } + + /** + * @param Throwable $e + */ + public function exceptionHandler($e) + { + if (!$this->request instanceof Request) { + $this->request = new Request(); + } + + $handler = $this->handler[$this->environment]; + $handler->report($e); + $handler->render($this->request, $e); + $this->die(); + } + + /** + * Exit the application + * + * @codeCoverageIgnore + * @param string $message + */ + protected function die($message = '') + { + echo $message; + die(); } /** @@ -42,4 +86,50 @@ abstract class Handler { return $this->environment; } + + /** + * @param string $environment + */ + public function setEnvironment($environment) + { + $this->environment = $environment; + } + + /** + * @param string $environment + * @return HandlerInterface|HandlerInterface[] + */ + public function getHandler($environment = null) + { + if (!is_null($environment)) { + return $this->handler[$environment]; + } + + return $this->handler; + } + + /** + * @param string $environment + * @param HandlerInterface $handler + */ + public function setHandler($environment, HandlerInterface $handler) + { + $this->handler[$environment] = $handler; + } + + /** + * @return Request + */ + public function getRequest() + { + return $this->request; + } + + /** + * @param Request $request + */ + public function setRequest(Request $request) + { + $this->request = $request; + } } diff --git a/src/Exceptions/Handlers/HandlerInterface.php b/src/Exceptions/Handlers/HandlerInterface.php new file mode 100644 index 00000000..9de33e1f --- /dev/null +++ b/src/Exceptions/Handlers/HandlerInterface.php @@ -0,0 +1,21 @@ +unexpected error occurred, a team of untrained monkeys has been dispatched to deal with it.'; + } + + /** + * @param Throwable $e + */ + public function report(Throwable $e) + { + error_log(sprintf('Exception: Code: %s, Message: %s, File: %s:%u, Trace: %s', + $e->getCode(), + $e->getMessage(), + $this->stripBasePath($e->getFile()), + $e->getLine(), + json_encode($e->getTrace()) + )); + } + + /** + * @param string $path + * @return string + */ + protected function stripBasePath($path) + { + $basePath = realpath(__DIR__ . '/../../..') . '/'; + return str_replace($basePath, '', $path); + } +} diff --git a/src/Exceptions/Handlers/LegacyDevelopment.php b/src/Exceptions/Handlers/LegacyDevelopment.php new file mode 100644 index 00000000..86f86f4c --- /dev/null +++ b/src/Exceptions/Handlers/LegacyDevelopment.php @@ -0,0 +1,57 @@ +stripBasePath($e->getFile()); + + echo '
';
+        echo sprintf('%s: (%s)' . PHP_EOL, get_class($e), $e->getCode());
+        $data = [
+            'string'     => $e->getMessage(),
+            'file'       => $file . ':' . $e->getLine(),
+            'stacktrace' => $this->formatStackTrace($e->getTrace()),
+        ];
+        var_dump($data);
+        echo '
'; + } + + /** + * @param array $stackTrace + * @return array + */ + protected function formatStackTrace($stackTrace) + { + $return = []; + $stackTrace = array_reverse($stackTrace); + + foreach ($stackTrace as $trace) { + $path = ''; + $line = ''; + + if (isset($trace['file']) && isset($trace['line'])) { + $path = $this->stripBasePath($trace['file']); + $line = $trace['line']; + } + + $functionName = $trace['function']; + + $return[] = [ + 'file' => $path . ':' . $line, + $functionName => isset($trace['args']) ? $trace['args'] : null, + ]; + } + + return $return; + } +} diff --git a/src/Exceptions/Handlers/Whoops.php b/src/Exceptions/Handlers/Whoops.php new file mode 100644 index 00000000..807f5eb0 --- /dev/null +++ b/src/Exceptions/Handlers/Whoops.php @@ -0,0 +1,85 @@ +app = $app; + } + + /** + * @param Request $request + * @param Throwable $e + */ + public function render($request, Throwable $e) + { + $whoops = $this->app->make(WhoopsRunner::class); + $handler = $this->getPrettyPageHandler($e); + $whoops->pushHandler($handler); + + if ($request->isXmlHttpRequest()) { + $handler = $this->getJsonResponseHandler(); + $whoops->pushHandler($handler); + } + + echo $whoops->handleException($e); + } + + /** + * @param Throwable $e + * @return PrettyPageHandler + */ + protected function getPrettyPageHandler(Throwable $e) + { + $handler = $this->app->make(PrettyPageHandler::class); + + $handler->setPageTitle('Just another ' . get_class($e) . ' to fix :('); + $handler->setApplicationPaths([realpath(__DIR__ . '/../..')]); + + $data = $this->getData(); + $handler->addDataTable('Application', $data); + + return $handler; + } + + /** + * @return JsonResponseHandler + */ + protected function getJsonResponseHandler() + { + $handler = $this->app->make(JsonResponseHandler::class); + $handler->setJsonApi(true); + $handler->addTraceToOutput(true); + + return $handler; + } + + /** + * Aggregate application data + * + * @return array + */ + protected function getData() + { + global $user; + + $data = []; + $data['user'] = $user; + $data['Booted'] = $this->app->isBooted(); + + return $data; + } +} diff --git a/tests/Unit/Exceptions/ExceptionsServiceProviderTest.php b/tests/Unit/Exceptions/ExceptionsServiceProviderTest.php index 01fb2f11..4f2ae654 100644 --- a/tests/Unit/Exceptions/ExceptionsServiceProviderTest.php +++ b/tests/Unit/Exceptions/ExceptionsServiceProviderTest.php @@ -2,30 +2,108 @@ namespace Engelsystem\Test\Unit\Exceptions; -use Engelsystem\Exceptions\BasicHandler as ExceptionHandler; use Engelsystem\Exceptions\ExceptionsServiceProvider; use Engelsystem\Exceptions\Handler; +use Engelsystem\Exceptions\Handlers\HandlerInterface; +use Engelsystem\Exceptions\Handlers\Legacy; +use Engelsystem\Exceptions\Handlers\LegacyDevelopment; +use Engelsystem\Exceptions\Handlers\Whoops; +use Engelsystem\Http\Request; use Engelsystem\Test\Unit\ServiceProviderTest; -use PHPUnit_Framework_MockObject_MockObject; +use PHPUnit_Framework_MockObject_MockObject as MockObject; class ExceptionsServiceProviderTest extends ServiceProviderTest { /** * @covers \Engelsystem\Exceptions\ExceptionsServiceProvider::register() + * @covers \Engelsystem\Exceptions\ExceptionsServiceProvider::addProductionHandler() + * @covers \Engelsystem\Exceptions\ExceptionsServiceProvider::addDevelopmentHandler() */ public function testRegister() { - /** @var PHPUnit_Framework_MockObject_MockObject|ExceptionHandler $exceptionHandler */ - $exceptionHandler = $this->getMockBuilder(ExceptionHandler::class) + $app = $this->getApp(['make', 'instance', 'bind']); + + /** @var MockObject|Handler $handler */ + $handler = $this->createMock(Handler::class); + $this->setExpects($handler, 'register'); + /** @var Legacy|MockObject $legacyHandler */ + $legacyHandler = $this->createMock(Legacy::class); + /** @var LegacyDevelopment|MockObject $developmentHandler */ + $developmentHandler = $this->createMock(LegacyDevelopment::class); + + $whoopsHandler = $this->getMockBuilder(Whoops::class) + ->setConstructorArgs([$app]) ->getMock(); - $app = $this->getApp(['make', 'instance', 'bind']); + $app->expects($this->exactly(3)) + ->method('instance') + ->withConsecutive( + ['error.handler.production', $legacyHandler], + ['error.handler.development', $whoopsHandler], + ['error.handler', $handler] + ); - $this->setExpects($app, 'make', [ExceptionHandler::class], $exceptionHandler); - $this->setExpects($app, 'instance', ['error.handler', $exceptionHandler]); - $this->setExpects($app, 'bind', [Handler::class, 'error.handler']); + $app->expects($this->exactly(4)) + ->method('make') + ->withConsecutive( + [Handler::class], + [Legacy::class], + [LegacyDevelopment::class], + [Whoops::class] + ) + ->willReturnOnConsecutiveCalls( + $handler, + $legacyHandler, + $developmentHandler, + $whoopsHandler + ); + + $app->expects($this->exactly(2)) + ->method('bind') + ->withConsecutive( + [HandlerInterface::class, 'error.handler.production'], + [Handler::class, 'error.handler'] + ); + + $handler->expects($this->exactly(2)) + ->method('setHandler') + ->withConsecutive( + [Handler::ENV_PRODUCTION, $legacyHandler], + [Handler::ENV_DEVELOPMENT, $whoopsHandler] + ); $serviceProvider = new ExceptionsServiceProvider($app); $serviceProvider->register(); } + + /** + * @covers \Engelsystem\Exceptions\ExceptionsServiceProvider::boot() + */ + public function testBoot() + { + /** @var MockObject|Handler $handler */ + $handler = $this->createMock(Handler::class); + + /** @var MockObject|Request $request */ + $request = $this->createMock(Request::class); + + $handler->expects($this->once()) + ->method('setRequest') + ->with($request); + + $app = $this->getApp(['get']); + $app->expects($this->exactly(2)) + ->method('get') + ->withConsecutive( + ['error.handler'], + ['request'] + ) + ->willReturnOnConsecutiveCalls( + $handler, + $request + ); + + $provider = new ExceptionsServiceProvider($app); + $provider->boot(); + } } diff --git a/tests/Unit/Exceptions/HandlerTest.php b/tests/Unit/Exceptions/HandlerTest.php index 29759be7..40202be8 100644 --- a/tests/Unit/Exceptions/HandlerTest.php +++ b/tests/Unit/Exceptions/HandlerTest.php @@ -3,6 +3,10 @@ namespace Engelsystem\Test\Unit\Exceptions; use Engelsystem\Exceptions\Handler; +use Engelsystem\Exceptions\Handlers\HandlerInterface; +use Engelsystem\Http\Request; +use ErrorException; +use Exception; use PHPUnit\Framework\TestCase; use PHPUnit_Framework_MockObject_MockObject as Mock; @@ -10,14 +14,80 @@ class HandlerTest extends TestCase { /** * @covers \Engelsystem\Exceptions\Handler::__construct() + */ + public function testCreate() + { + /** @var Handler|Mock $handler */ + $handler = new Handler(); + $this->assertInstanceOf(Handler::class, $handler); + $this->assertEquals(Handler::ENV_PRODUCTION, $handler->getEnvironment()); + + $anotherHandler = new Handler(Handler::ENV_DEVELOPMENT); + $this->assertEquals(Handler::ENV_DEVELOPMENT, $anotherHandler->getEnvironment()); + } + + /** + * @covers \Engelsystem\Exceptions\Handler::errorHandler() + */ + public function testErrorHandler() + { + /** @var Handler|Mock $handler */ + $handler = $this->getMockBuilder(Handler::class) + ->setMethods(['exceptionHandler']) + ->getMock(); + + $handler->expects($this->once()) + ->method('exceptionHandler') + ->with($this->isInstanceOf(ErrorException::class)); + + $handler->errorHandler(1, 'Foo and bar!', '/lo/rem.php', 123); + } + + /** + * @covers \Engelsystem\Exceptions\Handler::exceptionHandler() + */ + public function testExceptionHandler() + { + $exception = new Exception(); + + /** @var HandlerInterface|Mock $handlerMock */ + $handlerMock = $this->getMockForAbstractClass(HandlerInterface::class); + $handlerMock->expects($this->once()) + ->method('report') + ->with($exception); + $handlerMock->expects($this->once()) + ->method('render') + ->with($this->isInstanceOf(Request::class), $exception); + + /** @var Handler|Mock $handler */ + $handler = $this->getMockBuilder(Handler::class) + ->setMethods(['die']) + ->getMock(); + $handler->expects($this->once()) + ->method('die'); + + $handler->setHandler(Handler::ENV_PRODUCTION, $handlerMock); + + $handler->exceptionHandler($exception); + } + + /** * @covers \Engelsystem\Exceptions\Handler::register() */ public function testRegister() { /** @var Handler|Mock $handler */ $handler = $this->getMockForAbstractClass(Handler::class); - $this->assertInstanceOf(Handler::class, $handler); $handler->register(); + + set_error_handler($errorHandler = set_error_handler('var_dump')); + $this->assertEquals($handler, array_shift($errorHandler)); + + set_exception_handler($exceptionHandler = set_error_handler('var_dump')); + $this->assertEquals($handler, array_shift($exceptionHandler)); + + restore_error_handler(); + restore_exception_handler(); } /** @@ -26,8 +96,7 @@ class HandlerTest extends TestCase */ public function testEnvironment() { - /** @var Handler|Mock $handler */ - $handler = $this->getMockForAbstractClass(Handler::class); + $handler = new Handler(); $handler->setEnvironment(Handler::ENV_DEVELOPMENT); $this->assertEquals(Handler::ENV_DEVELOPMENT, $handler->getEnvironment()); @@ -35,4 +104,37 @@ class HandlerTest extends TestCase $handler->setEnvironment(Handler::ENV_PRODUCTION); $this->assertEquals(Handler::ENV_PRODUCTION, $handler->getEnvironment()); } + + /** + * @covers \Engelsystem\Exceptions\Handler::setHandler() + * @covers \Engelsystem\Exceptions\Handler::getHandler() + */ + public function testHandler() + { + $handler = new Handler(); + /** @var HandlerInterface|Mock $devHandler */ + $devHandler = $this->getMockForAbstractClass(HandlerInterface::class); + /** @var HandlerInterface|Mock $prodHandler */ + $prodHandler = $this->getMockForAbstractClass(HandlerInterface::class); + + $handler->setHandler(Handler::ENV_DEVELOPMENT, $devHandler); + $handler->setHandler(Handler::ENV_PRODUCTION, $prodHandler); + $this->assertEquals($devHandler, $handler->getHandler(Handler::ENV_DEVELOPMENT)); + $this->assertEquals($prodHandler, $handler->getHandler(Handler::ENV_PRODUCTION)); + $this->assertCount(2, $handler->getHandler()); + } + + /** + * @covers \Engelsystem\Exceptions\Handler::setRequest() + * @covers \Engelsystem\Exceptions\Handler::getRequest() + */ + public function testRequest() + { + $handler = new Handler(); + /** @var Request|Mock $request */ + $request = $this->createMock(Request::class); + + $handler->setRequest($request); + $this->assertEquals($request, $handler->getRequest()); + } } diff --git a/tests/Unit/Exceptions/Handlers/LegacyDevelopmentTest.php b/tests/Unit/Exceptions/Handlers/LegacyDevelopmentTest.php new file mode 100644 index 00000000..d5390c9e --- /dev/null +++ b/tests/Unit/Exceptions/Handlers/LegacyDevelopmentTest.php @@ -0,0 +1,35 @@ +createMock(Request::class); + $exception = new ErrorException('Lorem Ipsum', 4242, 1, 'foo.php', 9999); + + $regex = sprintf( + '%%.*ErrorException.*4242.*Lorem Ipsum.*%s.*%s.*%s.*%%is', + 'foo.php', + 9999, + __FUNCTION__ + ); + $this->expectOutputRegex($regex); + + $handler->render($request, $exception); + } +} diff --git a/tests/Unit/Exceptions/Handlers/LegacyTest.php b/tests/Unit/Exceptions/Handlers/LegacyTest.php new file mode 100644 index 00000000..04b214f2 --- /dev/null +++ b/tests/Unit/Exceptions/Handlers/LegacyTest.php @@ -0,0 +1,55 @@ +createMock(Request::class); + /** @var Exception|Mock $exception */ + $exception = $this->createMock(Exception::class); + + $this->expectOutputRegex('/.*error occurred.*/i'); + + $handler->render($request, $exception); + } + + /** + * @covers \Engelsystem\Exceptions\Handlers\Legacy::report() + * @covers \Engelsystem\Exceptions\Handlers\Legacy::stripBasePath() + */ + public function testReport() + { + $handler = new Legacy(); + $exception = new Exception('Lorem Ipsum', 4242); + $line = __LINE__ - 1; + + $log = tempnam(sys_get_temp_dir(), 'engelsystem-log'); + $errorLog = ini_get('error_log'); + ini_set('error_log', $log); + $handler->report($exception); + ini_set('error_log', $errorLog); + $logContent = file_get_contents($log); + unset($log); + + $this->assertContains('4242', $logContent); + $this->assertContains('Lorem Ipsum', $logContent); + $this->assertContains(basename(__FILE__), $logContent); + $this->assertContains((string)$line, $logContent); + $this->assertContains(__FUNCTION__, $logContent); + $this->assertContains(json_encode(__CLASS__), $logContent); + } +} diff --git a/tests/Unit/Exceptions/Handlers/WhoopsTest.php b/tests/Unit/Exceptions/Handlers/WhoopsTest.php new file mode 100644 index 00000000..261ee83f --- /dev/null +++ b/tests/Unit/Exceptions/Handlers/WhoopsTest.php @@ -0,0 +1,83 @@ +createMock(Application::class); + /** @var Request|Mock $request */ + $request = $this->createMock(Request::class); + $request->expects($this->once()) + ->method('isXmlHttpRequest') + ->willReturn(true); + /** @var WhoopsRunnerInterface|Mock $whoopsRunner */ + $whoopsRunner = $this->getMockForAbstractClass(WhoopsRunnerInterface::class); + /** @var PrettyPageHandler|Mock $prettyPageHandler */ + $prettyPageHandler = $this->createMock(PrettyPageHandler::class); + $prettyPageHandler + ->expects($this->atLeastOnce()) + ->method('setApplicationPaths'); + $prettyPageHandler + ->expects($this->once()) + ->method('setApplicationPaths'); + $prettyPageHandler + ->expects($this->once()) + ->method('addDataTable'); + /** @var JsonResponseHandler|Mock $jsonResponseHandler */ + $jsonResponseHandler = $this->createMock(JsonResponseHandler::class); + $jsonResponseHandler->expects($this->once()) + ->method('setJsonApi') + ->with(true); + $jsonResponseHandler->expects($this->once()) + ->method('addTraceToOutput') + ->with(true); + /** @var Exception|Mock $exception */ + $exception = $this->createMock(Exception::class); + + $app->expects($this->exactly(3)) + ->method('make') + ->withConsecutive( + [WhoopsRunner::class], + [PrettyPageHandler::class], + [JsonResponseHandler::class] + ) + ->willReturnOnConsecutiveCalls( + $whoopsRunner, + $prettyPageHandler, + $jsonResponseHandler + ); + + $whoopsRunner + ->expects($this->exactly(2)) + ->method('pushHandler') + ->withConsecutive( + [$prettyPageHandler], + [$jsonResponseHandler] + ); + $whoopsRunner + ->expects($this->once()) + ->method('handleException') + ->with($exception); + + $handler = new Whoops($app); + $handler->render($request, $exception); + } +} -- cgit v1.2.3-54-g00ecf