handler = new ParticipantParkingFieldHandler(); } public function testGetFieldName(): void { $this->assertSame('parking', $this->handler->getFieldName()); } public function testGetDependencies(): void { $this->assertSame(['transportationOutbound', 'transportationInbound', 'dateOfBirth'], $this->handler->getDependencies()); } public function testShouldProcessAlwaysReturnsTrue(): void { $this->assertTrue($this->handler->shouldProcess([], BookingDto::MODE_CREATE, 0)); $this->assertTrue($this->handler->shouldProcess(['some' => 'data'], BookingDto::MODE_EDIT, 5)); } /** * @dataProvider normalizeCheckboxValueCheckedProvider */ public function testNormalizeCheckboxValueReturnsTrueWhenChecked(mixed $value): void { $this->assertTrue($this->invokeNormalizeCheckboxValue($value)); } /** * @dataProvider normalizeCheckboxValueUncheckedProvider */ public function testNormalizeCheckboxValueReturnsFalseWhenUnchecked(mixed $value): void { $this->assertFalse($this->invokeNormalizeCheckboxValue($value)); } public function testProcessFieldWithoutParticipant(): void { $travel = new Travel(); $bookingDto = new BookingDto($travel, 1); $submittedData = ['parking' => true]; $this->handler->processField($submittedData, $bookingDto, 0); $this->expectNotToPerformAssertions(); } public function testProcessFieldClearsParkingWhenTransportationIsNotPkw(): void { $busService = $this->createTransportationService(DirectionMapper::SUBTYPE_BUS_API); $participant = new ParticipantDto(); $participant->dateOfBirth = new \DateTimeImmutable('-25 years'); $participant->transportationOutbound = $busService; $participant->parking = true; $travel = new Travel(); $bookingDto = new BookingDto($travel, 1); $bookingDto->participants = [$participant]; $submittedData = ['parking' => true]; $this->handler->processField($submittedData, $bookingDto, 0); $this->assertFalse($participant->parking); $this->assertNull($participant->parkingService); } public function testProcessFieldClearsParkingWhenParticipantIsUnder18(): void { $pkwService = $this->createTransportationService(DirectionMapper::SUBTYPE_CAR_API); // 17-year-old participant $participant = new ParticipantDto(); $participant->dateOfBirth = new \DateTimeImmutable('-17 years'); $participant->transportationOutbound = $pkwService; $participant->parking = true; $travel = new Travel(); $bookingDto = new BookingDto($travel, 1); $bookingDto->participants = [$participant]; $submittedData = ['parking' => true]; $this->handler->processField($submittedData, $bookingDto, 0); $this->assertFalse($participant->parking); $this->assertNull($participant->parkingService); } public function testProcessFieldClearsParkingWhenParticipantIsExactly17(): void { $pkwService = $this->createTransportationService(DirectionMapper::SUBTYPE_CAR_API); // Participant who is exactly 17 (just before 18th birthday) $participant = new ParticipantDto(); $participant->dateOfBirth = new \DateTimeImmutable('2007-06-15'); $participant->transportationOutbound = $pkwService; $participant->parking = true; $travel = new Travel(); $bookingDto = new BookingDto($travel, 1); $bookingDto->participants = [$participant]; // Assume today is 2024-06-14 (one day before 17th birthday would make them 16) // But since we use current date, we need to be careful with this test // Let's use a fixed approach - participant born 17 years ago today is exactly 17 $participant->dateOfBirth = (new \DateTimeImmutable())->modify('-17 years'); $submittedData = ['parking' => true]; $this->handler->processField($submittedData, $bookingDto, 0); $this->assertFalse($participant->parking); } public function testProcessFieldAllowsParkingForAdultWithPkw(): void { $pkwService = $this->createTransportationService(DirectionMapper::SUBTYPE_CAR_API); // 25-year-old participant $participant = new ParticipantDto(); $participant->dateOfBirth = new \DateTimeImmutable('-25 years'); $participant->transportationOutbound = $pkwService; $travel = new Travel(); $bookingDto = new BookingDto($travel, 1); $bookingDto->participants = [$participant]; $submittedData = ['parking' => '1']; $this->handler->processField($submittedData, $bookingDto, 0); $this->assertTrue($participant->parking); } public function testProcessFieldAllowsParkingForExactly18YearOld(): void { $pkwService = $this->createTransportationService(DirectionMapper::SUBTYPE_CAR_API); // Exactly 18 years old $participant = new ParticipantDto(); $participant->dateOfBirth = (new \DateTimeImmutable())->modify('-18 years'); $participant->transportationOutbound = $pkwService; $travel = new Travel(); $bookingDto = new BookingDto($travel, 1); $bookingDto->participants = [$participant]; $submittedData = ['parking' => true]; $this->handler->processField($submittedData, $bookingDto, 0); $this->assertTrue($participant->parking); } public function testProcessFieldClearsParkingWhenNoDateOfBirth(): void { $pkwService = $this->createTransportationService(DirectionMapper::SUBTYPE_CAR_API); $participant = new ParticipantDto(); $participant->dateOfBirth = null; // No date of birth $participant->transportationOutbound = $pkwService; $participant->parking = true; $travel = new Travel(); $bookingDto = new BookingDto($travel, 1); $bookingDto->participants = [$participant]; $submittedData = ['parking' => true]; $this->handler->processField($submittedData, $bookingDto, 0); $this->assertFalse($participant->parking); $this->assertNull($participant->parkingService); } public function testProcessFieldClearsParkingWhenBabyParticipant(): void { $pkwService = $this->createTransportationService(DirectionMapper::SUBTYPE_CAR_API); // Baby participant (1 year old) $participant = new ParticipantDto(); $participant->dateOfBirth = new \DateTimeImmutable('-1 year'); $participant->transportationOutbound = $pkwService; $participant->parking = true; $travel = new Travel(); $bookingDto = new BookingDto($travel, 1); $bookingDto->participants = [$participant]; $submittedData = ['parking' => true]; $this->handler->processField($submittedData, $bookingDto, 0); $this->assertFalse($participant->parking); $this->assertNull($participant->parkingService); } public function testProcessFieldClearsParkingForChildParticipant(): void { $pkwService = $this->createTransportationService(DirectionMapper::SUBTYPE_CAR_API); // 10-year-old child $participant = new ParticipantDto(); $participant->dateOfBirth = new \DateTimeImmutable('-10 years'); $participant->transportationOutbound = $pkwService; $participant->parking = true; $travel = new Travel(); $bookingDto = new BookingDto($travel, 1); $bookingDto->participants = [$participant]; $submittedData = ['parking' => true]; $this->handler->processField($submittedData, $bookingDto, 0); $this->assertFalse($participant->parking); } public function testProcessFieldSetsParkingToFalseWhenNotSelected(): void { $pkwService = $this->createTransportationService(DirectionMapper::SUBTYPE_CAR_API); $participant = new ParticipantDto(); $participant->dateOfBirth = new \DateTimeImmutable('-25 years'); $participant->transportationOutbound = $pkwService; $travel = new Travel(); $bookingDto = new BookingDto($travel, 1); $bookingDto->participants = [$participant]; $submittedData = ['parking' => false]; $this->handler->processField($submittedData, $bookingDto, 0); $this->assertFalse($participant->parking); $this->assertNull($participant->parkingService); } /** * @return array */ public static function normalizeCheckboxValueCheckedProvider(): array { return [ 'true' => [true], 'int 1' => [1], 'string 1' => ['1'], ]; } /** * @return array */ public static function normalizeCheckboxValueUncheckedProvider(): array { return [ 'false' => [false], 'int 0' => [0], 'string 0' => ['0'], 'empty string' => [''], 'null' => [null], 'non-numeric string' => ['off'], ]; } private function invokeNormalizeCheckboxValue(mixed $value): bool { $reflection = new \ReflectionMethod($this->handler, 'normalizeCheckboxValue'); return $reflection->invoke($this->handler, $value); } private function createTransportationService(string $subType): Service { $service = new Service(); $service->id = 100; $service->label = 'Test Transportation'; $service->subType = $subType; return $service; } }