4 * This file is part of the Symfony package.
6 * (c) Fabien Potencier <fabien@symfony.com>
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
12 namespace Symfony\Component\Validator\Test;
14 use PHPUnit\Framework\Assert;
15 use PHPUnit\Framework\TestCase;
16 use Symfony\Component\Validator\Constraint;
17 use Symfony\Component\Validator\Constraints\NotNull;
18 use Symfony\Component\Validator\ConstraintValidatorInterface;
19 use Symfony\Component\Validator\ConstraintViolation;
20 use Symfony\Component\Validator\Context\ExecutionContext;
21 use Symfony\Component\Validator\Context\ExecutionContextInterface;
22 use Symfony\Component\Validator\Mapping\ClassMetadata;
23 use Symfony\Component\Validator\Mapping\PropertyMetadata;
26 * A test case to ease testing Constraint Validators.
28 * @author Bernhard Schussek <bschussek@gmail.com>
30 abstract class ConstraintValidatorTestCase extends TestCase
33 * @var ExecutionContextInterface
38 * @var ConstraintValidatorInterface
47 protected $propertyPath;
48 protected $constraint;
49 protected $defaultTimezone;
51 protected function setUp()
53 $this->group = 'MyGroup';
54 $this->metadata = null;
56 $this->value = 'InvalidValue';
58 $this->propertyPath = 'property.path';
60 // Initialize the context with some constraint so that we can
61 // successfully build a violation.
62 $this->constraint = new NotNull();
64 $this->context = $this->createContext();
65 $this->validator = $this->createValidator();
66 $this->validator->initialize($this->context);
68 \Locale::setDefault('en');
70 $this->setDefaultTimezone('UTC');
73 protected function tearDown()
75 $this->restoreDefaultTimezone();
78 protected function setDefaultTimezone($defaultTimezone)
80 // Make sure this method can not be called twice before calling
81 // also restoreDefaultTimezone()
82 if (null === $this->defaultTimezone) {
83 $this->defaultTimezone = date_default_timezone_get();
84 date_default_timezone_set($defaultTimezone);
88 protected function restoreDefaultTimezone()
90 if (null !== $this->defaultTimezone) {
91 date_default_timezone_set($this->defaultTimezone);
92 $this->defaultTimezone = null;
96 protected function createContext()
98 $translator = $this->getMockBuilder('Symfony\Component\Translation\TranslatorInterface')->getMock();
99 $validator = $this->getMockBuilder('Symfony\Component\Validator\Validator\ValidatorInterface')->getMock();
100 $contextualValidator = $this->getMockBuilder('Symfony\Component\Validator\Validator\ContextualValidatorInterface')->getMock();
102 $context = new ExecutionContext($validator, $this->root, $translator);
103 $context->setGroup($this->group);
104 $context->setNode($this->value, $this->object, $this->metadata, $this->propertyPath);
105 $context->setConstraint($this->constraint);
107 $validator->expects($this->any())
108 ->method('inContext')
110 ->will($this->returnValue($contextualValidator));
115 protected function setGroup($group)
117 $this->group = $group;
118 $this->context->setGroup($group);
121 protected function setObject($object)
123 $this->object = $object;
124 $this->metadata = \is_object($object)
125 ? new ClassMetadata(\get_class($object))
128 $this->context->setNode($this->value, $this->object, $this->metadata, $this->propertyPath);
131 protected function setProperty($object, $property)
133 $this->object = $object;
134 $this->metadata = \is_object($object)
135 ? new PropertyMetadata(\get_class($object), $property)
138 $this->context->setNode($this->value, $this->object, $this->metadata, $this->propertyPath);
141 protected function setValue($value)
143 $this->value = $value;
144 $this->context->setNode($this->value, $this->object, $this->metadata, $this->propertyPath);
147 protected function setRoot($root)
150 $this->context = $this->createContext();
151 $this->validator->initialize($this->context);
154 protected function setPropertyPath($propertyPath)
156 $this->propertyPath = $propertyPath;
157 $this->context->setNode($this->value, $this->object, $this->metadata, $this->propertyPath);
160 protected function expectNoValidate()
162 $validator = $this->context->getValidator()->inContext($this->context);
163 $validator->expects($this->never())
165 $validator->expects($this->never())
166 ->method('validate');
169 protected function expectValidateAt($i, $propertyPath, $value, $group)
171 $validator = $this->context->getValidator()->inContext($this->context);
172 $validator->expects($this->at(2 * $i))
174 ->with($propertyPath)
175 ->will($this->returnValue($validator));
176 $validator->expects($this->at(2 * $i + 1))
178 ->with($value, $this->logicalOr(null, array(), $this->isInstanceOf('\Symfony\Component\Validator\Constraints\Valid')), $group);
181 protected function expectValidateValueAt($i, $propertyPath, $value, $constraints, $group = null)
183 $contextualValidator = $this->context->getValidator()->inContext($this->context);
184 $contextualValidator->expects($this->at(2 * $i))
186 ->with($propertyPath)
187 ->will($this->returnValue($contextualValidator));
188 $contextualValidator->expects($this->at(2 * $i + 1))
190 ->with($value, $constraints, $group);
193 protected function assertNoViolation()
195 $this->assertSame(0, $violationsCount = \count($this->context->getViolations()), sprintf('0 violation expected. Got %u.', $violationsCount));
201 * @return ConstraintViolationAssertion
203 protected function buildViolation($message)
205 return new ConstraintViolationAssertion($this->context, $message, $this->constraint);
208 abstract protected function createValidator();
214 class ConstraintViolationAssertion
217 * @var ExecutionContextInterface
222 * @var ConstraintViolationAssertion[]
227 private $parameters = array();
228 private $invalidValue = 'InvalidValue';
229 private $propertyPath = 'property.path';
235 public function __construct(ExecutionContextInterface $context, $message, Constraint $constraint = null, array $assertions = array())
237 $this->context = $context;
238 $this->message = $message;
239 $this->constraint = $constraint;
240 $this->assertions = $assertions;
243 public function atPath($path)
245 $this->propertyPath = $path;
250 public function setParameter($key, $value)
252 $this->parameters[$key] = $value;
257 public function setParameters(array $parameters)
259 $this->parameters = $parameters;
264 public function setTranslationDomain($translationDomain)
271 public function setInvalidValue($invalidValue)
273 $this->invalidValue = $invalidValue;
278 public function setPlural($number)
280 $this->plural = $number;
285 public function setCode($code)
292 public function setCause($cause)
294 $this->cause = $cause;
299 public function buildNextViolation($message)
301 $assertions = $this->assertions;
302 $assertions[] = $this;
304 return new self($this->context, $message, $this->constraint, $assertions);
307 public function assertRaised()
310 foreach ($this->assertions as $assertion) {
311 $expected[] = $assertion->getViolation();
313 $expected[] = $this->getViolation();
315 $violations = iterator_to_array($this->context->getViolations());
317 Assert::assertSame($expectedCount = \count($expected), $violationsCount = \count($violations), sprintf('%u violation(s) expected. Got %u.', $expectedCount, $violationsCount));
321 foreach ($expected as $violation) {
322 Assert::assertEquals($violation, current($violations));
327 private function getViolation()
329 return new ConstraintViolation(
333 $this->context->getRoot(),