/test/Unit/Error/Registry/ErrorHandlerRegistryTest.php

https://github.com/szeber/yapep_base · PHP · 356 lines · 283 code · 62 blank · 11 comment · 0 complexity · 3a55a39a20c7c9fdcefbe8c6804ba6f4 MD5 · raw file

  1. <?php
  2. declare(strict_types=1);
  3. namespace PHPUnit\Framework\Error\Registry;
  4. use Mockery\MockInterface;
  5. use YapepBase\Error\Entity\Error;
  6. use YapepBase\Error\Entity\ExceptionEntity;
  7. use YapepBase\Error\Handler\IErrorHandler;
  8. use YapepBase\Error\Helper\ErrorHelper;
  9. use YapepBase\Error\Registry\ErrorHandlerRegistry;
  10. use YapepBase\Error\Registry\IIdGenerator;
  11. use YapepBase\ErrorHandler\ITerminatable;
  12. use YapepBase\Event\Entity\Event;
  13. use YapepBase\Event\IEventHandlerRegistry;
  14. use YapepBase\Response\IResponse;
  15. use YapepBase\Test\Unit\TestAbstract;
  16. class ErrorHandlerRegistryTest extends TestAbstract
  17. {
  18. /** @var IIdGenerator|MockInterface */
  19. private $idGenerator;
  20. /** @var ErrorHelper|MockInterface */
  21. private $errorHelper;
  22. /** @var IResponse|MockInterface */
  23. private $response;
  24. /** @var IErrorHandler|MockInterface */
  25. private $errorHandler;
  26. /** @var IEventHandlerRegistry|MockInterface */
  27. private $eventHandler;
  28. /** @var ITerminatable|MockInterface */
  29. private $terminator;
  30. /** @var int */
  31. private $originalErrorReportingLevel;
  32. /** @var int */
  33. private $errorCode = E_USER_WARNING;
  34. /** @var string */
  35. private $message = 'message';
  36. /** @var string */
  37. private $file = 'file';
  38. /** @var int */
  39. private $line = 2;
  40. protected function setUp(): void
  41. {
  42. parent::setUp(); // TODO: Change the autogenerated stub
  43. $this->idGenerator = \Mockery::mock(IIdGenerator::class);
  44. $this->errorHelper = \Mockery::mock(ErrorHelper::class);
  45. $this->response = \Mockery::mock(IResponse::class);
  46. $this->errorHandler = \Mockery::mock(IErrorHandler::class);
  47. $this->eventHandler = \Mockery::mock(IEventHandlerRegistry::class);
  48. $this->terminator = \Mockery::mock(ITerminatable::class);
  49. $this->originalErrorReportingLevel = error_reporting();
  50. }
  51. protected function tearDown(): void
  52. {
  53. error_reporting($this->originalErrorReportingLevel);
  54. parent::tearDown();
  55. }
  56. public function testAddErrorHandler_shouldAdd()
  57. {
  58. $registry = $this->getErrorHandlerRegistry();
  59. $handler1 = \Mockery::mock(IErrorHandler::class);
  60. $handler2 = \Mockery::mock(IErrorHandler::class);
  61. $registry->add($handler1);
  62. $registry->add($handler2);
  63. $registeredErrorHandlers = $registry->getAll();
  64. $this->assertSame($handler1, $registeredErrorHandlers[0]);
  65. $this->assertSame($handler2, $registeredErrorHandlers[1]);
  66. }
  67. public function testRemoveErrorHandler_shouldRemove()
  68. {
  69. $registry = $this->getErrorHandlerRegistry();
  70. $handler1 = \Mockery::mock(IErrorHandler::class);
  71. $handler2 = \Mockery::mock(IErrorHandler::class);
  72. $registry->add($handler1);
  73. $registry->add($handler2);
  74. $registry->remove($handler1);
  75. $registeredErrorHandlers = $registry->getAll();
  76. $this->assertSame($handler2, $registeredErrorHandlers[1]);
  77. $this->assertCount(1, $registeredErrorHandlers);
  78. }
  79. public function testHandleErrorWhenNoHandlerRegistered_shouldDoNothing()
  80. {
  81. $this->getErrorHandlerRegistry()->handleError(1, 'message', 'file', 2);
  82. $this->assertTrue(true);
  83. }
  84. public function testHandleErrorWhenErrorReportingIgnoresError_shouldDoNothing()
  85. {
  86. $registry = $this->getErrorHandlerRegistry();
  87. $registry->add($this->errorHandler);
  88. error_reporting(0);
  89. $registry->handleError(1, 'message', 'file', 2);
  90. $this->assertTrue(true);
  91. }
  92. public function testHandleError_shouldUseErrorHandler()
  93. {
  94. $registry = $this->getErrorHandlerRegistry();
  95. $registry->add($this->errorHandler);
  96. $this->expectIdGenerated();
  97. $this->expectErrorHandled();
  98. $this->expectCheckedIfErrorIsFatal(false);
  99. $registry->handleError($this->errorCode, $this->message, $this->file, $this->line);
  100. }
  101. public function testHandleErrorWhenFatal_shouldSendResponseAndExit()
  102. {
  103. $registry = $this->getErrorHandlerRegistry($this->response);
  104. $registry->add($this->errorHandler);
  105. $this->expectIdGenerated();
  106. $this->expectErrorHandled();
  107. $this->expectCheckedIfErrorIsFatal(true);
  108. $this->expectSendErrorResponse();
  109. $this->expectExit();
  110. $registry->handleError($this->errorCode, $this->message, $this->file, $this->line);
  111. }
  112. public function testHandleExceptionWhenNoHandlersRegistered_shouldTriggerError()
  113. {
  114. $registry = $this->getErrorHandlerRegistry();
  115. $this->expectException(\PHPUnit\Framework\Error\Error::class);
  116. $registry->handleException(new \Exception());
  117. }
  118. public function testHandleException_shouldUseErrorHandler()
  119. {
  120. $registry = $this->getErrorHandlerRegistry();
  121. $registry->add($this->errorHandler);
  122. $this->expectIdGenerated();
  123. $this->expectExceptionHandled();
  124. $registry->handleException(new \Exception($this->message, $this->errorCode));
  125. }
  126. public function testHandleShutdownWhenNoErrorOccurred_shouldTerminate()
  127. {
  128. $errorHandlerRegistry = $this->getErrorHandlerRegistry();
  129. $this->expectLastError(null);
  130. $this->expectEventChecked(Event::APPLICATION_STARTED, true);
  131. $this->expectExit();
  132. $errorHandlerRegistry->handleShutdown();
  133. }
  134. public function testHandleShutdownWhenErrorNotFatal_shouldTerminate()
  135. {
  136. $errorHandlerRegistry = $this->getErrorHandlerRegistry();
  137. $this->expectLastError(new Error($this->errorCode, $this->message, $this->file, $this->line));
  138. $this->expectEventChecked(Event::APPLICATION_FINISHED, false);
  139. $this->expectCheckedIfErrorIsFatal(false);
  140. $this->expectEventChecked(Event::APPLICATION_STARTED, true);
  141. $this->expectExit();
  142. $errorHandlerRegistry->handleShutdown();
  143. }
  144. public function testHandleShutdownWhenApplicationRanSuccessfully_shouldTerminate()
  145. {
  146. $errorHandlerRegistry = $this->getErrorHandlerRegistry();
  147. $this->expectLastError(new Error($this->errorCode, $this->message, $this->file, $this->line));
  148. $this->expectEventChecked(Event::APPLICATION_FINISHED, true);
  149. $this->expectEventChecked(Event::APPLICATION_STARTED, true);
  150. $this->expectExit();
  151. $errorHandlerRegistry->handleShutdown();
  152. }
  153. public function testHandleShutdownWhenShouldTerminateAndApplicationNotStartedYet_shouldSendErrorResponse()
  154. {
  155. $errorHandlerRegistry = $this->getErrorHandlerRegistry($this->response);
  156. $this->expectLastError(null);
  157. $this->expectEventChecked(Event::APPLICATION_STARTED, false);
  158. $this->expectSendErrorResponse();
  159. $this->expectExit();
  160. $errorHandlerRegistry->handleShutdown();
  161. }
  162. public function testHandleShutdownWhenShouldTerminateAndTerminatorAdded_shouldUseTerminator()
  163. {
  164. $errorHandlerRegistry = $this->getErrorHandlerRegistry();
  165. $this->expectTerminatorCalled(false);
  166. $errorHandlerRegistry->setTerminator($this->terminator);
  167. $this->expectLastError(null);
  168. $this->expectEventChecked(Event::APPLICATION_STARTED, true);
  169. $this->expectExit();
  170. $errorHandlerRegistry->handleShutdown();
  171. }
  172. public function testHandleShutdownNoErrorHandlers_shouldLogError()
  173. {
  174. $errorHandlerRegistry = $this->getErrorHandlerRegistry();
  175. $this->expectLastError(new Error($this->errorCode, $this->message, $this->file, $this->line));
  176. $this->expectEventChecked(Event::APPLICATION_FINISHED, false);
  177. $this->expectCheckedIfErrorIsFatal(true);
  178. $this->expectEventChecked(Event::APPLICATION_STARTED, true);
  179. $this->expectErrorLoggedDirectly('No error handlers are defined and a fatal error occurred');
  180. $this->expectExit();
  181. $errorHandlerRegistry->handleShutdown();
  182. }
  183. public function testHandleShutdown_shouldCallErrorHandlers()
  184. {
  185. $errorHandlerRegistry = $this->getErrorHandlerRegistry();
  186. $errorHandlerRegistry->add($this->errorHandler);
  187. $this->expectLastError(new Error($this->errorCode, $this->message, $this->file, $this->line));
  188. $this->expectEventChecked(Event::APPLICATION_FINISHED, false);
  189. $this->expectCheckedIfErrorIsFatal(true);
  190. $this->expectEventChecked(Event::APPLICATION_STARTED, true);
  191. $this->expectIdGenerated();
  192. $this->expectShutdownHandled();
  193. $this->expectExit();
  194. $errorHandlerRegistry->handleShutdown();
  195. }
  196. private function expectIdGenerated(): void
  197. {
  198. $this->idGenerator->shouldReceive('generateId');
  199. }
  200. private function expectErrorHandled(): void
  201. {
  202. $this->errorHandler
  203. ->shouldReceive('handleError')
  204. ->once()
  205. ->with(\Mockery::on(function (Error $error) {
  206. $this->assertSame($this->errorCode, $error->getCode());
  207. $this->assertSame($this->message, $error->getMessage());
  208. $this->assertSame($this->file, $error->getFile());
  209. $this->assertSame($this->line, $error->getLine());
  210. return true;
  211. }));
  212. }
  213. private function expectExceptionHandled(): void
  214. {
  215. $this->errorHandler
  216. ->shouldReceive('handleException')
  217. ->once()
  218. ->with(\Mockery::on(function (ExceptionEntity $exception) {
  219. $this->assertSame($this->message, $exception->getException()->getMessage());
  220. $this->assertSame($this->errorCode, $exception->getException()->getCode());
  221. return true;
  222. }));
  223. }
  224. private function expectShutdownHandled(): void
  225. {
  226. $this->errorHandler
  227. ->shouldReceive('handleShutdown')
  228. ->once()
  229. ->with(\Mockery::on(function (Error $error) {
  230. $this->assertSame($this->errorCode, $error->getCode());
  231. $this->assertSame($this->message, $error->getMessage());
  232. $this->assertSame($this->file, $error->getFile());
  233. $this->assertSame($this->line, $error->getLine());
  234. return true;
  235. }));
  236. }
  237. private function expectCheckedIfErrorIsFatal(bool $expectedResult): void
  238. {
  239. $this->errorHelper
  240. ->shouldReceive('isFatal')
  241. ->once()
  242. ->with($this->errorCode)
  243. ->andReturn($expectedResult);
  244. }
  245. private function expectExit(): void
  246. {
  247. $this->errorHelper->shouldReceive('exit');
  248. }
  249. private function expectLastError($expectedResult): void
  250. {
  251. $this->errorHelper
  252. ->shouldReceive('getLastError')
  253. ->once()
  254. ->andReturn($expectedResult);
  255. }
  256. private function expectErrorLoggedDirectly(string $expectedMessagePrefix)
  257. {
  258. $this->errorHelper
  259. ->shouldReceive('log')
  260. ->once()
  261. ->with(\Mockery::on(function ($message) use ($expectedMessagePrefix) {
  262. $this->assertStringContainsString($expectedMessagePrefix, $message);
  263. $this->assertStringContainsString($this->message, $message);
  264. $this->assertStringContainsString($this->file, $message);
  265. $this->assertStringContainsString((string)$this->line, $message);
  266. $this->assertStringContainsString((string)$this->errorCode, $message);
  267. return true;
  268. }));
  269. }
  270. private function expectSendErrorResponse(): void
  271. {
  272. $this->response->shouldReceive('sendError');
  273. }
  274. private function expectEventChecked(string $event, bool $expectedResult): void
  275. {
  276. $this->eventHandler
  277. ->shouldReceive('isRaised')
  278. ->with($event)
  279. ->andReturn($expectedResult)
  280. ->getMock();
  281. $this->pimpleContainer->setEventHandlerRegistry($this->eventHandler);
  282. }
  283. private function expectTerminatorCalled(bool $isFatalError): void
  284. {
  285. $this->terminator
  286. ->shouldReceive('terminate')
  287. ->once()
  288. ->with($isFatalError);
  289. }
  290. private function getErrorHandlerRegistry(?IResponse $response = null): ErrorHandlerRegistry
  291. {
  292. return new ErrorHandlerRegistry($this->idGenerator, $this->errorHelper, $response);
  293. }
  294. }