Chris@0: Chris@0: * Chris@0: * For the full copyright and license information, please view the LICENSE Chris@0: * file that was distributed with this source code. Chris@0: */ Chris@0: Chris@0: namespace Symfony\Component\Validator\Test; Chris@0: Chris@0: use PHPUnit\Framework\Assert; Chris@0: use PHPUnit\Framework\TestCase; Chris@0: use Symfony\Component\Validator\Constraint; Chris@0: use Symfony\Component\Validator\Constraints\NotNull; Chris@0: use Symfony\Component\Validator\ConstraintValidatorInterface; Chris@0: use Symfony\Component\Validator\ConstraintViolation; Chris@0: use Symfony\Component\Validator\Context\ExecutionContext; Chris@0: use Symfony\Component\Validator\Context\ExecutionContextInterface; Chris@0: use Symfony\Component\Validator\Mapping\ClassMetadata; Chris@0: use Symfony\Component\Validator\Mapping\PropertyMetadata; Chris@0: Chris@0: /** Chris@0: * A test case to ease testing Constraint Validators. Chris@0: * Chris@0: * @author Bernhard Schussek Chris@0: */ Chris@0: abstract class ConstraintValidatorTestCase extends TestCase Chris@0: { Chris@18: use TestCaseSetUpTearDownTrait; Chris@18: Chris@0: /** Chris@0: * @var ExecutionContextInterface Chris@0: */ Chris@0: protected $context; Chris@0: Chris@0: /** Chris@0: * @var ConstraintValidatorInterface Chris@0: */ Chris@0: protected $validator; Chris@0: Chris@0: protected $group; Chris@0: protected $metadata; Chris@0: protected $object; Chris@0: protected $value; Chris@0: protected $root; Chris@0: protected $propertyPath; Chris@0: protected $constraint; Chris@0: protected $defaultTimezone; Chris@0: Chris@18: private function doSetUp() Chris@0: { Chris@0: $this->group = 'MyGroup'; Chris@0: $this->metadata = null; Chris@0: $this->object = null; Chris@0: $this->value = 'InvalidValue'; Chris@0: $this->root = 'root'; Chris@0: $this->propertyPath = 'property.path'; Chris@0: Chris@0: // Initialize the context with some constraint so that we can Chris@0: // successfully build a violation. Chris@0: $this->constraint = new NotNull(); Chris@0: Chris@0: $this->context = $this->createContext(); Chris@0: $this->validator = $this->createValidator(); Chris@0: $this->validator->initialize($this->context); Chris@0: Chris@0: \Locale::setDefault('en'); Chris@0: Chris@0: $this->setDefaultTimezone('UTC'); Chris@0: } Chris@0: Chris@18: private function doTearDown() Chris@0: { Chris@0: $this->restoreDefaultTimezone(); Chris@0: } Chris@0: Chris@0: protected function setDefaultTimezone($defaultTimezone) Chris@0: { Chris@0: // Make sure this method can not be called twice before calling Chris@0: // also restoreDefaultTimezone() Chris@0: if (null === $this->defaultTimezone) { Chris@0: $this->defaultTimezone = date_default_timezone_get(); Chris@0: date_default_timezone_set($defaultTimezone); Chris@0: } Chris@0: } Chris@0: Chris@0: protected function restoreDefaultTimezone() Chris@0: { Chris@0: if (null !== $this->defaultTimezone) { Chris@0: date_default_timezone_set($this->defaultTimezone); Chris@0: $this->defaultTimezone = null; Chris@0: } Chris@0: } Chris@0: Chris@0: protected function createContext() Chris@0: { Chris@0: $translator = $this->getMockBuilder('Symfony\Component\Translation\TranslatorInterface')->getMock(); Chris@0: $validator = $this->getMockBuilder('Symfony\Component\Validator\Validator\ValidatorInterface')->getMock(); Chris@0: $contextualValidator = $this->getMockBuilder('Symfony\Component\Validator\Validator\ContextualValidatorInterface')->getMock(); Chris@0: Chris@0: $context = new ExecutionContext($validator, $this->root, $translator); Chris@0: $context->setGroup($this->group); Chris@0: $context->setNode($this->value, $this->object, $this->metadata, $this->propertyPath); Chris@0: $context->setConstraint($this->constraint); Chris@0: Chris@0: $validator->expects($this->any()) Chris@0: ->method('inContext') Chris@0: ->with($context) Chris@0: ->will($this->returnValue($contextualValidator)); Chris@0: Chris@0: return $context; Chris@0: } Chris@0: Chris@0: protected function setGroup($group) Chris@0: { Chris@0: $this->group = $group; Chris@0: $this->context->setGroup($group); Chris@0: } Chris@0: Chris@0: protected function setObject($object) Chris@0: { Chris@0: $this->object = $object; Chris@17: $this->metadata = \is_object($object) Chris@17: ? new ClassMetadata(\get_class($object)) Chris@0: : null; Chris@0: Chris@0: $this->context->setNode($this->value, $this->object, $this->metadata, $this->propertyPath); Chris@0: } Chris@0: Chris@0: protected function setProperty($object, $property) Chris@0: { Chris@0: $this->object = $object; Chris@17: $this->metadata = \is_object($object) Chris@17: ? new PropertyMetadata(\get_class($object), $property) Chris@0: : null; Chris@0: Chris@0: $this->context->setNode($this->value, $this->object, $this->metadata, $this->propertyPath); Chris@0: } Chris@0: Chris@0: protected function setValue($value) Chris@0: { Chris@0: $this->value = $value; Chris@0: $this->context->setNode($this->value, $this->object, $this->metadata, $this->propertyPath); Chris@0: } Chris@0: Chris@0: protected function setRoot($root) Chris@0: { Chris@0: $this->root = $root; Chris@0: $this->context = $this->createContext(); Chris@0: $this->validator->initialize($this->context); Chris@0: } Chris@0: Chris@0: protected function setPropertyPath($propertyPath) Chris@0: { Chris@0: $this->propertyPath = $propertyPath; Chris@0: $this->context->setNode($this->value, $this->object, $this->metadata, $this->propertyPath); Chris@0: } Chris@0: Chris@0: protected function expectNoValidate() Chris@0: { Chris@0: $validator = $this->context->getValidator()->inContext($this->context); Chris@0: $validator->expects($this->never()) Chris@0: ->method('atPath'); Chris@0: $validator->expects($this->never()) Chris@0: ->method('validate'); Chris@0: } Chris@0: Chris@0: protected function expectValidateAt($i, $propertyPath, $value, $group) Chris@0: { Chris@0: $validator = $this->context->getValidator()->inContext($this->context); Chris@0: $validator->expects($this->at(2 * $i)) Chris@0: ->method('atPath') Chris@0: ->with($propertyPath) Chris@0: ->will($this->returnValue($validator)); Chris@0: $validator->expects($this->at(2 * $i + 1)) Chris@0: ->method('validate') Chris@17: ->with($value, $this->logicalOr(null, [], $this->isInstanceOf('\Symfony\Component\Validator\Constraints\Valid')), $group); Chris@0: } Chris@0: Chris@0: protected function expectValidateValueAt($i, $propertyPath, $value, $constraints, $group = null) Chris@0: { Chris@0: $contextualValidator = $this->context->getValidator()->inContext($this->context); Chris@0: $contextualValidator->expects($this->at(2 * $i)) Chris@0: ->method('atPath') Chris@0: ->with($propertyPath) Chris@0: ->will($this->returnValue($contextualValidator)); Chris@0: $contextualValidator->expects($this->at(2 * $i + 1)) Chris@0: ->method('validate') Chris@0: ->with($value, $constraints, $group); Chris@0: } Chris@0: Chris@0: protected function assertNoViolation() Chris@0: { Chris@17: $this->assertSame(0, $violationsCount = \count($this->context->getViolations()), sprintf('0 violation expected. Got %u.', $violationsCount)); Chris@0: } Chris@0: Chris@0: /** Chris@0: * @param $message Chris@0: * Chris@0: * @return ConstraintViolationAssertion Chris@0: */ Chris@0: protected function buildViolation($message) Chris@0: { Chris@0: return new ConstraintViolationAssertion($this->context, $message, $this->constraint); Chris@0: } Chris@0: Chris@0: abstract protected function createValidator(); Chris@0: } Chris@0: Chris@0: /** Chris@0: * @internal Chris@0: */ Chris@0: class ConstraintViolationAssertion Chris@0: { Chris@0: /** Chris@0: * @var ExecutionContextInterface Chris@0: */ Chris@0: private $context; Chris@0: Chris@0: /** Chris@0: * @var ConstraintViolationAssertion[] Chris@0: */ Chris@0: private $assertions; Chris@0: Chris@0: private $message; Chris@17: private $parameters = []; Chris@0: private $invalidValue = 'InvalidValue'; Chris@0: private $propertyPath = 'property.path'; Chris@0: private $plural; Chris@0: private $code; Chris@0: private $constraint; Chris@0: private $cause; Chris@0: Chris@17: public function __construct(ExecutionContextInterface $context, $message, Constraint $constraint = null, array $assertions = []) Chris@0: { Chris@0: $this->context = $context; Chris@0: $this->message = $message; Chris@0: $this->constraint = $constraint; Chris@0: $this->assertions = $assertions; Chris@0: } Chris@0: Chris@0: public function atPath($path) Chris@0: { Chris@0: $this->propertyPath = $path; Chris@0: Chris@0: return $this; Chris@0: } Chris@0: Chris@0: public function setParameter($key, $value) Chris@0: { Chris@0: $this->parameters[$key] = $value; Chris@0: Chris@0: return $this; Chris@0: } Chris@0: Chris@0: public function setParameters(array $parameters) Chris@0: { Chris@0: $this->parameters = $parameters; Chris@0: Chris@0: return $this; Chris@0: } Chris@0: Chris@0: public function setTranslationDomain($translationDomain) Chris@0: { Chris@14: // no-op for BC Chris@0: Chris@0: return $this; Chris@0: } Chris@0: Chris@0: public function setInvalidValue($invalidValue) Chris@0: { Chris@0: $this->invalidValue = $invalidValue; Chris@0: Chris@0: return $this; Chris@0: } Chris@0: Chris@0: public function setPlural($number) Chris@0: { Chris@0: $this->plural = $number; Chris@0: Chris@0: return $this; Chris@0: } Chris@0: Chris@0: public function setCode($code) Chris@0: { Chris@0: $this->code = $code; Chris@0: Chris@0: return $this; Chris@0: } Chris@0: Chris@0: public function setCause($cause) Chris@0: { Chris@0: $this->cause = $cause; Chris@0: Chris@0: return $this; Chris@0: } Chris@0: Chris@0: public function buildNextViolation($message) Chris@0: { Chris@0: $assertions = $this->assertions; Chris@0: $assertions[] = $this; Chris@0: Chris@0: return new self($this->context, $message, $this->constraint, $assertions); Chris@0: } Chris@0: Chris@0: public function assertRaised() Chris@0: { Chris@17: $expected = []; Chris@0: foreach ($this->assertions as $assertion) { Chris@0: $expected[] = $assertion->getViolation(); Chris@0: } Chris@0: $expected[] = $this->getViolation(); Chris@0: Chris@0: $violations = iterator_to_array($this->context->getViolations()); Chris@0: Chris@17: Assert::assertSame($expectedCount = \count($expected), $violationsCount = \count($violations), sprintf('%u violation(s) expected. Got %u.', $expectedCount, $violationsCount)); Chris@0: Chris@0: reset($violations); Chris@0: Chris@0: foreach ($expected as $violation) { Chris@0: Assert::assertEquals($violation, current($violations)); Chris@0: next($violations); Chris@0: } Chris@0: } Chris@0: Chris@0: private function getViolation() Chris@0: { Chris@0: return new ConstraintViolation( Chris@0: null, Chris@0: $this->message, Chris@0: $this->parameters, Chris@0: $this->context->getRoot(), Chris@0: $this->propertyPath, Chris@0: $this->invalidValue, Chris@0: $this->plural, Chris@0: $this->code, Chris@0: $this->constraint, Chris@0: $this->cause Chris@0: ); Chris@0: } Chris@0: }