sequence); self::assertSame('T1', $period->label); self::assertSame('2025-09-01', $period->startDate->format('Y-m-d')); self::assertSame('2025-11-30', $period->endDate->format('Y-m-d')); } #[Test] public function itRejectsEndDateBeforeStartDate(): void { $this->expectException(InvalidPeriodDatesException::class); new AcademicPeriod( sequence: 1, label: 'T1', startDate: new DateTimeImmutable('2025-11-30'), endDate: new DateTimeImmutable('2025-09-01'), ); } #[Test] public function itRejectsEqualDates(): void { $this->expectException(InvalidPeriodDatesException::class); new AcademicPeriod( sequence: 1, label: 'T1', startDate: new DateTimeImmutable('2025-09-01'), endDate: new DateTimeImmutable('2025-09-01'), ); } #[Test] public function itDetectsDateWithinPeriod(): void { $period = new AcademicPeriod( sequence: 1, label: 'T1', startDate: new DateTimeImmutable('2025-09-01'), endDate: new DateTimeImmutable('2025-11-30'), ); self::assertTrue($period->containsDate(new DateTimeImmutable('2025-10-15'))); self::assertTrue($period->containsDate(new DateTimeImmutable('2025-09-01'))); self::assertTrue($period->containsDate(new DateTimeImmutable('2025-11-30'))); self::assertFalse($period->containsDate(new DateTimeImmutable('2025-08-31'))); self::assertFalse($period->containsDate(new DateTimeImmutable('2025-12-01'))); } #[Test] public function itIncludesLastDayRegardlessOfTime(): void { $period = new AcademicPeriod( sequence: 1, label: 'T1', startDate: new DateTimeImmutable('2025-09-01'), endDate: new DateTimeImmutable('2025-11-30'), ); // Last day at 15:00 must still be "within" the period self::assertTrue($period->containsDate(new DateTimeImmutable('2025-11-30 15:00:00'))); self::assertFalse($period->isPast(new DateTimeImmutable('2025-11-30 23:59:59'))); self::assertTrue($period->isPast(new DateTimeImmutable('2025-12-01 00:00:01'))); // daysRemaining on last day should be 0 (same day) self::assertSame(0, $period->daysRemaining(new DateTimeImmutable('2025-11-30 15:00:00'))); } #[Test] public function itCalculatesDaysRemaining(): void { $period = new AcademicPeriod( sequence: 1, label: 'T1', startDate: new DateTimeImmutable('2025-09-01'), endDate: new DateTimeImmutable('2025-11-30'), ); // During the period self::assertSame(30, $period->daysRemaining(new DateTimeImmutable('2025-10-31'))); // After the period self::assertSame(0, $period->daysRemaining(new DateTimeImmutable('2025-12-01'))); // Before the period: returns total period length self::assertSame(90, $period->daysRemaining(new DateTimeImmutable('2025-08-01'))); } #[Test] public function itDetectsPastPeriod(): void { $period = new AcademicPeriod( sequence: 1, label: 'T1', startDate: new DateTimeImmutable('2025-09-01'), endDate: new DateTimeImmutable('2025-11-30'), ); self::assertTrue($period->isPast(new DateTimeImmutable('2025-12-01'))); self::assertFalse($period->isPast(new DateTimeImmutable('2025-11-30'))); self::assertFalse($period->isPast(new DateTimeImmutable('2025-10-15'))); } }