Files
alrahma_sunday_school/tests/app/Controllers/Api/AttendanceTrackingControllerTest.php
2026-02-10 22:11:06 -05:00

230 lines
6.2 KiB
PHP

<?php
namespace Tests\App\Controllers\Api;
use App\Controllers\Api\AttendanceTrackingController;
use CodeIgniter\HTTP\URI;
use CodeIgniter\HTTP\UserAgent;
use CodeIgniter\Test\CIUnitTestCase;
use CodeIgniter\Test\Mock\MockIncomingRequest;
use Config\App;
class FakeTrackingRequest extends MockIncomingRequest
{
public function __construct(private readonly ?array $json = null, private readonly array $gets = [])
{
parent::__construct(config(App::class), new URI('https://test.alrahmaisgl.org'), 'php://input', new UserAgent());
}
public function getJSON(bool $assoc = false, int $depth = 512, int $options = 0): ?array
{
return $this->json;
}
public function getGet($key = null, $filter = null, $default = null)
{
if ($key === null) {
return $this->gets;
}
return $this->gets[$key] ?? $default;
}
}
class StubTrackingModel
{
public array $findAllResult = [];
public array $findResult = [];
public array $updated = [];
public array $inserted = [];
public array $firstQueue = [];
public function where($column, $value = null)
{
return $this;
}
public function select($columns)
{
return $this;
}
public function groupBy($column)
{
return $this;
}
public function having($column, $value)
{
return $this;
}
public function findAll(): array
{
return $this->findAllResult;
}
public function orderBy(...$args)
{
return $this;
}
public function first()
{
return array_shift($this->firstQueue) ?? null;
}
public function queueFirst(array $row): void
{
$this->firstQueue[] = $row;
}
public function insert(array $data)
{
$this->inserted[] = $data;
return 1;
}
public function getInsertID()
{
return 1;
}
public function update(int $id, array $data)
{
$this->updated[$id] = $data;
}
public function find(int $id)
{
return $this->findResult[$id] ?? null;
}
}
class TestableAttendanceTrackingController extends AttendanceTrackingController
{
public bool $validationResult = true;
public array $validationErrors = [];
public $validator;
public function __construct()
{
// bypass real model instantiation
}
public function setTrackingModel(StubTrackingModel $model): void
{
$this->trackingModel = $model;
}
public function setValidationResult(bool $result, array $errors = []): void
{
$this->validationResult = $result;
$this->validationErrors = $errors;
}
protected function validate($rules, array $messages = []): bool
{
$this->validator = new class($this->validationErrors) {
private array $errors;
public function __construct(array $errors)
{
$this->errors = $errors;
}
public function getErrors()
{
return $this->errors;
}
};
return $this->validationResult;
}
protected function respond($data = null, ?int $status = null, string $message = '')
{
return ['data' => $data, 'code' => $status, 'message' => $message];
}
}
class AttendanceTrackingControllerTest extends CIUnitTestCase
{
private TestableAttendanceTrackingController $controller;
private StubTrackingModel $model;
protected function setUp(): void
{
parent::setUp();
$this->controller = new TestableAttendanceTrackingController();
$this->model = new StubTrackingModel();
$this->controller->setTrackingModel($this->model);
}
public function testRecordValidationFails()
{
$this->controller->setValidationResult(false, ['student_id' => 'required']);
$this->controller->setRequest(new FakeTrackingRequest(['student_id' => null]));
$response = $this->controller->record();
$this->assertSame(422, $response['code']);
$this->assertArrayHasKey('student_id', $response['errors']);
}
public function testRecordUpdatesExisting()
{
$this->model->queueFirst(['id' => 5]);
$request = new FakeTrackingRequest(['student_id' => 1, 'date' => '2024-09-01', 'status' => 'present']);
$this->controller->setRequest($request);
$response = $this->controller->record();
$this->assertSame('Attendance tracking record updated successfully', $response['message']);
$this->assertSame(['student_id' => 1, 'date' => '2024-09-01', 'status' => 'present'], $this->model->updated[5]);
}
public function testRecordCreatesNew()
{
$request = new FakeTrackingRequest(['student_id' => 2, 'date' => '2024-09-02', 'status' => 'late']);
$this->controller->setRequest($request);
$this->controller->setValidationResult(true);
$response = $this->controller->record();
$this->assertSame('Attendance tracking record created successfully', $response['message']);
$this->assertSame(1, $response['data']['id']);
}
public function testViolationsDefaultsThreshold()
{
$this->controller->setRequest(new FakeTrackingRequest(null, []));
$this->model->findAllResult = [['student_id' => 3, 'total_violations' => 5]];
$response = $this->controller->violations();
$this->assertSame('Attendance violations retrieved successfully', $response['message']);
$this->assertSame(1, count($response['data']));
}
public function testViolationsCustomThreshold()
{
$request = new FakeTrackingRequest(null, ['threshold' => '2']);
$this->controller->setRequest($request);
$this->model->findAllResult = [['student_id' => 4, 'total_violations' => 3]];
$response = $this->controller->violations();
$this->assertSame(1, count($response['data']));
}
public function testStudentRecordsOrder()
{
$this->model->findAllResult = [['id' => 7]];
$response = $this->controller->student(7);
$this->assertSame('Tracking records retrieved successfully for student', $response['message']);
$this->assertSame(7, $response['data'][0]['id']);
}
}