createMock(\medoo::class); $mockSettings = $this->createMock(SettingsRepository::class); $mockSettings->method('getSingleValue') ->with('api_key') ->willReturn($storedApiKey); return new ApiRouter($mockDb, $mockSettings); } public function testHandleReturns401WhenNoApiKey(): void { unset($_SERVER['HTTP_X_API_KEY']); $_GET['endpoint'] = 'orders'; $_GET['action'] = 'list'; $router = $this->createRouter(); ob_start(); $router->handle(); $output = ob_get_clean(); $this->assertSame(401, http_response_code()); $json = json_decode($output, true); $this->assertSame('error', $json['status']); $this->assertSame('UNAUTHORIZED', $json['code']); } public function testHandleReturns401WhenWrongApiKey(): void { $_SERVER['HTTP_X_API_KEY'] = 'wrong-key'; $_GET['endpoint'] = 'orders'; $_GET['action'] = 'list'; $router = $this->createRouter(); ob_start(); $router->handle(); $output = ob_get_clean(); $this->assertSame(401, http_response_code()); $json = json_decode($output, true); $this->assertSame('UNAUTHORIZED', $json['code']); } public function testHandleReturns401WhenStoredKeyEmpty(): void { $_SERVER['HTTP_X_API_KEY'] = 'any-key'; $_GET['endpoint'] = 'orders'; $_GET['action'] = 'list'; $router = $this->createRouter(''); ob_start(); $router->handle(); $output = ob_get_clean(); $this->assertSame(401, http_response_code()); } public function testHandleReturns400WhenMissingEndpoint(): void { $_SERVER['HTTP_X_API_KEY'] = 'test-api-key-123'; unset($_GET['endpoint']); $_GET['action'] = 'list'; $_GET['endpoint'] = ''; $router = $this->createRouter(); ob_start(); $router->handle(); $output = ob_get_clean(); $this->assertSame(400, http_response_code()); $json = json_decode($output, true); $this->assertSame('BAD_REQUEST', $json['code']); } public function testHandleReturns400WhenMissingAction(): void { $_SERVER['HTTP_X_API_KEY'] = 'test-api-key-123'; $_GET['endpoint'] = 'orders'; $_GET['action'] = ''; $router = $this->createRouter(); ob_start(); $router->handle(); $output = ob_get_clean(); $this->assertSame(400, http_response_code()); } public function testHandleReturns404ForUnknownEndpoint(): void { $_SERVER['HTTP_X_API_KEY'] = 'test-api-key-123'; $_GET['endpoint'] = 'unknown'; $_GET['action'] = 'list'; $router = $this->createRouter(); ob_start(); $router->handle(); $output = ob_get_clean(); $this->assertSame(404, http_response_code()); $json = json_decode($output, true); $this->assertSame('NOT_FOUND', $json['code']); } public function testSendSuccessOutputsCorrectJson(): void { ob_start(); ApiRouter::sendSuccess(['foo' => 'bar']); $output = ob_get_clean(); $json = json_decode($output, true); $this->assertSame('ok', $json['status']); $this->assertSame('bar', $json['data']['foo']); } public function testSendErrorOutputsCorrectJson(): void { ob_start(); ApiRouter::sendError('BAD_REQUEST', 'Test error', 400); $output = ob_get_clean(); $this->assertSame(400, http_response_code()); $json = json_decode($output, true); $this->assertSame('error', $json['status']); $this->assertSame('BAD_REQUEST', $json['code']); $this->assertSame('Test error', $json['message']); } public function testRequireMethodReturnsTrueForMatchingMethod(): void { $_SERVER['REQUEST_METHOD'] = 'GET'; ob_start(); $result = ApiRouter::requireMethod('GET'); ob_get_clean(); $this->assertTrue($result); } public function testRequireMethodReturnsFalseAndSendsErrorForMismatch(): void { $_SERVER['REQUEST_METHOD'] = 'POST'; ob_start(); $result = ApiRouter::requireMethod('GET'); $output = ob_get_clean(); $this->assertFalse($result); $this->assertSame(405, http_response_code()); $json = json_decode($output, true); $this->assertSame('METHOD_NOT_ALLOWED', $json['code']); } protected function tearDown(): void { unset($_SERVER['HTTP_X_API_KEY']); unset($_SERVER['REQUEST_METHOD']); $_GET = []; http_response_code(200); } }