handler = new ParticipantEmailFieldHandler(); } public function testGetFieldName(): void { $this->assertSame('email', $this->handler->getFieldName()); } public function testGetDependencies(): void { $this->assertSame([], $this->handler->getDependencies()); } public function testShouldProcessReturnsTrueWhenEmailFieldExists(): void { $this->assertTrue($this->handler->shouldProcess(['email' => 'test@example.com'], BookingDto::MODE_CREATE, 0)); $this->assertTrue($this->handler->shouldProcess(['email' => null], BookingDto::MODE_EDIT, 5)); } public function testShouldProcessReturnsFalseWhenEmailFieldMissing(): void { $this->assertFalse($this->handler->shouldProcess([], BookingDto::MODE_CREATE, 0)); $this->assertFalse($this->handler->shouldProcess(['firstName' => 'John'], BookingDto::MODE_EDIT, 5)); } public function testProcessFieldAdultsWithUniqueEmailsNoNotification(): void { $participant1 = $this->createAdultParticipant('adult1@example.com'); $participant2 = $this->createAdultParticipant('adult2@example.com'); $travel = new Travel(); $bookingDto = new BookingDto($travel, 1); $bookingDto->participants = [$participant1, $participant2]; $submittedData = ['email' => 'adult1@example.com']; $this->handler->processField($submittedData, $bookingDto, 0); $this->assertEmpty($participant1->notifications); } public function testProcessFieldAdultsWithDuplicateEmailsAddsWarningNotification(): void { $participant1 = $this->createAdultParticipant('duplicate@example.com'); $participant2 = $this->createAdultParticipant('duplicate@example.com'); $travel = new Travel(); $bookingDto = new BookingDto($travel, 1); $bookingDto->participants = [$participant1, $participant2]; $submittedData = ['email' => 'duplicate@example.com']; $this->handler->processField($submittedData, $bookingDto, 0); $this->assertCount(1, $participant1->notifications); $this->assertSame('warning', $participant1->notifications[0]['type']); $this->assertSame( 'Diese E-Mail Adresse wird bereits von einem anderen erwachsenen Teilnehmer verwendet', $participant1->notifications[0]['message'] ); } public function testProcessFieldAdultWithSameEmailAsChildNoNotification(): void { $adult = $this->createAdultParticipant('shared@example.com'); $child = $this->createChildParticipant('shared@example.com'); $travel = new Travel(); $bookingDto = new BookingDto($travel, 1); $bookingDto->participants = [$adult, $child]; $submittedData = ['email' => 'shared@example.com']; $this->handler->processField($submittedData, $bookingDto, 0); $this->assertEmpty($adult->notifications); } public function testProcessFieldChildWithDuplicateEmailNoNotification(): void { $child1 = $this->createChildParticipant('child@example.com'); $child2 = $this->createChildParticipant('child@example.com'); $travel = new Travel(); $bookingDto = new BookingDto($travel, 1); $bookingDto->participants = [$child1, $child2]; $submittedData = ['email' => 'child@example.com']; $this->handler->processField($submittedData, $bookingDto, 0); $this->assertEmpty($child1->notifications); } public function testProcessFieldChildWithSameEmailAsAdultNoNotification(): void { $adult = $this->createAdultParticipant('parent@example.com'); $child = $this->createChildParticipant('parent@example.com'); $travel = new Travel(); $bookingDto = new BookingDto($travel, 1); $bookingDto->participants = [$adult, $child]; $submittedData = ['email' => 'parent@example.com']; // Process child participant (index 1) $this->handler->processField($submittedData, $bookingDto, 1); $this->assertEmpty($child->notifications); } public function testProcessFieldThreeAdultsWithSameEmailAddsNotification(): void { $participant1 = $this->createAdultParticipant('same@example.com'); $participant2 = $this->createAdultParticipant('same@example.com'); $participant3 = $this->createAdultParticipant('same@example.com'); $travel = new Travel(); $bookingDto = new BookingDto($travel, 1); $bookingDto->participants = [$participant1, $participant2, $participant3]; $submittedData = ['email' => 'same@example.com']; $this->handler->processField($submittedData, $bookingDto, 0); $this->assertCount(1, $participant1->notifications); $this->assertSame('warning', $participant1->notifications[0]['type']); } public function testProcessFieldParticipantWithoutBirthDateTreatedAsAdult(): void { $participant1 = new ParticipantDto(); $participant1->dateOfBirth = null; // Unknown age - treated as adult $participant1->email = 'unknown@example.com'; $participant2 = $this->createAdultParticipant('unknown@example.com'); $travel = new Travel(); $bookingDto = new BookingDto($travel, 1); $bookingDto->participants = [$participant1, $participant2]; $submittedData = ['email' => 'unknown@example.com']; $this->handler->processField($submittedData, $bookingDto, 0); $this->assertCount(1, $participant1->notifications); $this->assertSame('warning', $participant1->notifications[0]['type']); } public function testProcessFieldNullEmailSkipsValidation(): void { $participant1 = $this->createAdultParticipant(null); $participant2 = $this->createAdultParticipant(null); $travel = new Travel(); $bookingDto = new BookingDto($travel, 1); $bookingDto->participants = [$participant1, $participant2]; $submittedData = ['email' => null]; $this->handler->processField($submittedData, $bookingDto, 0); $this->assertEmpty($participant1->notifications); } public function testProcessFieldEmptyEmailSkipsValidation(): void { $participant1 = $this->createAdultParticipant(''); $participant2 = $this->createAdultParticipant(''); $travel = new Travel(); $bookingDto = new BookingDto($travel, 1); $bookingDto->participants = [$participant1, $participant2]; $submittedData = ['email' => '']; $this->handler->processField($submittedData, $bookingDto, 0); $this->assertEmpty($participant1->notifications); } public function testProcessFieldWhitespaceOnlyEmailSkipsValidation(): void { $participant1 = $this->createAdultParticipant(' '); $participant2 = $this->createAdultParticipant(' '); $travel = new Travel(); $bookingDto = new BookingDto($travel, 1); $bookingDto->participants = [$participant1, $participant2]; $submittedData = ['email' => ' ']; $this->handler->processField($submittedData, $bookingDto, 0); $this->assertEmpty($participant1->notifications); } public function testProcessFieldCaseInsensitiveEmailComparison(): void { $participant1 = $this->createAdultParticipant('TEST@Example.COM'); $participant2 = $this->createAdultParticipant('test@example.com'); $travel = new Travel(); $bookingDto = new BookingDto($travel, 1); $bookingDto->participants = [$participant1, $participant2]; $submittedData = ['email' => 'TEST@Example.COM']; $this->handler->processField($submittedData, $bookingDto, 0); $this->assertCount(1, $participant1->notifications); $this->assertSame('warning', $participant1->notifications[0]['type']); } public function testProcessFieldWithoutParticipant(): void { $travel = new Travel(); $bookingDto = new BookingDto($travel, 1); $submittedData = ['email' => 'test@example.com']; $this->handler->processField($submittedData, $bookingDto, 0); // Should handle gracefully when participant doesn't exist $this->expectNotToPerformAssertions(); } public function testProcessFieldWithDifferentParticipantIndex(): void { $participant1 = $this->createAdultParticipant('user1@example.com'); $participant2 = $this->createAdultParticipant('duplicate@example.com'); $participant3 = $this->createAdultParticipant('duplicate@example.com'); $travel = new Travel(); $bookingDto = new BookingDto($travel, 1); $bookingDto->participants = [$participant1, $participant2, $participant3]; $submittedData = ['email' => 'duplicate@example.com']; // Process for participant at index 2 $this->handler->processField($submittedData, $bookingDto, 2); $this->assertEmpty($participant1->notifications); // Should not be affected $this->assertEmpty($participant2->notifications); // Should not be affected $this->assertCount(1, $participant3->notifications); // Should receive warning } private function createAdultParticipant(?string $email): ParticipantDto { $participant = new ParticipantDto(); $participant->dateOfBirth = new \DateTimeImmutable('1990-01-01'); // Adult (over 18) $participant->email = $email; return $participant; } private function createChildParticipant(?string $email): ParticipantDto { $participant = new ParticipantDto(); $participant->dateOfBirth = new \DateTimeImmutable('2015-01-01'); // Child (under 16) $participant->email = $email; return $participant; } }