315 lines
10 KiB
PHP
315 lines
10 KiB
PHP
<?php
|
|
|
|
namespace {
|
|
if (!function_exists('view')) {
|
|
function view($name, array $data = [], $options = [])
|
|
{
|
|
return ['view' => $name, 'data' => $data, 'options' => $options];
|
|
}
|
|
}
|
|
|
|
if (!function_exists('base_url')) {
|
|
function base_url($uri = '')
|
|
{
|
|
return 'https://test.alrahmaisgl.org/' . ltrim((string) $uri, '/');
|
|
}
|
|
}
|
|
}
|
|
|
|
namespace Tests\App\Controllers\View {
|
|
|
|
use App\Controllers\View\GradingController;
|
|
use App\Services\BelowSixtyService;
|
|
use App\Services\GradingScoreService;
|
|
use App\Services\PlacementGradingService;
|
|
use App\Services\StudentDecisionService;
|
|
use CodeIgniter\HTTP\RedirectResponse;
|
|
use CodeIgniter\Test\CIUnitTestCase;
|
|
use Config\Services;
|
|
|
|
class GradingDummyRequest
|
|
{
|
|
public function __construct(private array $get = [], private array $post = [])
|
|
{
|
|
}
|
|
|
|
public function getGet($key = null)
|
|
{
|
|
if ($key === null) {
|
|
return $this->get;
|
|
}
|
|
|
|
return $this->get[$key] ?? null;
|
|
}
|
|
|
|
public function getPost($key = null)
|
|
{
|
|
if ($key === null) {
|
|
return $this->post;
|
|
}
|
|
|
|
return $this->post[$key] ?? null;
|
|
}
|
|
}
|
|
|
|
class GradingFakeJsonResponse
|
|
{
|
|
public mixed $json = null;
|
|
public int $statusCode = 200;
|
|
|
|
public function setJSON($data): self
|
|
{
|
|
$this->json = $data;
|
|
return $this;
|
|
}
|
|
|
|
public function setStatusCode(int $code): self
|
|
{
|
|
$this->statusCode = $code;
|
|
return $this;
|
|
}
|
|
}
|
|
|
|
class GradingFakeRenderer
|
|
{
|
|
public array $lastData = [];
|
|
public string $lastName = '';
|
|
|
|
public function setData(array $data, string $type = 'raw')
|
|
{
|
|
$this->lastData = $data;
|
|
return $this;
|
|
}
|
|
|
|
public function render(string $name, array $options = [], bool $saveData = false)
|
|
{
|
|
$this->lastName = $name;
|
|
return 'fake-render';
|
|
}
|
|
}
|
|
|
|
class TestableGradingController extends GradingController
|
|
{
|
|
public function __construct()
|
|
{
|
|
// Skip ConfigurationModel lookup in the real constructor.
|
|
}
|
|
|
|
public function setTerm(string $schoolYear, string $semester): self
|
|
{
|
|
$this->schoolYear = $schoolYear;
|
|
$this->semester = $semester;
|
|
return $this;
|
|
}
|
|
|
|
public function setRequest($request): self
|
|
{
|
|
$this->request = $request;
|
|
return $this;
|
|
}
|
|
|
|
public function setResponse($response): self
|
|
{
|
|
$this->response = $response;
|
|
return $this;
|
|
}
|
|
}
|
|
|
|
class GradingControllerTest extends CIUnitTestCase
|
|
{
|
|
private TestableGradingController $controller;
|
|
private GradingFakeRenderer $renderer;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
|
|
Services::resetSingle('session');
|
|
session()->start();
|
|
|
|
$this->controller = (new TestableGradingController())
|
|
->setTerm('2024-2025', 'Fall')
|
|
->setRequest(new GradingDummyRequest());
|
|
$this->renderer = new GradingFakeRenderer();
|
|
Services::injectMock('renderer', $this->renderer);
|
|
}
|
|
|
|
protected function tearDown(): void
|
|
{
|
|
foreach ([
|
|
'renderer',
|
|
'gradingScore',
|
|
'placementGrading',
|
|
'belowSixty',
|
|
'studentDecision',
|
|
] as $service) {
|
|
Services::resetSingle($service);
|
|
}
|
|
session()->destroy();
|
|
parent::tearDown();
|
|
}
|
|
|
|
public function testGradingPageRendersViewFromScoreService(): void
|
|
{
|
|
$scoreService = $this->createMock(GradingScoreService::class);
|
|
$scoreService->expects($this->once())->method('setTerm')->with('2024-2025', 'Fall');
|
|
$scoreService->expects($this->once())
|
|
->method('gradingPage')
|
|
->willReturn([
|
|
'kind' => 'view',
|
|
'view' => 'grading/grading_main',
|
|
'data' => [
|
|
'semester' => 'Fall',
|
|
'schoolYear' => '2024-2025',
|
|
'grades' => [],
|
|
],
|
|
]);
|
|
Services::injectMock('gradingScore', $scoreService);
|
|
|
|
$result = $this->controller->grading();
|
|
$data = $this->viewData($result, 'grading/grading_main');
|
|
|
|
$this->assertSame('Fall', $data['semester']);
|
|
$this->assertSame('2024-2025', $data['schoolYear']);
|
|
}
|
|
|
|
public function testUpdateMapsFlashResultToRedirect(): void
|
|
{
|
|
$scoreService = $this->createMock(GradingScoreService::class);
|
|
$scoreService->method('setTerm');
|
|
$scoreService->expects($this->once())
|
|
->method('updateScores')
|
|
->willReturn([
|
|
'kind' => 'flash',
|
|
'redirect' => 'back',
|
|
'type' => 'status',
|
|
'message' => 'Scores updated successfully.',
|
|
]);
|
|
Services::injectMock('gradingScore', $scoreService);
|
|
|
|
$this->controller->setRequest(new GradingDummyRequest([], [
|
|
'type' => 'homework',
|
|
'student_id' => 1,
|
|
]));
|
|
|
|
$response = $this->controller->update();
|
|
|
|
$this->assertInstanceOf(RedirectResponse::class, $response);
|
|
$this->assertSame('Scores updated successfully.', session()->getFlashdata('status'));
|
|
}
|
|
|
|
public function testGetScoreCommentReturnsJsonFromScoreService(): void
|
|
{
|
|
$payload = ['1' => ['homework' => [['score' => '10']]]];
|
|
|
|
$scoreService = $this->createMock(GradingScoreService::class);
|
|
$scoreService->method('setTerm');
|
|
$scoreService->expects($this->once())
|
|
->method('getScoreComment')
|
|
->willReturn($payload);
|
|
Services::injectMock('gradingScore', $scoreService);
|
|
|
|
$response = new GradingFakeJsonResponse();
|
|
$this->controller->setResponse($response);
|
|
|
|
$result = $this->controller->getScoreComment();
|
|
|
|
$this->assertSame($response, $result);
|
|
$this->assertSame($payload, $response->json);
|
|
}
|
|
|
|
public function testPlacementUsesPlacementService(): void
|
|
{
|
|
$placement = $this->createMock(PlacementGradingService::class);
|
|
$placement->expects($this->once())->method('setSchoolYear')->with('2024-2025');
|
|
$placement->expects($this->once())
|
|
->method('placementPage')
|
|
->willReturn([
|
|
'kind' => 'view',
|
|
'view' => 'grading/placement_index',
|
|
'data' => ['batches' => []],
|
|
]);
|
|
Services::injectMock('placementGrading', $placement);
|
|
|
|
$result = $this->controller->placement();
|
|
$data = $this->viewData($result, 'grading/placement_index');
|
|
|
|
$this->assertSame([], $data['batches']);
|
|
}
|
|
|
|
public function testAllDecisionsUsesDecisionService(): void
|
|
{
|
|
$decision = $this->createMock(StudentDecisionService::class);
|
|
$decision->method('setTerm');
|
|
$decision->expects($this->once())
|
|
->method('allDecisionsPage')
|
|
->willReturn([
|
|
'kind' => 'view',
|
|
'view' => 'grading/all_decisions',
|
|
'data' => ['rows' => [], 'schoolYear' => '2024-2025'],
|
|
]);
|
|
Services::injectMock('studentDecision', $decision);
|
|
|
|
$result = $this->controller->allDecisions();
|
|
$data = $this->viewData($result, 'grading/all_decisions');
|
|
|
|
$this->assertSame('2024-2025', $data['schoolYear']);
|
|
}
|
|
|
|
public function testRespondGradingMapsJsonKindWithStatus(): void
|
|
{
|
|
$belowSixty = $this->createMock(BelowSixtyService::class);
|
|
$belowSixty->method('setTerm');
|
|
$belowSixty->expects($this->once())
|
|
->method('studentDecisionDetails')
|
|
->willReturn([
|
|
'kind' => 'json',
|
|
'status' => 400,
|
|
'data' => ['error' => 'Missing student or school year.'],
|
|
]);
|
|
Services::injectMock('belowSixty', $belowSixty);
|
|
|
|
$response = new GradingFakeJsonResponse();
|
|
$this->controller->setResponse($response);
|
|
|
|
$result = $this->controller->studentDecisionDetails();
|
|
|
|
$this->assertSame($response, $result);
|
|
$this->assertSame(400, $response->statusCode);
|
|
$this->assertSame(['error' => 'Missing student or school year.'], $response->json);
|
|
}
|
|
|
|
public function testShowTypeDelegatesRouteArgsToScoreService(): void
|
|
{
|
|
$scoreService = $this->createMock(GradingScoreService::class);
|
|
$scoreService->method('setTerm');
|
|
$scoreService->expects($this->once())
|
|
->method('showType')
|
|
->with('homework', '12', '34', $this->isType('array'))
|
|
->willReturn([
|
|
'kind' => 'view',
|
|
'view' => 'grading/homework',
|
|
'data' => ['type' => 'homework'],
|
|
]);
|
|
Services::injectMock('gradingScore', $scoreService);
|
|
|
|
$result = $this->controller->show('homework', '12', '34');
|
|
$data = $this->viewData($result, 'grading/homework');
|
|
|
|
$this->assertSame('homework', $data['type']);
|
|
}
|
|
|
|
private function viewData(mixed $result, string $expectedView): array
|
|
{
|
|
if (is_array($result)) {
|
|
$this->assertSame($expectedView, $result['view']);
|
|
return $result['data'];
|
|
}
|
|
|
|
$this->assertSame('fake-render', $result);
|
|
$this->assertSame($expectedView, $this->renderer->lastName);
|
|
return $this->renderer->lastData;
|
|
}
|
|
}
|
|
}
|