createCalendar(); self::assertTrue($calendar->tenantId->equals(TenantId::fromString(self::TENANT_ID))); self::assertTrue($calendar->academicYearId->equals(AcademicYearId::fromString(self::ACADEMIC_YEAR_ID))); self::assertNull($calendar->zone); self::assertEmpty($calendar->entries()); } #[Test] public function configurerZoneDefInitLaZone(): void { $calendar = $this->createCalendar(); $calendar->configurerZone(SchoolZone::A); self::assertSame(SchoolZone::A, $calendar->zone); } #[Test] public function configurerZonePeutEtreChangee(): void { $calendar = $this->createCalendar(); $calendar->configurerZone(SchoolZone::A); $calendar->configurerZone(SchoolZone::C); self::assertSame(SchoolZone::C, $calendar->zone); } #[Test] public function ajouterEntreeAjouteAuCalendrier(): void { $calendar = $this->createCalendar(); $entry = $this->createEntry(CalendarEntryType::HOLIDAY, '2024-11-01', '2024-11-01', 'Toussaint'); $calendar->ajouterEntree($entry); self::assertCount(1, $calendar->entries()); self::assertSame($entry, $calendar->entries()[0]); } #[Test] public function ajouterPlusieursEntrees(): void { $calendar = $this->createCalendar(); $calendar->ajouterEntree($this->createEntry(CalendarEntryType::HOLIDAY, '2024-11-01', '2024-11-01', 'Toussaint')); $calendar->ajouterEntree($this->createEntry(CalendarEntryType::HOLIDAY, '2024-11-11', '2024-11-11', 'Armistice')); $calendar->ajouterEntree($this->createEntry(CalendarEntryType::VACATION, '2024-12-21', '2025-01-05', 'Vacances de Noël')); self::assertCount(3, $calendar->entries()); } #[Test] public function supprimerEntreeRetireEntreeExistante(): void { $calendar = $this->createCalendar(); $entry = $this->createEntry(CalendarEntryType::HOLIDAY, '2024-11-01', '2024-11-01', 'Toussaint'); $calendar->ajouterEntree($entry); $calendar->supprimerEntree($entry->id); self::assertEmpty($calendar->entries()); } #[Test] public function supprimerEntreeInexistanteLeveException(): void { $calendar = $this->createCalendar(); $this->expectException(CalendrierEntreeNonTrouveeException::class); $calendar->supprimerEntree(CalendarEntryId::generate()); } #[Test] public function viderEntreesSupprimeTout(): void { $calendar = $this->createCalendar(); $calendar->ajouterEntree($this->createEntry(CalendarEntryType::HOLIDAY, '2024-11-01', '2024-11-01', 'Toussaint')); $calendar->ajouterEntree($this->createEntry(CalendarEntryType::HOLIDAY, '2024-11-11', '2024-11-11', 'Armistice')); $calendar->viderEntrees(); self::assertEmpty($calendar->entries()); } #[Test] public function estJourOuvreRetourneTruePourJourSemaine(): void { $calendar = $this->createCalendar(); // Lundi 4 novembre 2024 self::assertTrue($calendar->estJourOuvre(new DateTimeImmutable('2024-11-04'))); } #[Test] public function estJourOuvreRetourneFalsePourSamedi(): void { $calendar = $this->createCalendar(); // Samedi 2 novembre 2024 self::assertFalse($calendar->estJourOuvre(new DateTimeImmutable('2024-11-02'))); } #[Test] public function estJourOuvreRetourneFalsePourDimanche(): void { $calendar = $this->createCalendar(); // Dimanche 3 novembre 2024 self::assertFalse($calendar->estJourOuvre(new DateTimeImmutable('2024-11-03'))); } #[Test] public function estJourOuvreRetourneFalsePourJourFerie(): void { $calendar = $this->createCalendar(); $calendar->ajouterEntree( $this->createEntry(CalendarEntryType::HOLIDAY, '2024-11-01', '2024-11-01', 'Toussaint'), ); // Vendredi 1er novembre 2024 (Toussaint) self::assertFalse($calendar->estJourOuvre(new DateTimeImmutable('2024-11-01'))); } #[Test] public function estJourOuvreRetourneFalsePendantVacances(): void { $calendar = $this->createCalendar(); $calendar->ajouterEntree( $this->createEntry(CalendarEntryType::VACATION, '2024-10-19', '2024-11-03', 'Vacances Toussaint'), ); // Mercredi 23 octobre 2024 (en plein dans les vacances) self::assertFalse($calendar->estJourOuvre(new DateTimeImmutable('2024-10-23'))); } #[Test] public function estJourOuvreRetourneFalsePourJourneePedagogique(): void { $calendar = $this->createCalendar(); $calendar->ajouterEntree( $this->createEntry(CalendarEntryType::PEDAGOGICAL_DAY, '2025-03-14', '2025-03-14', 'Formation'), ); // Vendredi 14 mars 2025 self::assertFalse($calendar->estJourOuvre(new DateTimeImmutable('2025-03-14'))); } #[Test] public function estJourOuvreRetourneTrueApresVacances(): void { $calendar = $this->createCalendar(); $calendar->ajouterEntree( $this->createEntry(CalendarEntryType::VACATION, '2024-10-19', '2024-11-03', 'Vacances Toussaint'), ); // Lundi 4 novembre 2024 (jour de reprise) self::assertTrue($calendar->estJourOuvre(new DateTimeImmutable('2024-11-04'))); } #[Test] public function trouverEntreePourDateRetourneEntreeCorrespondante(): void { $calendar = $this->createCalendar(); $holiday = $this->createEntry(CalendarEntryType::HOLIDAY, '2024-11-01', '2024-11-01', 'Toussaint'); $calendar->ajouterEntree($holiday); $found = $calendar->trouverEntreePourDate(new DateTimeImmutable('2024-11-01')); self::assertNotNull($found); self::assertSame('Toussaint', $found->label); } #[Test] public function trouverEntreePourDateRetourneNullSiAucune(): void { $calendar = $this->createCalendar(); $found = $calendar->trouverEntreePourDate(new DateTimeImmutable('2024-11-01')); self::assertNull($found); } #[Test] public function estEnVacancesRetourneTruePendantVacances(): void { $calendar = $this->createCalendar(); $calendar->ajouterEntree( $this->createEntry(CalendarEntryType::VACATION, '2024-10-19', '2024-11-03', 'Vacances Toussaint'), ); self::assertTrue($calendar->estEnVacances(new DateTimeImmutable('2024-10-25'))); } #[Test] public function estEnVacancesRetourneFalseHorsVacances(): void { $calendar = $this->createCalendar(); $calendar->ajouterEntree( $this->createEntry(CalendarEntryType::VACATION, '2024-10-19', '2024-11-03', 'Vacances Toussaint'), ); self::assertFalse($calendar->estEnVacances(new DateTimeImmutable('2024-11-04'))); } #[Test] public function estEnVacancesRetourneFalsePourJourFerie(): void { $calendar = $this->createCalendar(); $calendar->ajouterEntree( $this->createEntry(CalendarEntryType::HOLIDAY, '2024-11-01', '2024-11-01', 'Toussaint'), ); self::assertFalse($calendar->estEnVacances(new DateTimeImmutable('2024-11-01'))); } #[Test] public function estJourRetourVacancesRetourneTruePourJourApresFinVacances(): void { $calendar = $this->createCalendar(); $calendar->ajouterEntree( $this->createEntry(CalendarEntryType::VACATION, '2024-10-19', '2024-11-03', 'Vacances Toussaint'), ); // 4 novembre = lendemain de la fin des vacances (3 novembre) self::assertTrue($calendar->estJourRetourVacances(new DateTimeImmutable('2024-11-04'))); } #[Test] public function estJourRetourVacancesRetourneFalsePourJourNormal(): void { $calendar = $this->createCalendar(); $calendar->ajouterEntree( $this->createEntry(CalendarEntryType::VACATION, '2024-10-19', '2024-11-03', 'Vacances Toussaint'), ); self::assertFalse($calendar->estJourRetourVacances(new DateTimeImmutable('2024-11-05'))); } #[Test] public function configurerDefinitZoneEtImporteEntreesAvecEvenement(): void { $calendar = $this->createCalendar(); $entries = [ $this->createEntry(CalendarEntryType::HOLIDAY, '2024-11-01', '2024-11-01', 'Toussaint'), $this->createEntry(CalendarEntryType::VACATION, '2024-10-19', '2024-11-03', 'Vacances Toussaint'), ]; $at = new DateTimeImmutable('2026-02-17 10:00:00'); $calendar->configurer(SchoolZone::A, $entries, $at); self::assertSame(SchoolZone::A, $calendar->zone); self::assertCount(2, $calendar->entries()); $events = $calendar->pullDomainEvents(); self::assertCount(1, $events); self::assertInstanceOf(CalendrierConfigure::class, $events[0]); self::assertSame(SchoolZone::A, $events[0]->zone); self::assertSame(2, $events[0]->nombreEntrees); $expectedAggregateId = Uuid::uuid5( Uuid::NAMESPACE_DNS, sprintf('school-calendar:%s:%s', self::TENANT_ID, self::ACADEMIC_YEAR_ID), ); self::assertTrue($events[0]->aggregateId()->equals($expectedAggregateId)); } #[Test] public function configurerPreserveJourneesPedagogiques(): void { $calendar = $this->createCalendar(); $pedaEntry = $this->createEntry(CalendarEntryType::PEDAGOGICAL_DAY, '2025-03-14', '2025-03-14', 'Formation'); $calendar->ajouterEntree($pedaEntry); $calendar->ajouterEntree($this->createEntry(CalendarEntryType::HOLIDAY, '2024-11-01', '2024-11-01', 'Toussaint')); $entries = [ $this->createEntry(CalendarEntryType::VACATION, '2024-12-21', '2025-01-05', 'Vacances de Noël'), ]; $calendar->configurer(SchoolZone::A, $entries, new DateTimeImmutable()); // 1 preserved pedagogical day + 1 new vacation = 2 self::assertCount(2, $calendar->entries()); $types = array_map(static fn (CalendarEntry $e) => $e->type, $calendar->entries()); self::assertContains(CalendarEntryType::PEDAGOGICAL_DAY, $types); self::assertContains(CalendarEntryType::VACATION, $types); self::assertNotContains(CalendarEntryType::HOLIDAY, $types); } #[Test] public function configurerReemplaceEntreesExistantes(): void { $calendar = $this->createCalendar(); $calendar->ajouterEntree($this->createEntry(CalendarEntryType::HOLIDAY, '2024-11-01', '2024-11-01', 'Ancienne')); $entries = [ $this->createEntry(CalendarEntryType::HOLIDAY, '2024-11-11', '2024-11-11', 'Armistice'), ]; $calendar->configurer(SchoolZone::B, $entries, new DateTimeImmutable()); self::assertCount(1, $calendar->entries()); self::assertSame('Armistice', $calendar->entries()[0]->label); } #[Test] public function ajouterJourneePedagogiqueEmetEvenement(): void { $calendar = $this->createCalendar(); $entry = $this->createEntry(CalendarEntryType::PEDAGOGICAL_DAY, '2025-03-14', '2025-03-14', 'Formation enseignants'); $at = new DateTimeImmutable('2026-02-17 10:00:00'); $calendar->ajouterJourneePedagogique($entry, $at); self::assertCount(1, $calendar->entries()); $events = $calendar->pullDomainEvents(); self::assertCount(1, $events); self::assertInstanceOf(JourneePedagogiqueAjoutee::class, $events[0]); self::assertSame('Formation enseignants', $events[0]->label); self::assertSame('2025-03-14', $events[0]->date->format('Y-m-d')); $expectedAggregateId = Uuid::uuid5( Uuid::NAMESPACE_DNS, sprintf('school-calendar:%s:%s', self::TENANT_ID, self::ACADEMIC_YEAR_ID), ); self::assertTrue($events[0]->aggregateId()->equals($expectedAggregateId)); } #[Test] public function ajouterJourneePedagogiqueRefuseTypeDifferent(): void { $calendar = $this->createCalendar(); $entry = $this->createEntry(CalendarEntryType::HOLIDAY, '2024-11-01', '2024-11-01', 'Toussaint'); $this->expectException(InvalidArgumentException::class); $calendar->ajouterJourneePedagogique($entry, new DateTimeImmutable()); } #[Test] public function reconstituteRestaureLEtat(): void { $tenantId = TenantId::fromString(self::TENANT_ID); $yearId = AcademicYearId::fromString(self::ACADEMIC_YEAR_ID); $entry1 = $this->createEntry(CalendarEntryType::HOLIDAY, '2024-11-01', '2024-11-01', 'Toussaint'); $entry2 = $this->createEntry(CalendarEntryType::VACATION, '2024-12-21', '2025-01-05', 'Noël'); $calendar = SchoolCalendar::reconstitute( tenantId: $tenantId, academicYearId: $yearId, zone: SchoolZone::B, entries: [$entry1, $entry2], ); self::assertTrue($calendar->tenantId->equals($tenantId)); self::assertTrue($calendar->academicYearId->equals($yearId)); self::assertSame(SchoolZone::B, $calendar->zone); self::assertCount(2, $calendar->entries()); self::assertEmpty($calendar->pullDomainEvents()); } private function createCalendar(): SchoolCalendar { return SchoolCalendar::initialiser( tenantId: TenantId::fromString(self::TENANT_ID), academicYearId: AcademicYearId::fromString(self::ACADEMIC_YEAR_ID), ); } private function createEntry( CalendarEntryType $type, string $startDate, string $endDate, string $label, ): CalendarEntry { return new CalendarEntry( id: CalendarEntryId::generate(), type: $type, startDate: new DateTimeImmutable($startDate), endDate: new DateTimeImmutable($endDate), label: $label, ); } }