Files
Classeo/backend/tests/Unit/Administration/Domain/Model/AcademicYear/PeriodConfigurationTest.php
Mathias STRASSER f19d0ae3ef feat: Gestion des périodes scolaires
L'administration d'un établissement nécessite de découper l'année
scolaire en trimestres ou semestres avant de pouvoir saisir les notes
et générer les bulletins.

Ce module permet de configurer les périodes par année scolaire
(current/previous/next résolus en UUID v5 déterministes), de modifier
les dates individuelles avec validation anti-chevauchement, et de
consulter la période en cours avec le décompte des jours restants.

Les dates par défaut de février s'adaptent aux années bissextiles.
Le repository utilise UPSERT transactionnel pour garantir l'intégrité
lors du changement de mode (trimestres ↔ semestres). Les domain events
de Subject sont étendus pour couvrir toutes les mutations (code,
couleur, description) en plus du renommage.
2026-02-06 14:27:55 +01:00

151 lines
6.0 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Tests\Unit\Administration\Domain\Model\AcademicYear;
use App\Administration\Domain\Exception\InvalidPeriodCountException;
use App\Administration\Domain\Exception\PeriodsCoverageGapException;
use App\Administration\Domain\Exception\PeriodsOverlapException;
use App\Administration\Domain\Model\AcademicYear\AcademicPeriod;
use App\Administration\Domain\Model\AcademicYear\PeriodConfiguration;
use App\Administration\Domain\Model\AcademicYear\PeriodType;
use DateTimeImmutable;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;
final class PeriodConfigurationTest extends TestCase
{
#[Test]
public function itCreatesValidTrimesterConfiguration(): void
{
$config = $this->validTrimesterConfig();
self::assertSame(PeriodType::TRIMESTER, $config->type);
self::assertCount(3, $config->periods);
self::assertSame('2025-09-01', $config->startDate()->format('Y-m-d'));
self::assertSame('2026-06-30', $config->endDate()->format('Y-m-d'));
}
#[Test]
public function itCreatesValidSemesterConfiguration(): void
{
$config = new PeriodConfiguration(PeriodType::SEMESTER, [
new AcademicPeriod(1, 'S1', new DateTimeImmutable('2025-09-01'), new DateTimeImmutable('2026-01-31')),
new AcademicPeriod(2, 'S2', new DateTimeImmutable('2026-02-01'), new DateTimeImmutable('2026-06-30')),
]);
self::assertSame(PeriodType::SEMESTER, $config->type);
self::assertCount(2, $config->periods);
}
#[Test]
public function itRejectsWrongPeriodCountForTrimester(): void
{
$this->expectException(InvalidPeriodCountException::class);
new PeriodConfiguration(PeriodType::TRIMESTER, [
new AcademicPeriod(1, 'S1', new DateTimeImmutable('2025-09-01'), new DateTimeImmutable('2026-01-31')),
new AcademicPeriod(2, 'S2', new DateTimeImmutable('2026-02-01'), new DateTimeImmutable('2026-06-30')),
]);
}
#[Test]
public function itRejectsWrongPeriodCountForSemester(): void
{
$this->expectException(InvalidPeriodCountException::class);
new PeriodConfiguration(PeriodType::SEMESTER, [
new AcademicPeriod(1, 'T1', new DateTimeImmutable('2025-09-01'), new DateTimeImmutable('2025-11-30')),
new AcademicPeriod(2, 'T2', new DateTimeImmutable('2025-12-01'), new DateTimeImmutable('2026-02-28')),
new AcademicPeriod(3, 'T3', new DateTimeImmutable('2026-03-01'), new DateTimeImmutable('2026-06-30')),
]);
}
#[Test]
public function itRejectsOverlappingPeriods(): void
{
$this->expectException(PeriodsOverlapException::class);
new PeriodConfiguration(PeriodType::TRIMESTER, [
new AcademicPeriod(1, 'T1', new DateTimeImmutable('2025-09-01'), new DateTimeImmutable('2025-12-01')),
new AcademicPeriod(2, 'T2', new DateTimeImmutable('2025-11-30'), new DateTimeImmutable('2026-02-28')),
new AcademicPeriod(3, 'T3', new DateTimeImmutable('2026-03-01'), new DateTimeImmutable('2026-06-30')),
]);
}
#[Test]
public function itRejectsCoverageGap(): void
{
$this->expectException(PeriodsCoverageGapException::class);
new PeriodConfiguration(PeriodType::TRIMESTER, [
new AcademicPeriod(1, 'T1', new DateTimeImmutable('2025-09-01'), new DateTimeImmutable('2025-11-28')),
new AcademicPeriod(2, 'T2', new DateTimeImmutable('2025-12-01'), new DateTimeImmutable('2026-02-28')),
new AcademicPeriod(3, 'T3', new DateTimeImmutable('2026-03-01'), new DateTimeImmutable('2026-06-30')),
]);
}
#[Test]
public function itSortsPeriodsByStartDate(): void
{
$config = new PeriodConfiguration(PeriodType::TRIMESTER, [
new AcademicPeriod(3, 'T3', new DateTimeImmutable('2026-03-01'), new DateTimeImmutable('2026-06-30')),
new AcademicPeriod(1, 'T1', new DateTimeImmutable('2025-09-01'), new DateTimeImmutable('2025-11-30')),
new AcademicPeriod(2, 'T2', new DateTimeImmutable('2025-12-01'), new DateTimeImmutable('2026-02-28')),
]);
self::assertSame('T1', $config->periods[0]->label);
self::assertSame('T2', $config->periods[1]->label);
self::assertSame('T3', $config->periods[2]->label);
}
#[Test]
public function itFindsCurrentPeriod(): void
{
$config = $this->validTrimesterConfig();
$current = $config->currentPeriod(new DateTimeImmutable('2025-10-15'));
self::assertNotNull($current);
self::assertSame('T1', $current->label);
$current = $config->currentPeriod(new DateTimeImmutable('2026-01-15'));
self::assertNotNull($current);
self::assertSame('T2', $current->label);
$current = $config->currentPeriod(new DateTimeImmutable('2026-05-01'));
self::assertNotNull($current);
self::assertSame('T3', $current->label);
}
#[Test]
public function itReturnsNullWhenNoCurrentPeriod(): void
{
$config = $this->validTrimesterConfig();
self::assertNull($config->currentPeriod(new DateTimeImmutable('2025-08-01')));
self::assertNull($config->currentPeriod(new DateTimeImmutable('2026-07-01')));
}
#[Test]
public function itFindsPeriodBySequence(): void
{
$config = $this->validTrimesterConfig();
$period = $config->periodBySequence(2);
self::assertNotNull($period);
self::assertSame('T2', $period->label);
self::assertNull($config->periodBySequence(4));
}
private function validTrimesterConfig(): PeriodConfiguration
{
return new PeriodConfiguration(PeriodType::TRIMESTER, [
new AcademicPeriod(1, 'T1', new DateTimeImmutable('2025-09-01'), new DateTimeImmutable('2025-11-30')),
new AcademicPeriod(2, 'T2', new DateTimeImmutable('2025-12-01'), new DateTimeImmutable('2026-02-28')),
new AcademicPeriod(3, 'T3', new DateTimeImmutable('2026-03-01'), new DateTimeImmutable('2026-06-30')),
]);
}
}