dayRepository = $this->createStub(ContingentDayRepository::class); $this->syncStateRepository = $this->createStub(ContingentSyncStateRepository::class); } public function testReturnsNullWhenNothingHasEverSynced(): void { $this->dayRepository = $this->createMock(ContingentDayRepository::class); $this->syncStateRepository->method('findOneByAccommodation')->willReturn(null); $this->dayRepository->expects(self::never())->method('findByHotelCodeAndDateRange'); self::assertNull($this->read()); } public function testReturnsNullWhenTheSnapshotIsStale(): void { $this->dayRepository = $this->createMock(ContingentDayRepository::class); $this->syncStateRepository->method('findOneByAccommodation')->willReturn($this->state('-7 hours')); $this->dayRepository->expects(self::never())->method('findByHotelCodeAndDateRange'); self::assertNull($this->read()); } public function testReturnsStatusesWhenRecentlySynced(): void { $this->syncStateRepository->method('findOneByAccommodation')->willReturn($this->state('-10 minutes')); $this->dayRepository->method('findByHotelCodeAndDateRange')->willReturn([ '2026-09-01' => $this->day(ContingentStatus::Ok), '2026-09-02' => $this->day(ContingentStatus::OnRequest), ]); self::assertSame([ '2026-09-01' => ContingentStatus::Ok, '2026-09-02' => ContingentStatus::OnRequest, ], $this->read()); } public function testStillUsableJustInsideTheStalenessWindow(): void { $this->syncStateRepository->method('findOneByAccommodation')->willReturn($this->state('-5 hours')); $this->dayRepository->method('findByHotelCodeAndDateRange')->willReturn([]); self::assertSame([], $this->read()); } public function testReturnsNullForAnAccommodationWithoutACalendarCode(): void { $this->syncStateRepository = $this->createMock(ContingentSyncStateRepository::class); $this->syncStateRepository->expects(self::never())->method('findOneByAccommodation'); self::assertNull($this->read(new Accommodation())); } /** * @return array|null */ private function read(?Accommodation $accommodation = null): ?array { $reader = new ContingentSnapshotReader( $this->dayRepository, $this->syncStateRepository, $this->createStub(LoggerInterface::class), ); return $reader->statusesFor( $accommodation ?? (new Accommodation())->setCalendarCode('HOTEL1'), new \DateTimeImmutable('2026-09-01'), new \DateTimeImmutable('2026-09-03'), ); } private function state(string $syncedAgo): ContingentSyncState { return (new ContingentSyncState())->setSyncedAt(CarbonImmutable::now()->modify($syncedAgo)->toDateTimeImmutable()); } private function day(ContingentStatus $status): ContingentDay { return (new ContingentDay())->setStatus($status); } }