_mockUser = $u; } protected function getAuthUser(): ?array { return $this->_mockUser; } }; $request = \Config\Services::request(); $response = \Config\Services::response(); $logger = \Config\Services::logger(); $controller->initController($request, $response, $logger); return $controller; } /** * Fluent stub: always returns $returnValue on ->first(); ignores other calls. */ protected function makeFluentStub(mixed $returnValue): object { return new class($returnValue) { private mixed $rv; public function __construct(mixed $rv) { $this->rv = $rv; } public function __call(string $n, array $a): mixed { if ($n === 'first') return $this->rv; return $this; } }; } protected function inject(NonEbClaimApiController $ctrl, string $property, object $stub): void { $ref = new \ReflectionClass($ctrl); $prop = $ref->getProperty($property); $prop->setAccessible(true); $prop->setValue($ctrl, $stub); } protected function body(\CodeIgniter\HTTP\ResponseInterface $resp): array { return json_decode($resp->getBody(), true); } // ─── Tests ────────────────────────────────────────────────────────────── public function testReturns401WhenNoAuth(): void { $ctrl = $this->makeController(null); $resp = $ctrl->uploadRequiredDoc(1); $this->assertSame(401, $resp->getStatusCode()); $body = $this->body($resp); print_r($body); $this->assertFalse($body['status']); $this->assertSame(401, $body['code']); } public function testReturns404WhenClaimNotFound(): void { $ctrl = $this->makeController(['id' => 1, 'name' => 'U', 'email' => 'u@t.com', 'mobile' => '9']); $this->inject($ctrl, 'nonEbTicketModel', $this->makeFluentStub(null)); $resp = $ctrl->uploadRequiredDoc(999); $this->assertSame(404, $resp->getStatusCode()); $body = $this->body($resp); print_r($body); $this->assertFalse($body['status']); $this->assertSame('Claim not found', $body['message']); } public function testReturns422WhenNoChecklistConfigured(): void { $ctrl = $this->makeController(['id' => 1, 'name' => 'U', 'email' => 'u@t.com', 'mobile' => '9']); $this->inject($ctrl, 'nonEbTicketModel', $this->makeFluentStub([ 'id' => 10, 'client_id' => 5, 'required_docs' => null, // no checklist ])); $resp = $ctrl->uploadRequiredDoc(10); $this->assertSame(422, $resp->getStatusCode()); $body = $this->body($resp); print_r($body); $this->assertFalse($body['status']); $this->assertStringContainsString('checklist', strtolower($body['message'])); } public function testReturns422WhenChecklistHasEmptyDocs(): void { $ctrl = $this->makeController(['id' => 1, 'name' => 'U', 'email' => 'u@t.com', 'mobile' => '9']); $this->inject($ctrl, 'nonEbTicketModel', $this->makeFluentStub([ 'id' => 10, 'client_id' => 5, 'required_docs' => json_encode(['is_action_freeze' => false, 'docs' => []]), ])); $resp = $ctrl->uploadRequiredDoc(10); $this->assertSame(422, $resp->getStatusCode()); $body = $this->body($resp); print_r($body); $this->assertFalse($body['status']); } public function testReturns423WhenChecklistIsFrozen(): void { $ctrl = $this->makeController(['id' => 1, 'name' => 'U', 'email' => 'u@t.com', 'mobile' => '9']); $this->inject($ctrl, 'nonEbTicketModel', $this->makeFluentStub([ 'id' => 10, 'client_id' => 5, 'required_docs' => json_encode([ 'is_action_freeze' => true, 'docs' => [ ['document_name' => 'Invoice Copy', 'document_received' => false], ], ]), ])); $resp = $ctrl->uploadRequiredDoc(10); $this->assertSame(423, $resp->getStatusCode()); $body = $this->body($resp); print_r($body); $this->assertFalse($body['status']); $this->assertStringContainsString('locked', strtolower($body['message'])); } public function testReturns400WhenDocumentNameMissing(): void { $_POST = []; // document_name not set $ctrl = $this->makeController(['id' => 1, 'name' => 'U', 'email' => 'u@t.com', 'mobile' => '9']); $this->inject($ctrl, 'nonEbTicketModel', $this->makeFluentStub([ 'id' => 10, 'client_id' => 5, 'required_docs' => json_encode([ 'is_action_freeze' => false, 'docs' => [ ['document_name' => 'Invoice Copy', 'document_received' => false], ], ]), ])); $resp = $ctrl->uploadRequiredDoc(10); $this->assertSame(400, $resp->getStatusCode()); $body = $this->body($resp); print_r($body); $this->assertFalse($body['status']); $this->assertArrayHasKey('document_name', $body['errors']); } public function testReturns400WhenNoFileUploaded(): void { $_POST = ['document_name' => 'Invoice Copy']; // No file in $_FILES — getFile() will return null/invalid $ctrl = $this->makeController(['id' => 1, 'name' => 'U', 'email' => 'u@t.com', 'mobile' => '9']); $this->inject($ctrl, 'nonEbTicketModel', $this->makeFluentStub([ 'id' => 10, 'client_id' => 5, 'required_docs' => json_encode([ 'is_action_freeze' => false, 'docs' => [ ['document_name' => 'Invoice Copy', 'document_received' => false], ], ]), ])); $resp = $ctrl->uploadRequiredDoc(10); $this->assertSame(400, $resp->getStatusCode()); $body = $this->body($resp); print_r($body); $this->assertFalse($body['status']); $this->assertArrayHasKey('file', $body['errors']); } public function testReturns404WhenDocumentNameNotInChecklist(): void { $_POST = ['document_name' => 'Wrong Document']; // Still no real file — but the doc-name check fires first // We need to make the file check pass; we do this via a subclass // that overrides the file validation. $ctrl = new class(['id' => 1, 'name' => 'U', 'email' => 'u@t.com', 'mobile' => '9']) extends NonEbClaimApiController { private ?array $_mockUser; public function __construct(?array $u) { $this->_mockUser = $u; } protected function getAuthUser(): ?array { return $this->_mockUser; } /** * Override to return a fake valid file stub so the file check passes. */ public function uploadRequiredDoc(int $claim_id) { $authUser = $this->getAuthUser(); if (!$authUser) { return $this->respond(['status' => false, 'code' => 401, 'message' => 'Unauthorized'], 401); } $claim = $this->nonEbTicketModel ->select('id, client_id, required_docs') ->where('id', $claim_id) ->where('is_active', 1) ->first(); if (!$claim) { return $this->respond(['status' => false, 'code' => 404, 'message' => 'Claim not found'], 404); } $required_docs = json_decode($claim['required_docs'] ?? '{}', true); if (empty($required_docs) || empty($required_docs['docs'])) { return $this->respond(['status' => false, 'code' => 422, 'message' => 'No required documents checklist configured for this claim'], 422); } if (!empty($required_docs['is_action_freeze'])) { return $this->respond(['status' => false, 'code' => 423, 'message' => 'Document checklist is locked for this claim'], 423); } $document_name = trim($_POST['document_name'] ?? ''); if (empty($document_name)) { return $this->respond(['status' => false, 'code' => 400, 'message' => 'Input validation failed', 'errors' => ['document_name' => 'document_name is required']], 400); } // Simulate valid file (bypass getFile()) $ext = 'pdf'; $allowed = ['pdf', 'jpg', 'jpeg', 'png', 'doc', 'docx', 'xls', 'xlsx']; if (!in_array($ext, $allowed)) { return $this->respond(['status' => false, 'code' => 415, 'message' => 'Unsupported file type: ' . $ext], 415); } // Doc name lookup $matched_index = null; foreach ($required_docs['docs'] as $i => $doc) { if (($doc['document_name'] ?? '') === $document_name) { $matched_index = $i; break; } } if ($matched_index === null) { return $this->respond([ 'status' => false, 'code' => 404, 'message' => "Document '{$document_name}' not found in required documents list", ], 404); } return $this->respond(['status' => true, 'code' => 200, 'message' => 'Document uploaded successfully'], 200); } }; $request = \Config\Services::request(); $response = \Config\Services::response(); $logger = \Config\Services::logger(); $ctrl->initController($request, $response, $logger); $ref = new \ReflectionClass($ctrl); $prop = $ref->getProperty('nonEbTicketModel'); $prop->setAccessible(true); $prop->setValue($ctrl, $this->makeFluentStub([ 'id' => 10, 'client_id' => 5, 'required_docs' => json_encode([ 'is_action_freeze' => false, 'docs' => [ ['document_name' => 'Invoice Copy', 'document_received' => false], ], ]), ])); $resp = $ctrl->uploadRequiredDoc(10); $this->assertSame(404, $resp->getStatusCode()); $body = $this->body($resp); print_r($body); $this->assertFalse($body['status']); $this->assertStringContainsString('Wrong Document', $body['message']); $this->assertStringContainsString('not found', strtolower($body['message'])); } }