. */ namespace App\Tests\Validator\Constraints; use App\Entity\Base\AbstractDBElement; use App\Entity\Parts\Part; use App\Settings\MiscSettings\IpnSuggestSettings; use App\Validator\Constraints\UniquePartIpnConstraint; use App\Validator\Constraints\UniquePartIpnValidator; use Doctrine\ORM\EntityManagerInterface; use PHPUnit\Framework\MockObject\MockObject; use Symfony\Component\Validator\ConstraintValidatorInterface; use Symfony\Component\Validator\Test\ConstraintValidatorTestCase; final class UniquePartIpnValidatorTest extends ConstraintValidatorTestCase { private EntityManagerInterface&MockObject $em; private IpnSuggestSettings&MockObject $ipnSettings; protected function createValidator(): ConstraintValidatorInterface { $this->em = $this->createMock(EntityManagerInterface::class); // createMock() bypasses the ForbidConstructorTrait; public properties are accessible directly $this->ipnSettings = $this->createMock(IpnSuggestSettings::class); $this->ipnSettings->autoAppendSuffix = false; return new UniquePartIpnValidator($this->em, $this->ipnSettings); } public function testNullValueIsValid(): void { $this->validator->validate(null, new UniquePartIpnConstraint()); $this->assertNoViolation(); } public function testEmptyStringIsValid(): void { $this->validator->validate('', new UniquePartIpnConstraint()); $this->assertNoViolation(); } public function testAutoAppendSuffixSkipsValidation(): void { $this->ipnSettings->autoAppendSuffix = true; $this->validator->validate('IPN-001', new UniquePartIpnConstraint()); $this->assertNoViolation(); } public function testUniqueIpnIsValid(): void { $repo = $this->createMock(\Doctrine\ORM\EntityRepository::class); $repo->method('findBy')->willReturn([]); $this->em->method('getRepository')->willReturn($repo); $part = new Part(); $this->setObject($part); $this->validator->validate('UNIQUE-IPN', new UniquePartIpnConstraint()); $this->assertNoViolation(); } public function testDuplicateIpnRaisesViolation(): void { $existingPart = new Part(); $ref = new \ReflectionProperty(AbstractDBElement::class, 'id'); $ref->setValue($existingPart, 99); $repo = $this->createMock(\Doctrine\ORM\EntityRepository::class); $repo->method('findBy')->willReturn([$existingPart]); $this->em->method('getRepository')->willReturn($repo); // Validated part has no ID (new, unsaved part) $part = new Part(); $this->setObject($part); $constraint = new UniquePartIpnConstraint(); $this->validator->validate('DUPLICATE-IPN', $constraint); $this->buildViolation($constraint->message) ->setParameter('{{ value }}', 'DUPLICATE-IPN') ->assertRaised(); } }