230 lines
6.2 KiB
PHP
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']);
|
|
}
|
|
}
|