pickupLoader = $this->createMock(PickupLoader::class); $this->hotelLoader = $this->createMock(HotelLoader::class); $this->insuranceLoader = $this->createMock(InsuranceLoader::class); $this->logger = $this->createMock(LoggerInterface::class); $this->service = new TravelEnrichmentService( $this->pickupLoader, $this->hotelLoader, $this->insuranceLoader, $this->logger, ); } // ------------------------------------------------------------------------- // enrichFromXml // ------------------------------------------------------------------------- public function testEnrichFromXmlReturnsTrueOnSuccess(): void { $travel = new Travel(); $travel->id = 100; $this->pickupLoader ->expects($this->once()) ->method('patchPickupsDetails') ->with($travel); $this->hotelLoader ->expects($this->once()) ->method('patchHotelDetails') ->with($travel); $this->assertTrue($this->service->enrichFromXml($travel)); } public function testEnrichFromXmlReturnsFalseAndLogsWarningOnFailure(): void { $travel = new Travel(); $travel->id = 100; $this->pickupLoader ->method('patchPickupsDetails') ->willThrowException(new \RuntimeException('XML error')); $this->logger ->expects($this->once()) ->method('warning') ->with('Failed to enrich travel data', $this->arrayHasKey('travelId')); $this->assertFalse($this->service->enrichFromXml($travel)); } // ------------------------------------------------------------------------- // patchInsurances // ------------------------------------------------------------------------- public function testPatchInsurancesReplacesExistingInsurances(): void { $travel = new Travel(); $travel->id = 100; $stale = new Insurance(); $stale->id = 'stale'; $travel->insurances = [$stale]; $individual = new Insurance(); $individual->id = '10'; $individual->package = false; $package = new Insurance(); $package->id = '20'; $package->package = true; $package->containedInsuranceIds = ['10']; // InsuranceParser populates containedInsurances at parse time $package->containedInsurances = [$individual]; $this->insuranceLoader ->expects($this->once()) ->method('loadAll') ->willReturn([$individual, $package]); $this->service->patchInsurances($travel); $this->assertSame([$individual, $package], $travel->insurances); } public function testPatchInsurancesPreservesContainedInsurancesFromParser(): void { $travel = new Travel(); $travel->id = 100; $individual = new Insurance(); $individual->id = '10'; $individual->package = false; $package = new Insurance(); $package->id = '20'; $package->package = true; $package->containedInsuranceIds = ['10']; $package->containedInsurances = [$individual]; $this->insuranceLoader->method('loadAll')->willReturn([$individual, $package]); $this->service->patchInsurances($travel); $this->assertCount(1, $package->containedInsurances); $this->assertSame($individual, $package->containedInsurances[0]); } public function testPatchInsurancesLogsWarningOnFailureAndDoesNotThrow(): void { $travel = new Travel(); $travel->id = 100; $original = []; $travel->insurances = $original; $this->insuranceLoader ->method('loadAll') ->willThrowException(new \RuntimeException('XML parse error')); $this->logger ->expects($this->once()) ->method('warning') ->with('Failed to load insurance data', $this->arrayHasKey('travelId')); // Must not throw; insurances stay unchanged $this->service->patchInsurances($travel); $this->assertSame($original, $travel->insurances); } }