130 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			130 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
 | 
						|
/*
 | 
						|
 * This file is part of the Symfony package.
 | 
						|
 *
 | 
						|
 * (c) Fabien Potencier <fabien@symfony.com>
 | 
						|
 *
 | 
						|
 * For the full copyright and license information, please view the LICENSE
 | 
						|
 * file that was distributed with this source code.
 | 
						|
 */
 | 
						|
 | 
						|
namespace Symfony\Component\Validator\Test;
 | 
						|
 | 
						|
use PHPUnit\Framework\ExpectationFailedException;
 | 
						|
use PHPUnit\Framework\TestCase;
 | 
						|
use Symfony\Component\Validator\Constraint;
 | 
						|
use Symfony\Component\Validator\Constraints\Compound;
 | 
						|
use Symfony\Component\Validator\Constraints\CompoundValidator;
 | 
						|
use Symfony\Component\Validator\ConstraintViolationListInterface;
 | 
						|
use Symfony\Component\Validator\Context\ExecutionContext;
 | 
						|
use Symfony\Component\Validator\Context\ExecutionContextInterface;
 | 
						|
use Symfony\Component\Validator\Validation;
 | 
						|
use Symfony\Component\Validator\Validator\ValidatorInterface;
 | 
						|
use Symfony\Contracts\Translation\TranslatorInterface;
 | 
						|
 | 
						|
/**
 | 
						|
 * A test case to ease testing Compound Constraints.
 | 
						|
 *
 | 
						|
 * @author Alexandre Daubois <alex.daubois@gmail.com>
 | 
						|
 *
 | 
						|
 * @template T of Compound
 | 
						|
 */
 | 
						|
abstract class CompoundConstraintTestCase extends TestCase
 | 
						|
{
 | 
						|
    protected ValidatorInterface $validator;
 | 
						|
    protected ?ConstraintViolationListInterface $violationList = null;
 | 
						|
    protected ExecutionContextInterface $context;
 | 
						|
    protected mixed $root;
 | 
						|
 | 
						|
    private mixed $validatedValue;
 | 
						|
 | 
						|
    protected function setUp(): void
 | 
						|
    {
 | 
						|
        $this->root = 'root';
 | 
						|
        $this->validator = $this->createValidator();
 | 
						|
        $this->context = $this->createContext($this->validator);
 | 
						|
    }
 | 
						|
 | 
						|
    protected function validateValue(mixed $value): void
 | 
						|
    {
 | 
						|
        $this->validator->inContext($this->context)->validate($this->validatedValue = $value, $this->createCompound());
 | 
						|
    }
 | 
						|
 | 
						|
    protected function createValidator(): ValidatorInterface
 | 
						|
    {
 | 
						|
        return Validation::createValidator();
 | 
						|
    }
 | 
						|
 | 
						|
    protected function createContext(?ValidatorInterface $validator = null): ExecutionContextInterface
 | 
						|
    {
 | 
						|
        $translator = $this->createMock(TranslatorInterface::class);
 | 
						|
        $translator->expects($this->any())->method('trans')->willReturnArgument(0);
 | 
						|
 | 
						|
        return new ExecutionContext($validator ?? $this->createValidator(), $this->root, $translator);
 | 
						|
    }
 | 
						|
 | 
						|
    public function assertViolationsRaisedByCompound(Constraint|array $constraints): void
 | 
						|
    {
 | 
						|
        if ($constraints instanceof Constraint) {
 | 
						|
            $constraints = [$constraints];
 | 
						|
        }
 | 
						|
 | 
						|
        $validator = new CompoundValidator();
 | 
						|
        $context = $this->createContext();
 | 
						|
        $validator->initialize($context);
 | 
						|
 | 
						|
        $validator->validate($this->validatedValue, new class($constraints) extends Compound {
 | 
						|
            public function __construct(private array $testedConstraints)
 | 
						|
            {
 | 
						|
                parent::__construct();
 | 
						|
            }
 | 
						|
 | 
						|
            protected function getConstraints(array $options): array
 | 
						|
            {
 | 
						|
                return $this->testedConstraints;
 | 
						|
            }
 | 
						|
        });
 | 
						|
 | 
						|
        $expectedViolations = iterator_to_array($context->getViolations());
 | 
						|
 | 
						|
        if (!$expectedViolations) {
 | 
						|
            throw new ExpectationFailedException(\sprintf('Expected at least one violation for constraint(s) "%s", got none raised.', implode(', ', array_map(fn ($constraint) => $constraint::class, $constraints))));
 | 
						|
        }
 | 
						|
 | 
						|
        $failedToAssertViolations = [];
 | 
						|
        reset($expectedViolations);
 | 
						|
        foreach ($this->context->getViolations() as $violation) {
 | 
						|
            if ($violation != current($expectedViolations)) {
 | 
						|
                $failedToAssertViolations[] = $violation;
 | 
						|
            }
 | 
						|
 | 
						|
            next($expectedViolations);
 | 
						|
        }
 | 
						|
 | 
						|
        $this->assertSame(
 | 
						|
            [],
 | 
						|
            $failedToAssertViolations,
 | 
						|
            \sprintf('Expected violation(s) for constraint(s) %s to be raised by compound.',
 | 
						|
                implode(', ', array_map(fn ($violation) => ($violation->getConstraint())::class, $failedToAssertViolations))
 | 
						|
            )
 | 
						|
        );
 | 
						|
    }
 | 
						|
 | 
						|
    public function assertViolationsCount(int $count): void
 | 
						|
    {
 | 
						|
        $this->assertCount($count, $this->context->getViolations());
 | 
						|
    }
 | 
						|
 | 
						|
    protected function assertNoViolation(): void
 | 
						|
    {
 | 
						|
        $violationsCount = \count($this->context->getViolations());
 | 
						|
        $this->assertSame(0, $violationsCount, \sprintf('No violation expected. Got %d.', $violationsCount));
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @return T
 | 
						|
     */
 | 
						|
    abstract protected function createCompound(): Compound;
 | 
						|
}
 |