diff --git a/.gitignore b/.gitignore index 9323bcb..56adb1f 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,7 @@ composer.lock vendor test/coverage tests/unit/.phpunit.result.cache +tests/unit/.phpunit.cache/* # Compiled source # ################### diff --git a/composer.json b/composer.json index 5d2b909..e6f426e 100644 --- a/composer.json +++ b/composer.json @@ -36,28 +36,28 @@ "g4/version": "0.0.*" }, "require-dev": { - "phpunit/phpunit" : "9.*", - "squizlabs/php_codesniffer" : "3.*", - "g4/code-coverage" : "2.*" + "phpunit/phpunit" : "^11.5", + "squizlabs/php_codesniffer" : "*", + "g4/code-coverage" : "*" }, "scripts": { "unit-test": [ - "vendor/bin/phpunit -c tests/unit/phpunit.xml --colors=always --coverage-html tests/unit/coverage" + "php8.3 vendor/bin/phpunit -c tests/unit/phpunit.xml --colors=always" ], "test-coverage": [ - "./vendor/bin/phpunit --colors=always -c tests/unit/phpunit.xml --coverage-text" + "XDEBUG_MODE=coverage php8.3 ./vendor/bin/phpunit --colors=always -c tests/unit/phpunit.xml --coverage-text --coverage-html tests/unit/coverage" ], "test-report": [ - "./vendor/bin/phpunit --colors=always -c tests/unit/phpunit.xml --coverage-clover=tests/unit/coverage/code-coverage.xml" + "XDEBUG_MODE=coverage php8.3 ./vendor/bin/phpunit --colors=always -c tests/unit/phpunit.xml --coverage-clover=tests/unit/coverage/code-coverage.xml" ], "code-coverage": [ - "./vendor/bin/code-coverage -p 90 -f tests/unit/coverage/code-coverage.xml" + "php8.3 ./vendor/bin/code-coverage -p 50 -f tests/unit/coverage/code-coverage.xml" ], "psr2": [ - "./vendor/bin/phpcs --colors --standard=PSR2 src/" + "php8.3 ./vendor/bin/phpcs --colors --standard=PSR2 src/" ], "psr2-fix": [ - "./vendor/bin/phpcbf --colors --standard=PSR2 src/" + "php8.3 ./vendor/bin/phpcbf --colors --standard=PSR2 src/" ] } } diff --git a/src/Profiler.php b/src/Profiler.php index 65edc35..c423bcd 100644 --- a/src/Profiler.php +++ b/src/Profiler.php @@ -9,6 +9,7 @@ class Profiler const LOG_OFF = 0; const LOG_ERRORS_ONLY = 1; const LOG_ALWAYS = 2; + const LOG_ABOVE_THRESHOLD = 3; /** * @var array @@ -80,11 +81,27 @@ public function getProfilerOutput($httpCode, $dbProfiler = 0, $responseElapsedTi : []; } + public function getTaskerProfilerOutput($taskStatus, $executionTime = 0) + { + if (!$this->hasProfilers()) { + return null; + } + if (!$this->shouldLogTaskerProfiler($taskStatus, $executionTime)) { + return null; + } + return $this->getFormatted(2, $executionTime); + } + public function getProfilerSummary() { return (new ProfilerSummary($this->profilers))->getSummary(); } + /** + * @param $httpCode int HTTP Response Code + * @param $responseElapsedTime int Response time in seconds + * @return bool + */ private function shouldLogProfiler($httpCode, $responseElapsedTime) { if ($this->logLevel === self::LOG_OFF) { @@ -93,14 +110,30 @@ private function shouldLogProfiler($httpCode, $responseElapsedTime) if ($this->logLevel === self::LOG_ALWAYS) { return true; } - - if($this->isRequestTresholdExceded($responseElapsedTime)){ + if ($this->isRequestTresholdExceded($responseElapsedTime)) { return true; } return self::LOG_ERRORS_ONLY && substr($httpCode, 0, 1) != 2; } + private function shouldLogTaskerProfiler($taskStatus, $execTime) + { + if ($this->logLevel === self::LOG_OFF) { + return false; + } + if ($this->logLevel === self::LOG_ALWAYS) { + return true; + } + if ($this->logLevel === self::LOG_ABOVE_THRESHOLD + && $this->isRequestTresholdExceded($execTime) + ) { + return true; + } + + return self::LOG_ERRORS_ONLY && (int) $taskStatus != 2; + } + public function isRequestTresholdExceded($responseElapsedTime) { return $this->threshold && $responseElapsedTime > $this->threshold; diff --git a/tests/unit/phpunit.xml b/tests/unit/phpunit.xml index 1408100..8a8ef35 100644 --- a/tests/unit/phpunit.xml +++ b/tests/unit/phpunit.xml @@ -1,11 +1,17 @@ - - + + + + ./src + + + - ../../src/ + ../../src - - - ./src - + diff --git a/tests/unit/src/Exception/InvalidModuleExceptionTest.php b/tests/unit/src/Exception/InvalidModuleExceptionTest.php new file mode 100644 index 0000000..520120d --- /dev/null +++ b/tests/unit/src/Exception/InvalidModuleExceptionTest.php @@ -0,0 +1,25 @@ +assertStringContainsString($moduleName, $exception->getMessage()); + $this->assertStringContainsString('Module is not valid', $exception->getMessage()); + } + + public function testExceptionCode(): void + { + $exception = new InvalidModuleException('test'); + + $this->assertEquals(ErrorCodes::INVALID_MODULE, $exception->getCode()); + } +} diff --git a/tests/unit/src/Exception/InvalidServiceExceptionTest.php b/tests/unit/src/Exception/InvalidServiceExceptionTest.php new file mode 100644 index 0000000..614cc68 --- /dev/null +++ b/tests/unit/src/Exception/InvalidServiceExceptionTest.php @@ -0,0 +1,25 @@ +assertStringContainsString($serviceName, $exception->getMessage()); + $this->assertStringContainsString('Service is not valid', $exception->getMessage()); + } + + public function testExceptionCode(): void + { + $exception = new InvalidServiceException('test'); + + $this->assertEquals(ErrorCodes::INVALID_SERVICE, $exception->getCode()); + } +} diff --git a/tests/unit/src/LoggerTest.php b/tests/unit/src/LoggerTest.php new file mode 100644 index 0000000..933e448 --- /dev/null +++ b/tests/unit/src/LoggerTest.php @@ -0,0 +1,94 @@ +logger = new Logger(); + } + + public function testConstructorInitializesLogger(): void + { + $this->assertInstanceOf(Logger::class, $this->logger); + } + + public function testSetLogger(): void + { + $logLoggerMock = $this->createMock(LogLogger::class); + $this->logger->setLogger($logLoggerMock); + + // Test that logger is set by calling logRequest which should register shutdown function + $applicationMock = $this->createMock(Application::class); + $applicationMock->method('getRequest')->willReturn( + $this->createMock(\G4\CleanCore\Request\Request::class) + ); + + $this->logger->logRequest($applicationMock); + + // If no exception is thrown, the logger was set correctly + $this->assertTrue(true); + } + + public function testLogRequestWithoutLoggerDoesNothing(): void + { + $applicationMock = $this->createMock(Application::class); + + // Should not throw any exception + $this->logger->logRequest($applicationMock); + + $this->assertTrue(true); + } + + public function testLogResponseWithoutLoggerDoesNothing(): void + { + $applicationMock = $this->createMock(Application::class); + $profilerMock = $this->createMock(Profiler::class); + + // Should not throw any exception + $this->logger->logResponse($applicationMock, $profilerMock); + + $this->assertTrue(true); + } + + public function testLogRequestWithLoggerRegistersShutdownFunction(): void + { + $logLoggerMock = $this->createMock(LogLogger::class); + $this->logger->setLogger($logLoggerMock); + + $applicationMock = $this->createMock(Application::class); + $requestMock = $this->createMock(\G4\CleanCore\Request\Request::class); + $applicationMock->method('getRequest')->willReturn($requestMock); + + // This should register a shutdown function + $this->logger->logRequest($applicationMock); + + // If no exception is thrown, the shutdown function was registered + $this->assertTrue(true); + } + + public function testLogResponseWithLoggerRegistersShutdownFunction(): void + { + $logLoggerMock = $this->createMock(LogLogger::class); + $this->logger->setLogger($logLoggerMock); + + $applicationMock = $this->createMock(Application::class); + $responseMock = $this->createMock(\G4\CleanCore\Response\Response::class); + $applicationMock->method('getResponse')->willReturn($responseMock); + + $profilerMock = $this->createMock(Profiler::class); + + // This should register a shutdown function + $this->logger->logResponse($applicationMock, $profilerMock); + + // If no exception is thrown, the shutdown function was registered + $this->assertTrue(true); + } +} diff --git a/tests/unit/src/Presenter/ContentTypeTest.php b/tests/unit/src/Presenter/ContentTypeTest.php index a032a56..90074d3 100644 --- a/tests/unit/src/Presenter/ContentTypeTest.php +++ b/tests/unit/src/Presenter/ContentTypeTest.php @@ -114,7 +114,7 @@ public function testInvalidFormat($format) * * @return array */ - public function validDataProvider() + public static function validDataProvider() { return [ ['gif', 'image/gif'], @@ -128,7 +128,7 @@ public function validDataProvider() * * @return array */ - public function invalidDataProvider() + public static function invalidDataProvider() { return [ ['ppam'], diff --git a/tests/unit/src/Presenter/DataTransferTest.php b/tests/unit/src/Presenter/DataTransferTest.php new file mode 100644 index 0000000..a33bff5 --- /dev/null +++ b/tests/unit/src/Presenter/DataTransferTest.php @@ -0,0 +1,83 @@ +httpRequest = $this->createMock(HttpRequest::class); + $this->profiler = $this->createMock(Profiler::class); + $this->request = $this->createMock(Request::class); + $this->response = $this->createMock(Response::class); + + $this->dataTransfer = new DataTransfer( + $this->httpRequest, + $this->profiler, + $this->request, + $this->response, + '1.0.0' + ); + } + + public function testGetHttpRequest(): void + { + $result = $this->dataTransfer->getHttpRequest(); + + $this->assertSame($this->httpRequest, $result); + } + + public function testGetProfiler(): void + { + $result = $this->dataTransfer->getProfiler(); + + $this->assertSame($this->profiler, $result); + } + + public function testGetRequest(): void + { + $result = $this->dataTransfer->getRequest(); + + $this->assertSame($this->request, $result); + } + + public function testGetResponse(): void + { + $result = $this->dataTransfer->getResponse(); + + $this->assertSame($this->response, $result); + } + + public function testGetVersion(): void + { + $result = $this->dataTransfer->getVersion(); + + $this->assertEquals('1.0.0', $result); + } + + public function testGetVersionWithNullVersion(): void + { + $dataTransfer = new DataTransfer( + $this->httpRequest, + $this->profiler, + $this->request, + $this->response + ); + + $result = $dataTransfer->getVersion(); + + $this->assertNull($result); + } +} diff --git a/tests/unit/src/Presenter/Formatter/BasicTest.php b/tests/unit/src/Presenter/Formatter/BasicTest.php new file mode 100644 index 0000000..dfaf231 --- /dev/null +++ b/tests/unit/src/Presenter/Formatter/BasicTest.php @@ -0,0 +1,88 @@ +formatter = new Basic(); + + $httpRequest = $this->createMock(HttpRequest::class); + $httpRequest->method('has')->willReturn(false); + + $profiler = $this->createMock(Profiler::class); + $profiler->method('getProfilerOutput')->willReturn([]); + + $request = $this->createMock(Request::class); + + $response = $this->createMock(Response::class); + $response->method('getHttpResponseCode')->willReturn(200); + $response->method('getHttpMessage')->willReturn('OK'); + $response->method('getResponseObject')->willReturn(['data' => 'test']); + + $this->dataTransfer = new DataTransfer( + $httpRequest, + $profiler, + $request, + $response, + '1.0.0' + ); + } + + public function testFormat(): void + { + $this->formatter->setDataTransfer($this->dataTransfer); + $result = $this->formatter->format(); + + $this->assertIsArray($result); + $this->assertArrayHasKey('code', $result); + $this->assertArrayHasKey('message', $result); + $this->assertArrayHasKey('response', $result); + $this->assertEquals(200, $result['code']); + $this->assertEquals('OK', $result['message']); + $this->assertEquals(['data' => 'test'], $result['response']); + } + + public function testSetDataTransfer(): void + { + $result = $this->formatter->setDataTransfer($this->dataTransfer); + + $this->assertInstanceOf(Basic::class, $result); + } + + public function testGetBasicData(): void + { + $this->formatter->setDataTransfer($this->dataTransfer); + $result = $this->formatter->getBasicData(); + + $this->assertIsArray($result); + $this->assertArrayHasKey('code', $result); + $this->assertArrayHasKey('message', $result); + $this->assertArrayHasKey('app_version', $result); + $this->assertArrayHasKey('response', $result); + } + + public function testGetProfilerData(): void + { + $this->formatter->setDataTransfer($this->dataTransfer); + $result = $this->formatter->getProfilerData(); + + $this->assertIsArray($result); + $this->assertEmpty($result); + } +} diff --git a/tests/unit/src/Presenter/Formatter/VerboseTest.php b/tests/unit/src/Presenter/Formatter/VerboseTest.php new file mode 100644 index 0000000..f28d36f --- /dev/null +++ b/tests/unit/src/Presenter/Formatter/VerboseTest.php @@ -0,0 +1,84 @@ +formatter = new Verbose(); + + $httpRequest = $this->createMock(HttpRequest::class); + $httpRequest->method('has')->willReturn(false); + + $profiler = $this->createMock(Profiler::class); + $profiler->method('getProfilerOutput')->willReturn([]); + + $request = $this->createMock(Request::class); + $request->method('getModule')->willReturn('test'); + $request->method('getResourceName')->willReturn('resource'); + $request->method('getMethod')->willReturn('get'); + $request->method('getParamsAnonymized')->willReturn(['param' => 'value']); + + $response = $this->createMock(Response::class); + $response->method('getHttpResponseCode')->willReturn(200); + $response->method('getHttpMessage')->willReturn('OK'); + $response->method('getResponseObject')->willReturn(['data' => 'test']); + $response->method('getApplicationResponseCode')->willReturn(1000); + $response->method('getResponseMessage')->willReturn('Success'); + + $this->dataTransfer = new DataTransfer( + $httpRequest, + $profiler, + $request, + $response, + '1.0.0' + ); + } + + public function testFormat(): void + { + $this->formatter->setDataTransfer($this->dataTransfer); + $result = $this->formatter->format(); + + $this->assertIsArray($result); + $this->assertArrayHasKey('code', $result); + $this->assertArrayHasKey('message', $result); + $this->assertArrayHasKey('response', $result); + $this->assertArrayHasKey('app_code', $result); + $this->assertArrayHasKey('app_message', $result); + $this->assertArrayHasKey('params', $result); + $this->assertArrayHasKey('method', $result); + $this->assertArrayHasKey('resource_name', $result); + $this->assertArrayHasKey('body_id', $result); + + $this->assertEquals(200, $result['code']); + $this->assertEquals('OK', $result['message']); + $this->assertEquals(1000, $result['app_code']); + $this->assertEquals('Success', $result['app_message']); + $this->assertEquals('get', $result['method']); + $this->assertEquals('resource', $result['resource_name']); + $this->assertEquals('test_resource_get', $result['body_id']); + } + + public function testSetDataTransfer(): void + { + $result = $this->formatter->setDataTransfer($this->dataTransfer); + + $this->assertInstanceOf(Verbose::class, $result); + } +} diff --git a/tests/unit/src/Presenter/View/JsonTest.php b/tests/unit/src/Presenter/View/JsonTest.php new file mode 100644 index 0000000..a7bb73b --- /dev/null +++ b/tests/unit/src/Presenter/View/JsonTest.php @@ -0,0 +1,99 @@ +createMock(HttpRequest::class); + $httpRequest->method('has')->willReturn(false); + + $profiler = $this->createMock(Profiler::class); + $request = $this->createMock(Request::class); + $response = $this->createMock(Response::class); + + $this->dataTransfer = new DataTransfer( + $httpRequest, + $profiler, + $request, + $response + ); + + $this->contentType = $this->createMock(ContentType::class); + + $data = ['test' => 'data', 'number' => 123]; + $this->jsonView = new Json($data, $this->dataTransfer); + } + + public function testRenderBody(): void + { + $result = $this->jsonView->renderBody(); + + $this->assertIsString($result); + $this->assertJson($result); + + $decoded = json_decode($result, true); + $this->assertEquals('data', $decoded['test']); + $this->assertEquals(123, $decoded['number']); + } + + public function testRenderBodyWithPrettyPrint(): void + { + $httpRequest = $this->createMock(HttpRequest::class); + $httpRequest->expects($this->once()) + ->method('has') + ->with('__pretty') + ->willReturn(true); + $httpRequest->expects($this->once()) + ->method('get') + ->with('__pretty') + ->willReturn(1); + + $profiler = $this->createMock(Profiler::class); + $request = $this->createMock(Request::class); + $response = $this->createMock(Response::class); + + $dataTransfer = new DataTransfer( + $httpRequest, + $profiler, + $request, + $response + ); + + $data = ['test' => 'data']; + $jsonView = new Json($data, $dataTransfer); + + $result = $jsonView->renderBody(); + + $this->assertIsString($result); + $this->assertJson($result); + // Verify it's valid JSON and contains the data + $decoded = json_decode($result, true); + $this->assertEquals('data', $decoded['test']); + } + + public function testRenderBodyWithUnicodeCharacters(): void + { + $data = ['text' => 'Ћирилица']; + $jsonView = new Json($data, $this->dataTransfer); + + $result = $jsonView->renderBody(); + + $this->assertIsString($result); + $this->assertJson($result); + $this->assertStringContainsString('Ћирилица', $result); + } +} diff --git a/tests/unit/src/ProfilerSummaryTest.php b/tests/unit/src/ProfilerSummaryTest.php new file mode 100644 index 0000000..3fba5a4 --- /dev/null +++ b/tests/unit/src/ProfilerSummaryTest.php @@ -0,0 +1,96 @@ +getSummary(); + + $this->assertIsArray($result); + $this->assertEmpty($result); + } + + public function testGetSummaryWithSingleProfiler(): void + { + $tickerMock = $this->createMock(TickerAbstract::class); + $tickerMock->method('getType')->willReturn('mysql'); + $tickerMock->method('getTotalNumQueries')->willReturn(10); + $tickerMock->method('getTotalElapsedTime')->willReturn(0.5); + + $profilerSummary = new ProfilerSummary([$tickerMock]); + $result = $profilerSummary->getSummary(); + + $this->assertIsArray($result); + $this->assertArrayHasKey('prof_mysql_calls', $result); + $this->assertArrayHasKey('prof_mysql_time_ms', $result); + $this->assertEquals(10, $result['prof_mysql_calls']); + $this->assertEquals(500, $result['prof_mysql_time_ms']); + } + + public function testGetSummaryWithMultipleProfilersOfSameType(): void + { + $tickerMock1 = $this->createMock(TickerAbstract::class); + $tickerMock1->method('getType')->willReturn('mysql'); + $tickerMock1->method('getTotalNumQueries')->willReturn(10); + $tickerMock1->method('getTotalElapsedTime')->willReturn(0.5); + + $tickerMock2 = $this->createMock(TickerAbstract::class); + $tickerMock2->method('getType')->willReturn('mysql'); + $tickerMock2->method('getTotalNumQueries')->willReturn(5); + $tickerMock2->method('getTotalElapsedTime')->willReturn(0.3); + + $profilerSummary = new ProfilerSummary([$tickerMock1, $tickerMock2]); + $result = $profilerSummary->getSummary(); + + $this->assertIsArray($result); + $this->assertArrayHasKey('prof_mysql_calls', $result); + $this->assertArrayHasKey('prof_mysql_time_ms', $result); + $this->assertEquals(15, $result['prof_mysql_calls']); + $this->assertEquals(800, $result['prof_mysql_time_ms']); + } + + public function testGetSummaryWithMultipleProfilersOfDifferentTypes(): void + { + $tickerMock1 = $this->createMock(TickerAbstract::class); + $tickerMock1->method('getType')->willReturn('mysql'); + $tickerMock1->method('getTotalNumQueries')->willReturn(10); + $tickerMock1->method('getTotalElapsedTime')->willReturn(0.5); + + $tickerMock2 = $this->createMock(TickerAbstract::class); + $tickerMock2->method('getType')->willReturn('redis'); + $tickerMock2->method('getTotalNumQueries')->willReturn(20); + $tickerMock2->method('getTotalElapsedTime')->willReturn(0.2); + + $profilerSummary = new ProfilerSummary([$tickerMock1, $tickerMock2]); + $result = $profilerSummary->getSummary(); + + $this->assertIsArray($result); + $this->assertArrayHasKey('prof_mysql_calls', $result); + $this->assertArrayHasKey('prof_mysql_time_ms', $result); + $this->assertArrayHasKey('prof_redis_calls', $result); + $this->assertArrayHasKey('prof_redis_time_ms', $result); + $this->assertEquals(10, $result['prof_mysql_calls']); + $this->assertEquals(500, $result['prof_mysql_time_ms']); + $this->assertEquals(20, $result['prof_redis_calls']); + $this->assertEquals(200, $result['prof_redis_time_ms']); + } + + public function testGetSummaryFormatsTimeInMilliseconds(): void + { + $tickerMock = $this->createMock(TickerAbstract::class); + $tickerMock->method('getType')->willReturn('mysql'); + $tickerMock->method('getTotalNumQueries')->willReturn(1); + $tickerMock->method('getTotalElapsedTime')->willReturn(1.234); + + $profilerSummary = new ProfilerSummary([$tickerMock]); + $result = $profilerSummary->getSummary(); + + $this->assertEquals(1234, $result['prof_mysql_time_ms']); + } +} diff --git a/tests/unit/src/ProfilerTest.php b/tests/unit/src/ProfilerTest.php new file mode 100644 index 0000000..01ecd5b --- /dev/null +++ b/tests/unit/src/ProfilerTest.php @@ -0,0 +1,216 @@ +profiler = new Profiler(); + } + + public function testConstructorSetsDefaultLogLevel(): void + { + $this->assertInstanceOf(Profiler::class, $this->profiler); + } + + public function testAddProfiler(): void + { + $tickerMock = $this->createMock(TickerAbstract::class); + $result = $this->profiler->addProfiler($tickerMock); + + $this->assertInstanceOf(Profiler::class, $result); + } + + public function testSetLogLevel(): void + { + $result = $this->profiler->setLogLevel(Profiler::LOG_OFF); + + $this->assertInstanceOf(Profiler::class, $result); + } + + public function testSetThreshold(): void + { + $result = $this->profiler->setThreshold(1000); + + $this->assertInstanceOf(Profiler::class, $result); + } + + public function testGetProfilerOutputReturnsEmptyArrayWhenNoProfilers(): void + { + $result = $this->profiler->getProfilerOutput(200); + + $this->assertIsArray($result); + $this->assertEmpty($result); + } + + public function testGetProfilerOutputWithLogOff(): void + { + $tickerMock = $this->createMock(TickerAbstract::class); + $this->profiler->addProfiler($tickerMock); + $this->profiler->setLogLevel(Profiler::LOG_OFF); + + $result = $this->profiler->getProfilerOutput(200); + + $this->assertIsArray($result); + $this->assertEmpty($result); + } + + public function testGetProfilerOutputWithLogAlways(): void + { + $tickerMock = $this->createMock(TickerAbstract::class); + $tickerMock->method('getName')->willReturn('test_profiler'); + $tickerMock->method('getFormatted')->willReturn(['test' => 'data']); + $tickerMock->method('getQueries')->willReturn([]); + + $this->profiler->addProfiler($tickerMock); + $this->profiler->setLogLevel(Profiler::LOG_ALWAYS); + + $result = $this->profiler->getProfilerOutput(200, 0, 0); + + $this->assertIsArray($result); + $this->assertEquals(['unsuported request parameter'], $result); + } + + public function testGetProfilerOutputWithDbProfiler1(): void + { + $tickerMock = $this->createMock(TickerAbstract::class); + $tickerMock->method('getName')->willReturn('test_profiler'); + $tickerMock->method('getFormatted')->willReturn(['test' => 'data']); + $tickerMock->method('getQueries')->willReturn([]); + + $this->profiler->addProfiler($tickerMock); + $this->profiler->setLogLevel(Profiler::LOG_ALWAYS); + + $result = $this->profiler->getProfilerOutput(200, 1, 0); + + $this->assertIsArray($result); + $this->assertArrayHasKey('test_profiler', $result); + $this->assertEquals(['test' => 'data'], $result['test_profiler']); + } + + public function testGetProfilerOutputWithDbProfiler2(): void + { + $tickerMock = $this->createMock(TickerAbstract::class); + $tickerMock->method('getName')->willReturn('test_profiler'); + $tickerMock->method('getFormatted')->willReturn(['test' => 'data']); + $tickerMock->method('getQueries')->willReturn([1 => ['query' => 'SELECT *']]); + + $this->profiler->addProfiler($tickerMock); + $this->profiler->setLogLevel(Profiler::LOG_ALWAYS); + + $result = $this->profiler->getProfilerOutput(200, 2, 0); + + $this->assertIsArray($result); + $this->assertArrayHasKey(1, $result); + } + + public function testIsRequestThresholdExceeded(): void + { + $this->profiler->setThreshold(1000); + + $this->assertTrue($this->profiler->isRequestTresholdExceded(1500)); + $this->assertFalse($this->profiler->isRequestTresholdExceded(500)); + } + + public function testIsRequestThresholdExceededWithNoThreshold(): void + { + $this->assertFalse($this->profiler->isRequestTresholdExceded(1500)); + } + + public function testGetTaskerProfilerOutputReturnsNullWhenNoProfilers(): void + { + $result = $this->profiler->getTaskerProfilerOutput(2); + + $this->assertNull($result); + } + + public function testGetTaskerProfilerOutputWithLogOff(): void + { + $tickerMock = $this->createMock(TickerAbstract::class); + $this->profiler->addProfiler($tickerMock); + $this->profiler->setLogLevel(Profiler::LOG_OFF); + + $result = $this->profiler->getTaskerProfilerOutput(2); + + $this->assertNull($result); + } + + public function testGetTaskerProfilerOutputWithLogAlways(): void + { + $tickerMock = $this->createMock(TickerAbstract::class); + $tickerMock->method('getName')->willReturn('test_profiler'); + $tickerMock->method('getFormatted')->willReturn(['test' => 'data']); + $tickerMock->method('getQueries')->willReturn([1 => ['query' => 'SELECT *']]); + + $this->profiler->addProfiler($tickerMock); + $this->profiler->setLogLevel(Profiler::LOG_ALWAYS); + + $result = $this->profiler->getTaskerProfilerOutput(2, 0); + + $this->assertIsArray($result); + } + + public function testGetTaskerProfilerOutputWithLogAboveThreshold(): void + { + $tickerMock = $this->createMock(TickerAbstract::class); + $tickerMock->method('getName')->willReturn('test_profiler'); + $tickerMock->method('getFormatted')->willReturn(['test' => 'data']); + $tickerMock->method('getQueries')->willReturn([1 => ['query' => 'SELECT *']]); + + $this->profiler->addProfiler($tickerMock); + $this->profiler->setLogLevel(Profiler::LOG_ABOVE_THRESHOLD); + $this->profiler->setThreshold(1000); + + $result = $this->profiler->getTaskerProfilerOutput(2, 1500); + + $this->assertIsArray($result); + } + + public function testGetTaskerProfilerOutputWithErrorStatus(): void + { + $tickerMock = $this->createMock(TickerAbstract::class); + $tickerMock->method('getName')->willReturn('test_profiler'); + $tickerMock->method('getFormatted')->willReturn(['test' => 'data']); + $tickerMock->method('getQueries')->willReturn([1 => ['query' => 'SELECT *']]); + + $this->profiler->addProfiler($tickerMock); + $this->profiler->setLogLevel(Profiler::LOG_ERRORS_ONLY); + + $result = $this->profiler->getTaskerProfilerOutput(1, 0); + + $this->assertIsArray($result); + } + + public function testClearProfilers(): void + { + $tickerMock = $this->createMock(TickerAbstract::class); + $tickerMock->expects($this->once())->method('clear'); + + $this->profiler->addProfiler($tickerMock); + $this->profiler->clearProfilers(); + } + + public function testGetProfilerSummary(): void + { + $tickerMock = $this->createMock(TickerAbstract::class); + $tickerMock->method('getType')->willReturn('mysql'); + $tickerMock->method('getTotalNumQueries')->willReturn(10); + $tickerMock->method('getTotalElapsedTime')->willReturn(0.5); + + $this->profiler->addProfiler($tickerMock); + + $result = $this->profiler->getProfilerSummary(); + + $this->assertIsArray($result); + $this->assertArrayHasKey('prof_mysql_calls', $result); + $this->assertArrayHasKey('prof_mysql_time_ms', $result); + $this->assertEquals(10, $result['prof_mysql_calls']); + $this->assertEquals(500, $result['prof_mysql_time_ms']); + } +} diff --git a/tests/unit/src/ResponseFormatterTest.php b/tests/unit/src/ResponseFormatterTest.php new file mode 100644 index 0000000..71ba896 --- /dev/null +++ b/tests/unit/src/ResponseFormatterTest.php @@ -0,0 +1,57 @@ +responseFormatter = new ResponseFormatter(); + } + + public function testConstructor(): void + { + $this->assertInstanceOf(ResponseFormatter::class, $this->responseFormatter); + } + + public function testGetBasicReturnsDefaultBasicFormatter(): void + { + $result = $this->responseFormatter->getBasic(); + + $this->assertInstanceOf(Basic::class, $result); + } + + public function testGetVerboseReturnsDefaultVerboseFormatter(): void + { + $result = $this->responseFormatter->getVerbose(); + + $this->assertInstanceOf(Verbose::class, $result); + } + + public function testAddBasicSetsCustomFormatter(): void + { + $customFormatter = $this->createMock(FormatterInterface::class); + $this->responseFormatter->addBasic($customFormatter); + + $result = $this->responseFormatter->getBasic(); + + $this->assertSame($customFormatter, $result); + } + + public function testAddVerboseSetsCustomFormatter(): void + { + $customFormatter = $this->createMock(FormatterInterface::class); + $this->responseFormatter->addVerbose($customFormatter); + + $result = $this->responseFormatter->getVerbose(); + + $this->assertSame($customFormatter, $result); + } +} diff --git a/tests/unit/src/Route/RouteFormatterTest.php b/tests/unit/src/Route/RouteFormatterTest.php index b2ee795..8de8a34 100644 --- a/tests/unit/src/Route/RouteFormatterTest.php +++ b/tests/unit/src/Route/RouteFormatterTest.php @@ -7,14 +7,27 @@ class RouteFormatterTest extends TestCase { - public function testFormat() + public function testFormat(): void { - $route = new Route(new StringLiteral('module-name'), new StringLiteral('service-name')); - $expectedArray = [ - 'module' => 'module-name', - 'service' => 'service-name' - ]; + $route = new Route(new StringLiteral('test-module'), new StringLiteral('test-service')); + + $result = RouteFormatter::format($route); + + $this->assertIsArray($result); + $this->assertArrayHasKey('module', $result); + $this->assertArrayHasKey('service', $result); + $this->assertEquals('test-module', $result['module']); + $this->assertEquals('test-service', $result['service']); + } - $this->assertEquals($expectedArray, (new RouteFormatter())->format($route)); + public function testFormatWithDifferentValues(): void + { + $route = new Route(new StringLiteral('user'), new StringLiteral('profile')); + + $result = RouteFormatter::format($route); + + $this->assertIsArray($result); + $this->assertEquals('user', $result['module']); + $this->assertEquals('profile', $result['service']); } } diff --git a/tests/unit/src/Route/RouteTest.php b/tests/unit/src/Route/RouteTest.php index d5e7af7..ffb771a 100644 --- a/tests/unit/src/Route/RouteTest.php +++ b/tests/unit/src/Route/RouteTest.php @@ -39,7 +39,7 @@ public function testConstructWithValidArguments($value) $this->assertEquals($route->module(), $value); } - public function invalidModuleAndServiceStrings() + public static function invalidModuleAndServiceStrings() { return [ ['front/'], @@ -50,7 +50,7 @@ public function invalidModuleAndServiceStrings() ]; } - public function validModuleAndServiceStrings() + public static function validModuleAndServiceStrings() { return [ ['front'],