handler = static::getContainer()->get(ValidateHomeworkDueDateHandler::class); } protected function tearDown(): void { /** @var Connection $connection */ $connection = static::getContainer()->get(Connection::class); $connection->executeStatement( 'DELETE FROM school_calendar_entries WHERE tenant_id = :tenant_id AND academic_year_id = :academic_year_id', ['tenant_id' => self::TENANT_ID, 'academic_year_id' => self::ACADEMIC_YEAR_ID], ); parent::tearDown(); } // ========================================================================= // AC3 (P0) — Blocage jours fériés // ========================================================================= #[Test] public function itRejectsHolidayAsHomeworkDueDate(): void { $this->persistCalendar([ new CalendarEntry( id: CalendarEntryId::generate(), type: CalendarEntryType::HOLIDAY, startDate: new DateTimeImmutable('2024-12-25'), endDate: new DateTimeImmutable('2024-12-25'), label: 'Noël', ), ]); // 2024-12-25 is a Wednesday (weekday) but a holiday $result = ($this->handler)(new ValidateHomeworkDueDateQuery( tenantId: self::TENANT_ID, academicYearId: self::ACADEMIC_YEAR_ID, dueDate: '2024-12-25', )); self::assertFalse($result->valid); self::assertNotNull($result->reason); self::assertStringContainsString('férié', $result->reason); } // ========================================================================= // AC3/AC4 (P0/P1) — Blocage vacances // ========================================================================= #[Test] public function itRejectsVacationDayAsHomeworkDueDate(): void { $this->persistCalendar([ new CalendarEntry( id: CalendarEntryId::generate(), type: CalendarEntryType::VACATION, startDate: new DateTimeImmutable('2025-02-15'), endDate: new DateTimeImmutable('2025-03-02'), label: 'Vacances d\'hiver', ), ]); // 2025-02-20 is a Thursday during the vacation $result = ($this->handler)(new ValidateHomeworkDueDateQuery( tenantId: self::TENANT_ID, academicYearId: self::ACADEMIC_YEAR_ID, dueDate: '2025-02-20', )); self::assertFalse($result->valid); self::assertNotNull($result->reason); self::assertStringContainsString('vacances', $result->reason); } // ========================================================================= // AC4 (P1) — Warning retour vacances // ========================================================================= #[Test] public function itAcceptsReturnDayWithWarning(): void { $this->persistCalendar([ new CalendarEntry( id: CalendarEntryId::generate(), type: CalendarEntryType::VACATION, startDate: new DateTimeImmutable('2025-02-15'), endDate: new DateTimeImmutable('2025-03-02'), label: 'Vacances d\'hiver', ), ]); // 2025-03-03 is a Monday, the day after vacation ends (2025-03-02) $result = ($this->handler)(new ValidateHomeworkDueDateQuery( tenantId: self::TENANT_ID, academicYearId: self::ACADEMIC_YEAR_ID, dueDate: '2025-03-03', )); self::assertTrue($result->valid); self::assertNotEmpty($result->warnings); self::assertStringContainsString('retour de vacances', $result->warnings[0]); } // ========================================================================= // Cas nominal — jour ouvré normal // ========================================================================= #[Test] public function itAcceptsNormalWeekday(): void { $this->persistCalendar(); // 2025-03-10 is a Monday with no calendar entry $result = ($this->handler)(new ValidateHomeworkDueDateQuery( tenantId: self::TENANT_ID, academicYearId: self::ACADEMIC_YEAR_ID, dueDate: '2025-03-10', )); self::assertTrue($result->valid); self::assertNull($result->reason); self::assertEmpty($result->warnings); } // ========================================================================= // Helpers // ========================================================================= private function persistCalendar(array $entries = []): void { $tenantId = TenantId::fromString(self::TENANT_ID); $academicYearId = AcademicYearId::fromString(self::ACADEMIC_YEAR_ID); $calendar = SchoolCalendar::initialiser($tenantId, $academicYearId); foreach ($entries as $entry) { $calendar->ajouterEntree($entry); } /** @var SchoolCalendarRepository $repository */ $repository = static::getContainer()->get(SchoolCalendarRepository::class); $repository->save($calendar); } }