repository = new InMemoryPeriodConfigurationRepository(); $clock = new class implements Clock { public function now(): DateTimeImmutable { return new DateTimeImmutable('2026-01-31 10:00:00'); } }; $eventBus = new class implements MessageBusInterface { public function dispatch(object $message, array $stamps = []): Envelope { return new Envelope($message); } }; $this->handler = new ConfigurePeriodsHandler($this->repository, $clock, $eventBus); } #[Test] public function itConfiguresTrimesterPeriods(): void { $command = new ConfigurePeriodsCommand( tenantId: self::TENANT_ID, academicYearId: self::ACADEMIC_YEAR_ID, periodType: 'trimester', startYear: 2025, ); $config = ($this->handler)($command); self::assertSame(PeriodType::TRIMESTER, $config->type); self::assertCount(3, $config->periods); self::assertSame('T1', $config->periods[0]->label); self::assertSame('T2', $config->periods[1]->label); self::assertSame('T3', $config->periods[2]->label); } #[Test] public function itConfiguresSemesterPeriods(): void { $command = new ConfigurePeriodsCommand( tenantId: self::TENANT_ID, academicYearId: self::ACADEMIC_YEAR_ID, periodType: 'semester', startYear: 2025, ); $config = ($this->handler)($command); self::assertSame(PeriodType::SEMESTER, $config->type); self::assertCount(2, $config->periods); self::assertSame('S1', $config->periods[0]->label); self::assertSame('S2', $config->periods[1]->label); } #[Test] public function itPersistsConfiguration(): void { $command = new ConfigurePeriodsCommand( tenantId: self::TENANT_ID, academicYearId: self::ACADEMIC_YEAR_ID, periodType: 'trimester', startYear: 2025, ); ($this->handler)($command); $saved = $this->repository->findByAcademicYear( \App\Shared\Domain\Tenant\TenantId::fromString(self::TENANT_ID), \App\Administration\Domain\Model\SchoolClass\AcademicYearId::fromString(self::ACADEMIC_YEAR_ID), ); self::assertNotNull($saved); self::assertSame(PeriodType::TRIMESTER, $saved->type); } #[Test] public function itRejectsDoubleConfiguration(): void { $command = new ConfigurePeriodsCommand( tenantId: self::TENANT_ID, academicYearId: self::ACADEMIC_YEAR_ID, periodType: 'trimester', startYear: 2025, ); ($this->handler)($command); $this->expectException(PeriodesDejaConfigureesException::class); ($this->handler)($command); } #[Test] public function itAllowsDifferentTenantsToConfigureSameYear(): void { $otherTenantId = '550e8400-e29b-41d4-a716-446655440099'; ($this->handler)(new ConfigurePeriodsCommand( tenantId: self::TENANT_ID, academicYearId: self::ACADEMIC_YEAR_ID, periodType: 'trimester', startYear: 2025, )); $config = ($this->handler)(new ConfigurePeriodsCommand( tenantId: $otherTenantId, academicYearId: self::ACADEMIC_YEAR_ID, periodType: 'semester', startYear: 2025, )); self::assertSame(PeriodType::SEMESTER, $config->type); } }