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