087a90a1850d7f09d12e4befa4bb08074695c323
[yaffs-website] / validator / Test / ConstraintValidatorTestCase.php
1 <?php
2
3 /*
4  * This file is part of the Symfony package.
5  *
6  * (c) Fabien Potencier <fabien@symfony.com>
7  *
8  * For the full copyright and license information, please view the LICENSE
9  * file that was distributed with this source code.
10  */
11
12 namespace Symfony\Component\Validator\Test;
13
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;
24
25 /**
26  * A test case to ease testing Constraint Validators.
27  *
28  * @author Bernhard Schussek <bschussek@gmail.com>
29  */
30 abstract class ConstraintValidatorTestCase extends TestCase
31 {
32     /**
33      * @var ExecutionContextInterface
34      */
35     protected $context;
36
37     /**
38      * @var ConstraintValidatorInterface
39      */
40     protected $validator;
41
42     protected $group;
43     protected $metadata;
44     protected $object;
45     protected $value;
46     protected $root;
47     protected $propertyPath;
48     protected $constraint;
49     protected $defaultTimezone;
50
51     protected function setUp()
52     {
53         $this->group = 'MyGroup';
54         $this->metadata = null;
55         $this->object = null;
56         $this->value = 'InvalidValue';
57         $this->root = 'root';
58         $this->propertyPath = 'property.path';
59
60         // Initialize the context with some constraint so that we can
61         // successfully build a violation.
62         $this->constraint = new NotNull();
63
64         $this->context = $this->createContext();
65         $this->validator = $this->createValidator();
66         $this->validator->initialize($this->context);
67
68         \Locale::setDefault('en');
69
70         $this->setDefaultTimezone('UTC');
71     }
72
73     protected function tearDown()
74     {
75         $this->restoreDefaultTimezone();
76     }
77
78     protected function setDefaultTimezone($defaultTimezone)
79     {
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);
85         }
86     }
87
88     protected function restoreDefaultTimezone()
89     {
90         if (null !== $this->defaultTimezone) {
91             date_default_timezone_set($this->defaultTimezone);
92             $this->defaultTimezone = null;
93         }
94     }
95
96     protected function createContext()
97     {
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();
101
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);
106
107         $validator->expects($this->any())
108             ->method('inContext')
109             ->with($context)
110             ->will($this->returnValue($contextualValidator));
111
112         return $context;
113     }
114
115     protected function setGroup($group)
116     {
117         $this->group = $group;
118         $this->context->setGroup($group);
119     }
120
121     protected function setObject($object)
122     {
123         $this->object = $object;
124         $this->metadata = \is_object($object)
125             ? new ClassMetadata(\get_class($object))
126             : null;
127
128         $this->context->setNode($this->value, $this->object, $this->metadata, $this->propertyPath);
129     }
130
131     protected function setProperty($object, $property)
132     {
133         $this->object = $object;
134         $this->metadata = \is_object($object)
135             ? new PropertyMetadata(\get_class($object), $property)
136             : null;
137
138         $this->context->setNode($this->value, $this->object, $this->metadata, $this->propertyPath);
139     }
140
141     protected function setValue($value)
142     {
143         $this->value = $value;
144         $this->context->setNode($this->value, $this->object, $this->metadata, $this->propertyPath);
145     }
146
147     protected function setRoot($root)
148     {
149         $this->root = $root;
150         $this->context = $this->createContext();
151         $this->validator->initialize($this->context);
152     }
153
154     protected function setPropertyPath($propertyPath)
155     {
156         $this->propertyPath = $propertyPath;
157         $this->context->setNode($this->value, $this->object, $this->metadata, $this->propertyPath);
158     }
159
160     protected function expectNoValidate()
161     {
162         $validator = $this->context->getValidator()->inContext($this->context);
163         $validator->expects($this->never())
164             ->method('atPath');
165         $validator->expects($this->never())
166             ->method('validate');
167     }
168
169     protected function expectValidateAt($i, $propertyPath, $value, $group)
170     {
171         $validator = $this->context->getValidator()->inContext($this->context);
172         $validator->expects($this->at(2 * $i))
173             ->method('atPath')
174             ->with($propertyPath)
175             ->will($this->returnValue($validator));
176         $validator->expects($this->at(2 * $i + 1))
177             ->method('validate')
178             ->with($value, $this->logicalOr(null, array(), $this->isInstanceOf('\Symfony\Component\Validator\Constraints\Valid')), $group);
179     }
180
181     protected function expectValidateValueAt($i, $propertyPath, $value, $constraints, $group = null)
182     {
183         $contextualValidator = $this->context->getValidator()->inContext($this->context);
184         $contextualValidator->expects($this->at(2 * $i))
185             ->method('atPath')
186             ->with($propertyPath)
187             ->will($this->returnValue($contextualValidator));
188         $contextualValidator->expects($this->at(2 * $i + 1))
189             ->method('validate')
190             ->with($value, $constraints, $group);
191     }
192
193     protected function assertNoViolation()
194     {
195         $this->assertSame(0, $violationsCount = \count($this->context->getViolations()), sprintf('0 violation expected. Got %u.', $violationsCount));
196     }
197
198     /**
199      * @param $message
200      *
201      * @return ConstraintViolationAssertion
202      */
203     protected function buildViolation($message)
204     {
205         return new ConstraintViolationAssertion($this->context, $message, $this->constraint);
206     }
207
208     abstract protected function createValidator();
209 }
210
211 /**
212  * @internal
213  */
214 class ConstraintViolationAssertion
215 {
216     /**
217      * @var ExecutionContextInterface
218      */
219     private $context;
220
221     /**
222      * @var ConstraintViolationAssertion[]
223      */
224     private $assertions;
225
226     private $message;
227     private $parameters = array();
228     private $invalidValue = 'InvalidValue';
229     private $propertyPath = 'property.path';
230     private $plural;
231     private $code;
232     private $constraint;
233     private $cause;
234
235     public function __construct(ExecutionContextInterface $context, $message, Constraint $constraint = null, array $assertions = array())
236     {
237         $this->context = $context;
238         $this->message = $message;
239         $this->constraint = $constraint;
240         $this->assertions = $assertions;
241     }
242
243     public function atPath($path)
244     {
245         $this->propertyPath = $path;
246
247         return $this;
248     }
249
250     public function setParameter($key, $value)
251     {
252         $this->parameters[$key] = $value;
253
254         return $this;
255     }
256
257     public function setParameters(array $parameters)
258     {
259         $this->parameters = $parameters;
260
261         return $this;
262     }
263
264     public function setTranslationDomain($translationDomain)
265     {
266         // no-op for BC
267
268         return $this;
269     }
270
271     public function setInvalidValue($invalidValue)
272     {
273         $this->invalidValue = $invalidValue;
274
275         return $this;
276     }
277
278     public function setPlural($number)
279     {
280         $this->plural = $number;
281
282         return $this;
283     }
284
285     public function setCode($code)
286     {
287         $this->code = $code;
288
289         return $this;
290     }
291
292     public function setCause($cause)
293     {
294         $this->cause = $cause;
295
296         return $this;
297     }
298
299     public function buildNextViolation($message)
300     {
301         $assertions = $this->assertions;
302         $assertions[] = $this;
303
304         return new self($this->context, $message, $this->constraint, $assertions);
305     }
306
307     public function assertRaised()
308     {
309         $expected = array();
310         foreach ($this->assertions as $assertion) {
311             $expected[] = $assertion->getViolation();
312         }
313         $expected[] = $this->getViolation();
314
315         $violations = iterator_to_array($this->context->getViolations());
316
317         Assert::assertSame($expectedCount = \count($expected), $violationsCount = \count($violations), sprintf('%u violation(s) expected. Got %u.', $expectedCount, $violationsCount));
318
319         reset($violations);
320
321         foreach ($expected as $violation) {
322             Assert::assertEquals($violation, current($violations));
323             next($violations);
324         }
325     }
326
327     private function getViolation()
328     {
329         return new ConstraintViolation(
330             null,
331             $this->message,
332             $this->parameters,
333             $this->context->getRoot(),
334             $this->propertyPath,
335             $this->invalidValue,
336             $this->plural,
337             $this->code,
338             $this->constraint,
339             $this->cause
340         );
341     }
342 }