createMock(TagAwareCacheInterface::class); $filesystem = $this->createMock(FilesystemOperator::class); $parser = $this->createMock(ContingentParser::class); $filesystem->method('listContents')->willReturn(new DirectoryListing([ new FileAttributes('HotelZimmer_100.xml', 10), new FileAttributes('HotelZimmer_200.xml', 10), new FileAttributes('other.xml', 10), ])); $item = $this->createMock(ItemInterface::class); $item->expects($this->once())->method('expiresAfter')->with(3 * 60 * 60); $item->expects($this->once())->method('tag')->with(['xml-sync']); $cache->expects($this->once()) ->method('get') ->with('bpn_contingent_files', $this->isType('callable')) ->willReturnCallback(fn (string $key, callable $callback) => $callback($item)); $loader = new ContingentLoader($parser, $cache, $filesystem); $map = $loader->generateFilesMap(); $this->assertSame([ 100 => 'HotelZimmer_100.xml', 200 => 'HotelZimmer_200.xml', ], $map); } public function testLoadByHotelIdUsesRootLinkOneHopAndTagsCache(): void { $cache = $this->createMock(TagAwareCacheInterface::class); $filesystem = $this->createMock(FilesystemOperator::class); $parser = $this->createMock(ContingentParser::class); $originalXml = ''; $linkedXml = ''; $parsed = ['roomTypes' => [], 'rows' => [['roomCode' => 'DZ']]]; $filesystem->method('listContents')->willReturn(new DirectoryListing([ new FileAttributes('HotelZimmer_100.xml', 10), new FileAttributes('HotelZimmer_200.xml', 10), ])); $filesystem->method('read')->willReturnMap([ ['HotelZimmer_100.xml', $originalXml], ['HotelZimmer_200.xml', $linkedXml], ]); $mapItem = $this->createMock(ItemInterface::class); $mapItem->method('expiresAfter')->with(3 * 60 * 60); $mapItem->method('tag')->with(['xml-sync']); $hotelItem = $this->createMock(ItemInterface::class); $hotelItem->method('expiresAfter')->with(3600); $hotelItem->method('tag')->with(['xml-sync']); $cache->method('get')->willReturnCallback( function (string $key, callable $callback) use ($mapItem, $hotelItem) { if ('bpn_contingent_files' === $key) { return $callback($mapItem); } if ('contingent_hotel_100' === $key) { return $callback($hotelItem); } return null; } ); $parser->expects($this->once())->method('parse')->with($linkedXml)->willReturn($parsed); $loader = new ContingentLoader($parser, $cache, $filesystem); $result = $loader->loadByHotelId(100); $this->assertSame($parsed, $result); } public function testLoadByHotelIdReturnsEmptyWhenLinkedTargetIsMissing(): void { $cache = $this->createMock(TagAwareCacheInterface::class); $filesystem = $this->createMock(FilesystemOperator::class); $parser = $this->createMock(ContingentParser::class); $xml = ''; $filesystem->method('listContents')->willReturn(new DirectoryListing([ new FileAttributes('HotelZimmer_100.xml', 10), ])); $filesystem->method('read')->willReturn($xml); $mapItem = $this->createMock(ItemInterface::class); $mapItem->method('expiresAfter')->with(3 * 60 * 60); $mapItem->method('tag')->with(['xml-sync']); $hotelItem = $this->createMock(ItemInterface::class); $hotelItem->method('expiresAfter')->with(3600); $hotelItem->method('tag')->with(['xml-sync']); $cache->method('get')->willReturnCallback( function (string $key, callable $callback) use ($mapItem, $hotelItem) { if ('bpn_contingent_files' === $key) { return $callback($mapItem); } if ('contingent_hotel_100' === $key) { return $callback($hotelItem); } return null; } ); $parser->expects($this->never())->method('parse'); $loader = new ContingentLoader($parser, $cache, $filesystem); $result = $loader->loadByHotelId(100); $this->assertSame(['roomTypes' => [], 'rows' => []], $result); } }