Files
myep/tests/Service/ContingentSnapshotReaderTest.php
T

109 lines
3.8 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Tests\Service;
use App\BpnConnect\Model\ContingentStatus;
use App\Entity\Groups\Accommodation;
use App\Entity\Groups\ContingentDay;
use App\Entity\Groups\ContingentSyncState;
use App\Repository\Groups\ContingentDayRepository;
use App\Repository\Groups\ContingentSyncStateRepository;
use App\Service\ContingentSnapshotReader;
use Carbon\CarbonImmutable;
use PHPUnit\Framework\MockObject\Stub;
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;
class ContingentSnapshotReaderTest extends TestCase
{
private ContingentDayRepository&Stub $dayRepository;
private ContingentSyncStateRepository&Stub $syncStateRepository;
protected function setUp(): void
{
$this->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<string, ContingentStatus>|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);
}
}