Minor dependency updates
[yaffs-website] / vendor / symfony / validator / Tests / Validator / AbstractValidatorTest.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\Tests\Validator;
13
14 use PHPUnit\Framework\TestCase;
15 use Symfony\Component\Validator\Constraints\Callback;
16 use Symfony\Component\Validator\Constraints\GroupSequence;
17 use Symfony\Component\Validator\Constraints\Valid;
18 use Symfony\Component\Validator\ConstraintViolationInterface;
19 use Symfony\Component\Validator\ExecutionContextInterface;
20 use Symfony\Component\Validator\Mapping\ClassMetadata;
21 use Symfony\Component\Validator\Tests\Fixtures\Entity;
22 use Symfony\Component\Validator\Tests\Fixtures\FakeMetadataFactory;
23 use Symfony\Component\Validator\Tests\Fixtures\GroupSequenceProviderEntity;
24 use Symfony\Component\Validator\Tests\Fixtures\Reference;
25
26 /**
27  * @author Bernhard Schussek <bschussek@gmail.com>
28  */
29 abstract class AbstractValidatorTest extends TestCase
30 {
31     const ENTITY_CLASS = 'Symfony\Component\Validator\Tests\Fixtures\Entity';
32
33     const REFERENCE_CLASS = 'Symfony\Component\Validator\Tests\Fixtures\Reference';
34
35     /**
36      * @var FakeMetadataFactory
37      */
38     public $metadataFactory;
39
40     /**
41      * @var ClassMetadata
42      */
43     public $metadata;
44
45     /**
46      * @var ClassMetadata
47      */
48     public $referenceMetadata;
49
50     protected function setUp()
51     {
52         $this->metadataFactory = new FakeMetadataFactory();
53         $this->metadata = new ClassMetadata(self::ENTITY_CLASS);
54         $this->referenceMetadata = new ClassMetadata(self::REFERENCE_CLASS);
55         $this->metadataFactory->addMetadata($this->metadata);
56         $this->metadataFactory->addMetadata($this->referenceMetadata);
57     }
58
59     protected function tearDown()
60     {
61         $this->metadataFactory = null;
62         $this->metadata = null;
63         $this->referenceMetadata = null;
64     }
65
66     abstract protected function validate($value, $constraints = null, $groups = null);
67
68     abstract protected function validateProperty($object, $propertyName, $groups = null);
69
70     abstract protected function validatePropertyValue($object, $propertyName, $value, $groups = null);
71
72     public function testValidate()
73     {
74         $test = $this;
75
76         $callback = function ($value, ExecutionContextInterface $context) use ($test) {
77             $test->assertNull($context->getClassName());
78             $test->assertNull($context->getPropertyName());
79             $test->assertSame('', $context->getPropertyPath());
80             $test->assertSame('Group', $context->getGroup());
81             $test->assertSame('Bernhard', $context->getRoot());
82             $test->assertSame('Bernhard', $context->getValue());
83             $test->assertSame('Bernhard', $value);
84
85             $context->addViolation('Message %param%', array('%param%' => 'value'));
86         };
87
88         $constraint = new Callback(array(
89             'callback' => $callback,
90             'groups' => 'Group',
91         ));
92
93         $violations = $this->validate('Bernhard', $constraint, 'Group');
94
95         /* @var ConstraintViolationInterface[] $violations */
96         $this->assertCount(1, $violations);
97         $this->assertSame('Message value', $violations[0]->getMessage());
98         $this->assertSame('Message %param%', $violations[0]->getMessageTemplate());
99         $this->assertSame(array('%param%' => 'value'), $violations[0]->getParameters());
100         $this->assertSame('', $violations[0]->getPropertyPath());
101         $this->assertSame('Bernhard', $violations[0]->getRoot());
102         $this->assertSame('Bernhard', $violations[0]->getInvalidValue());
103         $this->assertNull($violations[0]->getPlural());
104         $this->assertNull($violations[0]->getCode());
105     }
106
107     public function testClassConstraint()
108     {
109         $test = $this;
110         $entity = new Entity();
111
112         $callback = function ($value, ExecutionContextInterface $context) use ($test, $entity) {
113             $test->assertSame($test::ENTITY_CLASS, $context->getClassName());
114             $test->assertNull($context->getPropertyName());
115             $test->assertSame('', $context->getPropertyPath());
116             $test->assertSame('Group', $context->getGroup());
117             $test->assertSame($test->metadata, $context->getMetadata());
118             $test->assertSame($entity, $context->getRoot());
119             $test->assertSame($entity, $context->getValue());
120             $test->assertSame($entity, $value);
121
122             $context->addViolation('Message %param%', array('%param%' => 'value'));
123         };
124
125         $this->metadata->addConstraint(new Callback(array(
126             'callback' => $callback,
127             'groups' => 'Group',
128         )));
129
130         $violations = $this->validate($entity, null, 'Group');
131
132         /* @var ConstraintViolationInterface[] $violations */
133         $this->assertCount(1, $violations);
134         $this->assertSame('Message value', $violations[0]->getMessage());
135         $this->assertSame('Message %param%', $violations[0]->getMessageTemplate());
136         $this->assertSame(array('%param%' => 'value'), $violations[0]->getParameters());
137         $this->assertSame('', $violations[0]->getPropertyPath());
138         $this->assertSame($entity, $violations[0]->getRoot());
139         $this->assertSame($entity, $violations[0]->getInvalidValue());
140         $this->assertNull($violations[0]->getPlural());
141         $this->assertNull($violations[0]->getCode());
142     }
143
144     public function testPropertyConstraint()
145     {
146         $test = $this;
147         $entity = new Entity();
148         $entity->firstName = 'Bernhard';
149
150         $callback = function ($value, ExecutionContextInterface $context) use ($test, $entity) {
151             $propertyMetadatas = $test->metadata->getPropertyMetadata('firstName');
152
153             $test->assertSame($test::ENTITY_CLASS, $context->getClassName());
154             $test->assertSame('firstName', $context->getPropertyName());
155             $test->assertSame('firstName', $context->getPropertyPath());
156             $test->assertSame('Group', $context->getGroup());
157             $test->assertSame($propertyMetadatas[0], $context->getMetadata());
158             $test->assertSame($entity, $context->getRoot());
159             $test->assertSame('Bernhard', $context->getValue());
160             $test->assertSame('Bernhard', $value);
161
162             $context->addViolation('Message %param%', array('%param%' => 'value'));
163         };
164
165         $this->metadata->addPropertyConstraint('firstName', new Callback(array(
166             'callback' => $callback,
167             'groups' => 'Group',
168         )));
169
170         $violations = $this->validate($entity, null, 'Group');
171
172         /* @var ConstraintViolationInterface[] $violations */
173         $this->assertCount(1, $violations);
174         $this->assertSame('Message value', $violations[0]->getMessage());
175         $this->assertSame('Message %param%', $violations[0]->getMessageTemplate());
176         $this->assertSame(array('%param%' => 'value'), $violations[0]->getParameters());
177         $this->assertSame('firstName', $violations[0]->getPropertyPath());
178         $this->assertSame($entity, $violations[0]->getRoot());
179         $this->assertSame('Bernhard', $violations[0]->getInvalidValue());
180         $this->assertNull($violations[0]->getPlural());
181         $this->assertNull($violations[0]->getCode());
182     }
183
184     public function testGetterConstraint()
185     {
186         $test = $this;
187         $entity = new Entity();
188         $entity->setLastName('Schussek');
189
190         $callback = function ($value, ExecutionContextInterface $context) use ($test, $entity) {
191             $propertyMetadatas = $test->metadata->getPropertyMetadata('lastName');
192
193             $test->assertSame($test::ENTITY_CLASS, $context->getClassName());
194             $test->assertSame('lastName', $context->getPropertyName());
195             $test->assertSame('lastName', $context->getPropertyPath());
196             $test->assertSame('Group', $context->getGroup());
197             $test->assertSame($propertyMetadatas[0], $context->getMetadata());
198             $test->assertSame($entity, $context->getRoot());
199             $test->assertSame('Schussek', $context->getValue());
200             $test->assertSame('Schussek', $value);
201
202             $context->addViolation('Message %param%', array('%param%' => 'value'));
203         };
204
205         $this->metadata->addGetterConstraint('lastName', new Callback(array(
206             'callback' => $callback,
207             'groups' => 'Group',
208         )));
209
210         $violations = $this->validate($entity, null, 'Group');
211
212         /* @var ConstraintViolationInterface[] $violations */
213         $this->assertCount(1, $violations);
214         $this->assertSame('Message value', $violations[0]->getMessage());
215         $this->assertSame('Message %param%', $violations[0]->getMessageTemplate());
216         $this->assertSame(array('%param%' => 'value'), $violations[0]->getParameters());
217         $this->assertSame('lastName', $violations[0]->getPropertyPath());
218         $this->assertSame($entity, $violations[0]->getRoot());
219         $this->assertSame('Schussek', $violations[0]->getInvalidValue());
220         $this->assertNull($violations[0]->getPlural());
221         $this->assertNull($violations[0]->getCode());
222     }
223
224     public function testArray()
225     {
226         $test = $this;
227         $entity = new Entity();
228         $array = array('key' => $entity);
229
230         $callback = function ($value, ExecutionContextInterface $context) use ($test, $entity, $array) {
231             $test->assertSame($test::ENTITY_CLASS, $context->getClassName());
232             $test->assertNull($context->getPropertyName());
233             $test->assertSame('[key]', $context->getPropertyPath());
234             $test->assertSame('Group', $context->getGroup());
235             $test->assertSame($test->metadata, $context->getMetadata());
236             $test->assertSame($array, $context->getRoot());
237             $test->assertSame($entity, $context->getValue());
238             $test->assertSame($entity, $value);
239
240             $context->addViolation('Message %param%', array('%param%' => 'value'));
241         };
242
243         $this->metadata->addConstraint(new Callback(array(
244             'callback' => $callback,
245             'groups' => 'Group',
246         )));
247
248         $violations = $this->validate($array, null, 'Group');
249
250         /* @var ConstraintViolationInterface[] $violations */
251         $this->assertCount(1, $violations);
252         $this->assertSame('Message value', $violations[0]->getMessage());
253         $this->assertSame('Message %param%', $violations[0]->getMessageTemplate());
254         $this->assertSame(array('%param%' => 'value'), $violations[0]->getParameters());
255         $this->assertSame('[key]', $violations[0]->getPropertyPath());
256         $this->assertSame($array, $violations[0]->getRoot());
257         $this->assertSame($entity, $violations[0]->getInvalidValue());
258         $this->assertNull($violations[0]->getPlural());
259         $this->assertNull($violations[0]->getCode());
260     }
261
262     public function testRecursiveArray()
263     {
264         $test = $this;
265         $entity = new Entity();
266         $array = array(2 => array('key' => $entity));
267
268         $callback = function ($value, ExecutionContextInterface $context) use ($test, $entity, $array) {
269             $test->assertSame($test::ENTITY_CLASS, $context->getClassName());
270             $test->assertNull($context->getPropertyName());
271             $test->assertSame('[2][key]', $context->getPropertyPath());
272             $test->assertSame('Group', $context->getGroup());
273             $test->assertSame($test->metadata, $context->getMetadata());
274             $test->assertSame($array, $context->getRoot());
275             $test->assertSame($entity, $context->getValue());
276             $test->assertSame($entity, $value);
277
278             $context->addViolation('Message %param%', array('%param%' => 'value'));
279         };
280
281         $this->metadata->addConstraint(new Callback(array(
282             'callback' => $callback,
283             'groups' => 'Group',
284         )));
285
286         $violations = $this->validate($array, null, 'Group');
287
288         /* @var ConstraintViolationInterface[] $violations */
289         $this->assertCount(1, $violations);
290         $this->assertSame('Message value', $violations[0]->getMessage());
291         $this->assertSame('Message %param%', $violations[0]->getMessageTemplate());
292         $this->assertSame(array('%param%' => 'value'), $violations[0]->getParameters());
293         $this->assertSame('[2][key]', $violations[0]->getPropertyPath());
294         $this->assertSame($array, $violations[0]->getRoot());
295         $this->assertSame($entity, $violations[0]->getInvalidValue());
296         $this->assertNull($violations[0]->getPlural());
297         $this->assertNull($violations[0]->getCode());
298     }
299
300     public function testTraversable()
301     {
302         $test = $this;
303         $entity = new Entity();
304         $traversable = new \ArrayIterator(array('key' => $entity));
305
306         $callback = function ($value, ExecutionContextInterface $context) use ($test, $entity, $traversable) {
307             $test->assertSame($test::ENTITY_CLASS, $context->getClassName());
308             $test->assertNull($context->getPropertyName());
309             $test->assertSame('[key]', $context->getPropertyPath());
310             $test->assertSame('Group', $context->getGroup());
311             $test->assertSame($test->metadata, $context->getMetadata());
312             $test->assertSame($traversable, $context->getRoot());
313             $test->assertSame($entity, $context->getValue());
314             $test->assertSame($entity, $value);
315
316             $context->addViolation('Message %param%', array('%param%' => 'value'));
317         };
318
319         $this->metadata->addConstraint(new Callback(array(
320             'callback' => $callback,
321             'groups' => 'Group',
322         )));
323
324         $violations = $this->validate($traversable, null, 'Group');
325
326         /* @var ConstraintViolationInterface[] $violations */
327         $this->assertCount(1, $violations);
328         $this->assertSame('Message value', $violations[0]->getMessage());
329         $this->assertSame('Message %param%', $violations[0]->getMessageTemplate());
330         $this->assertSame(array('%param%' => 'value'), $violations[0]->getParameters());
331         $this->assertSame('[key]', $violations[0]->getPropertyPath());
332         $this->assertSame($traversable, $violations[0]->getRoot());
333         $this->assertSame($entity, $violations[0]->getInvalidValue());
334         $this->assertNull($violations[0]->getPlural());
335         $this->assertNull($violations[0]->getCode());
336     }
337
338     public function testRecursiveTraversable()
339     {
340         $test = $this;
341         $entity = new Entity();
342         $traversable = new \ArrayIterator(array(
343             2 => new \ArrayIterator(array('key' => $entity)),
344         ));
345
346         $callback = function ($value, ExecutionContextInterface $context) use ($test, $entity, $traversable) {
347             $test->assertSame($test::ENTITY_CLASS, $context->getClassName());
348             $test->assertNull($context->getPropertyName());
349             $test->assertSame('[2][key]', $context->getPropertyPath());
350             $test->assertSame('Group', $context->getGroup());
351             $test->assertSame($test->metadata, $context->getMetadata());
352             $test->assertSame($traversable, $context->getRoot());
353             $test->assertSame($entity, $context->getValue());
354             $test->assertSame($entity, $value);
355
356             $context->addViolation('Message %param%', array('%param%' => 'value'));
357         };
358
359         $this->metadata->addConstraint(new Callback(array(
360             'callback' => $callback,
361             'groups' => 'Group',
362         )));
363
364         $violations = $this->validate($traversable, null, 'Group');
365
366         /* @var ConstraintViolationInterface[] $violations */
367         $this->assertCount(1, $violations);
368         $this->assertSame('Message value', $violations[0]->getMessage());
369         $this->assertSame('Message %param%', $violations[0]->getMessageTemplate());
370         $this->assertSame(array('%param%' => 'value'), $violations[0]->getParameters());
371         $this->assertSame('[2][key]', $violations[0]->getPropertyPath());
372         $this->assertSame($traversable, $violations[0]->getRoot());
373         $this->assertSame($entity, $violations[0]->getInvalidValue());
374         $this->assertNull($violations[0]->getPlural());
375         $this->assertNull($violations[0]->getCode());
376     }
377
378     public function testReferenceClassConstraint()
379     {
380         $test = $this;
381         $entity = new Entity();
382         $entity->reference = new Reference();
383
384         $callback = function ($value, ExecutionContextInterface $context) use ($test, $entity) {
385             $test->assertSame($test::REFERENCE_CLASS, $context->getClassName());
386             $test->assertNull($context->getPropertyName());
387             $test->assertSame('reference', $context->getPropertyPath());
388             $test->assertSame('Group', $context->getGroup());
389             $test->assertSame($test->referenceMetadata, $context->getMetadata());
390             $test->assertSame($entity, $context->getRoot());
391             $test->assertSame($entity->reference, $context->getValue());
392             $test->assertSame($entity->reference, $value);
393
394             $context->addViolation('Message %param%', array('%param%' => 'value'));
395         };
396
397         $this->metadata->addPropertyConstraint('reference', new Valid());
398         $this->referenceMetadata->addConstraint(new Callback(array(
399             'callback' => $callback,
400             'groups' => 'Group',
401         )));
402
403         $violations = $this->validate($entity, null, 'Group');
404
405         /* @var ConstraintViolationInterface[] $violations */
406         $this->assertCount(1, $violations);
407         $this->assertSame('Message value', $violations[0]->getMessage());
408         $this->assertSame('Message %param%', $violations[0]->getMessageTemplate());
409         $this->assertSame(array('%param%' => 'value'), $violations[0]->getParameters());
410         $this->assertSame('reference', $violations[0]->getPropertyPath());
411         $this->assertSame($entity, $violations[0]->getRoot());
412         $this->assertSame($entity->reference, $violations[0]->getInvalidValue());
413         $this->assertNull($violations[0]->getPlural());
414         $this->assertNull($violations[0]->getCode());
415     }
416
417     public function testReferencePropertyConstraint()
418     {
419         $test = $this;
420         $entity = new Entity();
421         $entity->reference = new Reference();
422         $entity->reference->value = 'Foobar';
423
424         $callback = function ($value, ExecutionContextInterface $context) use ($test, $entity) {
425             $propertyMetadatas = $test->referenceMetadata->getPropertyMetadata('value');
426
427             $test->assertSame($test::REFERENCE_CLASS, $context->getClassName());
428             $test->assertSame('value', $context->getPropertyName());
429             $test->assertSame('reference.value', $context->getPropertyPath());
430             $test->assertSame('Group', $context->getGroup());
431             $test->assertSame($propertyMetadatas[0], $context->getMetadata());
432             $test->assertSame($entity, $context->getRoot());
433             $test->assertSame('Foobar', $context->getValue());
434             $test->assertSame('Foobar', $value);
435
436             $context->addViolation('Message %param%', array('%param%' => 'value'));
437         };
438
439         $this->metadata->addPropertyConstraint('reference', new Valid());
440         $this->referenceMetadata->addPropertyConstraint('value', new Callback(array(
441             'callback' => $callback,
442             'groups' => 'Group',
443         )));
444
445         $violations = $this->validate($entity, null, 'Group');
446
447         /* @var ConstraintViolationInterface[] $violations */
448         $this->assertCount(1, $violations);
449         $this->assertSame('Message value', $violations[0]->getMessage());
450         $this->assertSame('Message %param%', $violations[0]->getMessageTemplate());
451         $this->assertSame(array('%param%' => 'value'), $violations[0]->getParameters());
452         $this->assertSame('reference.value', $violations[0]->getPropertyPath());
453         $this->assertSame($entity, $violations[0]->getRoot());
454         $this->assertSame('Foobar', $violations[0]->getInvalidValue());
455         $this->assertNull($violations[0]->getPlural());
456         $this->assertNull($violations[0]->getCode());
457     }
458
459     public function testReferenceGetterConstraint()
460     {
461         $test = $this;
462         $entity = new Entity();
463         $entity->reference = new Reference();
464         $entity->reference->setPrivateValue('Bamboo');
465
466         $callback = function ($value, ExecutionContextInterface $context) use ($test, $entity) {
467             $propertyMetadatas = $test->referenceMetadata->getPropertyMetadata('privateValue');
468
469             $test->assertSame($test::REFERENCE_CLASS, $context->getClassName());
470             $test->assertSame('privateValue', $context->getPropertyName());
471             $test->assertSame('reference.privateValue', $context->getPropertyPath());
472             $test->assertSame('Group', $context->getGroup());
473             $test->assertSame($propertyMetadatas[0], $context->getMetadata());
474             $test->assertSame($entity, $context->getRoot());
475             $test->assertSame('Bamboo', $context->getValue());
476             $test->assertSame('Bamboo', $value);
477
478             $context->addViolation('Message %param%', array('%param%' => 'value'));
479         };
480
481         $this->metadata->addPropertyConstraint('reference', new Valid());
482         $this->referenceMetadata->addPropertyConstraint('privateValue', new Callback(array(
483             'callback' => $callback,
484             'groups' => 'Group',
485         )));
486
487         $violations = $this->validate($entity, null, 'Group');
488
489         /* @var ConstraintViolationInterface[] $violations */
490         $this->assertCount(1, $violations);
491         $this->assertSame('Message value', $violations[0]->getMessage());
492         $this->assertSame('Message %param%', $violations[0]->getMessageTemplate());
493         $this->assertSame(array('%param%' => 'value'), $violations[0]->getParameters());
494         $this->assertSame('reference.privateValue', $violations[0]->getPropertyPath());
495         $this->assertSame($entity, $violations[0]->getRoot());
496         $this->assertSame('Bamboo', $violations[0]->getInvalidValue());
497         $this->assertNull($violations[0]->getPlural());
498         $this->assertNull($violations[0]->getCode());
499     }
500
501     public function testsIgnoreNullReference()
502     {
503         $entity = new Entity();
504         $entity->reference = null;
505
506         $this->metadata->addPropertyConstraint('reference', new Valid());
507
508         $violations = $this->validate($entity);
509
510         /* @var ConstraintViolationInterface[] $violations */
511         $this->assertCount(0, $violations);
512     }
513
514     /**
515      * @expectedException \Symfony\Component\Validator\Exception\NoSuchMetadataException
516      */
517     public function testFailOnScalarReferences()
518     {
519         $entity = new Entity();
520         $entity->reference = 'string';
521
522         $this->metadata->addPropertyConstraint('reference', new Valid());
523
524         $this->validate($entity);
525     }
526
527     public function testArrayReference()
528     {
529         $test = $this;
530         $entity = new Entity();
531         $entity->reference = array('key' => new Reference());
532
533         $callback = function ($value, ExecutionContextInterface $context) use ($test, $entity) {
534             $test->assertSame($test::REFERENCE_CLASS, $context->getClassName());
535             $test->assertNull($context->getPropertyName());
536             $test->assertSame('reference[key]', $context->getPropertyPath());
537             $test->assertSame('Group', $context->getGroup());
538             $test->assertSame($test->referenceMetadata, $context->getMetadata());
539             $test->assertSame($entity, $context->getRoot());
540             $test->assertSame($entity->reference['key'], $context->getValue());
541             $test->assertSame($entity->reference['key'], $value);
542
543             $context->addViolation('Message %param%', array('%param%' => 'value'));
544         };
545
546         $this->metadata->addPropertyConstraint('reference', new Valid());
547         $this->referenceMetadata->addConstraint(new Callback(array(
548             'callback' => $callback,
549             'groups' => 'Group',
550         )));
551
552         $violations = $this->validate($entity, null, 'Group');
553
554         /* @var ConstraintViolationInterface[] $violations */
555         $this->assertCount(1, $violations);
556         $this->assertSame('Message value', $violations[0]->getMessage());
557         $this->assertSame('Message %param%', $violations[0]->getMessageTemplate());
558         $this->assertSame(array('%param%' => 'value'), $violations[0]->getParameters());
559         $this->assertSame('reference[key]', $violations[0]->getPropertyPath());
560         $this->assertSame($entity, $violations[0]->getRoot());
561         $this->assertSame($entity->reference['key'], $violations[0]->getInvalidValue());
562         $this->assertNull($violations[0]->getPlural());
563         $this->assertNull($violations[0]->getCode());
564     }
565
566     // https://github.com/symfony/symfony/issues/6246
567     public function testRecursiveArrayReference()
568     {
569         $test = $this;
570         $entity = new Entity();
571         $entity->reference = array(2 => array('key' => new Reference()));
572
573         $callback = function ($value, ExecutionContextInterface $context) use ($test, $entity) {
574             $test->assertSame($test::REFERENCE_CLASS, $context->getClassName());
575             $test->assertNull($context->getPropertyName());
576             $test->assertSame('reference[2][key]', $context->getPropertyPath());
577             $test->assertSame('Group', $context->getGroup());
578             $test->assertSame($test->referenceMetadata, $context->getMetadata());
579             $test->assertSame($entity, $context->getRoot());
580             $test->assertSame($entity->reference[2]['key'], $context->getValue());
581             $test->assertSame($entity->reference[2]['key'], $value);
582
583             $context->addViolation('Message %param%', array('%param%' => 'value'));
584         };
585
586         $this->metadata->addPropertyConstraint('reference', new Valid());
587         $this->referenceMetadata->addConstraint(new Callback(array(
588             'callback' => $callback,
589             'groups' => 'Group',
590         )));
591
592         $violations = $this->validate($entity, null, 'Group');
593
594         /* @var ConstraintViolationInterface[] $violations */
595         $this->assertCount(1, $violations);
596         $this->assertSame('Message value', $violations[0]->getMessage());
597         $this->assertSame('Message %param%', $violations[0]->getMessageTemplate());
598         $this->assertSame(array('%param%' => 'value'), $violations[0]->getParameters());
599         $this->assertSame('reference[2][key]', $violations[0]->getPropertyPath());
600         $this->assertSame($entity, $violations[0]->getRoot());
601         $this->assertSame($entity->reference[2]['key'], $violations[0]->getInvalidValue());
602         $this->assertNull($violations[0]->getPlural());
603         $this->assertNull($violations[0]->getCode());
604     }
605
606     public function testArrayTraversalCannotBeDisabled()
607     {
608         $entity = new Entity();
609         $entity->reference = array('key' => new Reference());
610
611         $callback = function ($value, ExecutionContextInterface $context) {
612             $context->addViolation('Message %param%', array('%param%' => 'value'));
613         };
614
615         $this->metadata->addPropertyConstraint('reference', new Valid(array(
616             'traverse' => false,
617         )));
618         $this->referenceMetadata->addConstraint(new Callback($callback));
619
620         $violations = $this->validate($entity);
621
622         /* @var ConstraintViolationInterface[] $violations */
623         $this->assertCount(1, $violations);
624     }
625
626     public function testRecursiveArrayTraversalCannotBeDisabled()
627     {
628         $entity = new Entity();
629         $entity->reference = array(2 => array('key' => new Reference()));
630
631         $callback = function ($value, ExecutionContextInterface $context) {
632             $context->addViolation('Message %param%', array('%param%' => 'value'));
633         };
634
635         $this->metadata->addPropertyConstraint('reference', new Valid(array(
636             'traverse' => false,
637         )));
638         $this->referenceMetadata->addConstraint(new Callback($callback));
639
640         $violations = $this->validate($entity);
641
642         /* @var ConstraintViolationInterface[] $violations */
643         $this->assertCount(1, $violations);
644     }
645
646     public function testIgnoreScalarsDuringArrayTraversal()
647     {
648         $entity = new Entity();
649         $entity->reference = array('string', 1234);
650
651         $this->metadata->addPropertyConstraint('reference', new Valid());
652
653         $violations = $this->validate($entity);
654
655         /* @var ConstraintViolationInterface[] $violations */
656         $this->assertCount(0, $violations);
657     }
658
659     public function testIgnoreNullDuringArrayTraversal()
660     {
661         $entity = new Entity();
662         $entity->reference = array(null);
663
664         $this->metadata->addPropertyConstraint('reference', new Valid());
665
666         $violations = $this->validate($entity);
667
668         /* @var ConstraintViolationInterface[] $violations */
669         $this->assertCount(0, $violations);
670     }
671
672     public function testTraversableReference()
673     {
674         $test = $this;
675         $entity = new Entity();
676         $entity->reference = new \ArrayIterator(array('key' => new Reference()));
677
678         $callback = function ($value, ExecutionContextInterface $context) use ($test, $entity) {
679             $test->assertSame($test::REFERENCE_CLASS, $context->getClassName());
680             $test->assertNull($context->getPropertyName());
681             $test->assertSame('reference[key]', $context->getPropertyPath());
682             $test->assertSame('Group', $context->getGroup());
683             $test->assertSame($test->referenceMetadata, $context->getMetadata());
684             $test->assertSame($entity, $context->getRoot());
685             $test->assertSame($entity->reference['key'], $context->getValue());
686             $test->assertSame($entity->reference['key'], $value);
687
688             $context->addViolation('Message %param%', array('%param%' => 'value'));
689         };
690
691         $this->metadata->addPropertyConstraint('reference', new Valid());
692         $this->referenceMetadata->addConstraint(new Callback(array(
693             'callback' => $callback,
694             'groups' => 'Group',
695         )));
696
697         $violations = $this->validate($entity, null, 'Group');
698
699         /* @var ConstraintViolationInterface[] $violations */
700         $this->assertCount(1, $violations);
701         $this->assertSame('Message value', $violations[0]->getMessage());
702         $this->assertSame('Message %param%', $violations[0]->getMessageTemplate());
703         $this->assertSame(array('%param%' => 'value'), $violations[0]->getParameters());
704         $this->assertSame('reference[key]', $violations[0]->getPropertyPath());
705         $this->assertSame($entity, $violations[0]->getRoot());
706         $this->assertSame($entity->reference['key'], $violations[0]->getInvalidValue());
707         $this->assertNull($violations[0]->getPlural());
708         $this->assertNull($violations[0]->getCode());
709     }
710
711     public function testDisableTraversableTraversal()
712     {
713         $entity = new Entity();
714         $entity->reference = new \ArrayIterator(array('key' => new Reference()));
715
716         $callback = function ($value, ExecutionContextInterface $context) {
717             $context->addViolation('Message %param%', array('%param%' => 'value'));
718         };
719
720         $this->metadataFactory->addMetadata(new ClassMetadata('ArrayIterator'));
721         $this->metadata->addPropertyConstraint('reference', new Valid(array(
722             'traverse' => false,
723         )));
724         $this->referenceMetadata->addConstraint(new Callback($callback));
725
726         $violations = $this->validate($entity);
727
728         /* @var ConstraintViolationInterface[] $violations */
729         $this->assertCount(0, $violations);
730     }
731
732     /**
733      * @expectedException \Symfony\Component\Validator\Exception\NoSuchMetadataException
734      */
735     public function testMetadataMustExistIfTraversalIsDisabled()
736     {
737         $entity = new Entity();
738         $entity->reference = new \ArrayIterator();
739
740         $this->metadata->addPropertyConstraint('reference', new Valid(array(
741             'traverse' => false,
742         )));
743
744         $this->validate($entity);
745     }
746
747     public function testEnableRecursiveTraversableTraversal()
748     {
749         $test = $this;
750         $entity = new Entity();
751         $entity->reference = new \ArrayIterator(array(
752             2 => new \ArrayIterator(array('key' => new Reference())),
753         ));
754
755         $callback = function ($value, ExecutionContextInterface $context) use ($test, $entity) {
756             $test->assertSame($test::REFERENCE_CLASS, $context->getClassName());
757             $test->assertNull($context->getPropertyName());
758             $test->assertSame('reference[2][key]', $context->getPropertyPath());
759             $test->assertSame('Group', $context->getGroup());
760             $test->assertSame($test->referenceMetadata, $context->getMetadata());
761             $test->assertSame($entity, $context->getRoot());
762             $test->assertSame($entity->reference[2]['key'], $context->getValue());
763             $test->assertSame($entity->reference[2]['key'], $value);
764
765             $context->addViolation('Message %param%', array('%param%' => 'value'));
766         };
767
768         $this->metadata->addPropertyConstraint('reference', new Valid(array(
769             'traverse' => true,
770         )));
771         $this->referenceMetadata->addConstraint(new Callback(array(
772             'callback' => $callback,
773             'groups' => 'Group',
774         )));
775
776         $violations = $this->validate($entity, null, 'Group');
777
778         /* @var ConstraintViolationInterface[] $violations */
779         $this->assertCount(1, $violations);
780         $this->assertSame('Message value', $violations[0]->getMessage());
781         $this->assertSame('Message %param%', $violations[0]->getMessageTemplate());
782         $this->assertSame(array('%param%' => 'value'), $violations[0]->getParameters());
783         $this->assertSame('reference[2][key]', $violations[0]->getPropertyPath());
784         $this->assertSame($entity, $violations[0]->getRoot());
785         $this->assertSame($entity->reference[2]['key'], $violations[0]->getInvalidValue());
786         $this->assertNull($violations[0]->getPlural());
787         $this->assertNull($violations[0]->getCode());
788     }
789
790     public function testValidateProperty()
791     {
792         $test = $this;
793         $entity = new Entity();
794         $entity->firstName = 'Bernhard';
795         $entity->setLastName('Schussek');
796
797         $callback1 = function ($value, ExecutionContextInterface $context) use ($test, $entity) {
798             $propertyMetadatas = $test->metadata->getPropertyMetadata('firstName');
799
800             $test->assertSame($test::ENTITY_CLASS, $context->getClassName());
801             $test->assertSame('firstName', $context->getPropertyName());
802             $test->assertSame('firstName', $context->getPropertyPath());
803             $test->assertSame('Group', $context->getGroup());
804             $test->assertSame($propertyMetadatas[0], $context->getMetadata());
805             $test->assertSame($entity, $context->getRoot());
806             $test->assertSame('Bernhard', $context->getValue());
807             $test->assertSame('Bernhard', $value);
808
809             $context->addViolation('Message %param%', array('%param%' => 'value'));
810         };
811
812         $callback2 = function ($value, ExecutionContextInterface $context) {
813             $context->addViolation('Other violation');
814         };
815
816         $this->metadata->addPropertyConstraint('firstName', new Callback(array(
817             'callback' => $callback1,
818             'groups' => 'Group',
819         )));
820         $this->metadata->addPropertyConstraint('lastName', new Callback(array(
821             'callback' => $callback2,
822             'groups' => 'Group',
823         )));
824
825         $violations = $this->validateProperty($entity, 'firstName', 'Group');
826
827         /* @var ConstraintViolationInterface[] $violations */
828         $this->assertCount(1, $violations);
829         $this->assertSame('Message value', $violations[0]->getMessage());
830         $this->assertSame('Message %param%', $violations[0]->getMessageTemplate());
831         $this->assertSame(array('%param%' => 'value'), $violations[0]->getParameters());
832         $this->assertSame('firstName', $violations[0]->getPropertyPath());
833         $this->assertSame($entity, $violations[0]->getRoot());
834         $this->assertSame('Bernhard', $violations[0]->getInvalidValue());
835         $this->assertNull($violations[0]->getPlural());
836         $this->assertNull($violations[0]->getCode());
837     }
838
839     /**
840      * Cannot be UnsupportedMetadataException for BC with Symfony < 2.5.
841      *
842      * @expectedException \Symfony\Component\Validator\Exception\ValidatorException
843      * @group legacy
844      */
845     public function testLegacyValidatePropertyFailsIfPropertiesNotSupported()
846     {
847         // $metadata does not implement PropertyMetadataContainerInterface
848         $metadata = $this->getMockBuilder('Symfony\Component\Validator\MetadataInterface')->getMock();
849
850         $this->metadataFactory->addMetadataForValue('VALUE', $metadata);
851
852         $this->validateProperty('VALUE', 'someProperty');
853     }
854
855     /**
856      * https://github.com/symfony/symfony/issues/11604.
857      */
858     public function testValidatePropertyWithoutConstraints()
859     {
860         $entity = new Entity();
861         $violations = $this->validateProperty($entity, 'lastName');
862
863         $this->assertCount(0, $violations, '->validateProperty() returns no violations if no constraints have been configured for the property being validated');
864     }
865
866     public function testValidatePropertyValue()
867     {
868         $test = $this;
869         $entity = new Entity();
870         $entity->setLastName('Schussek');
871
872         $callback1 = function ($value, ExecutionContextInterface $context) use ($test, $entity) {
873             $propertyMetadatas = $test->metadata->getPropertyMetadata('firstName');
874
875             $test->assertSame($test::ENTITY_CLASS, $context->getClassName());
876             $test->assertSame('firstName', $context->getPropertyName());
877             $test->assertSame('firstName', $context->getPropertyPath());
878             $test->assertSame('Group', $context->getGroup());
879             $test->assertSame($propertyMetadatas[0], $context->getMetadata());
880             $test->assertSame($entity, $context->getRoot());
881             $test->assertSame('Bernhard', $context->getValue());
882             $test->assertSame('Bernhard', $value);
883
884             $context->addViolation('Message %param%', array('%param%' => 'value'));
885         };
886
887         $callback2 = function ($value, ExecutionContextInterface $context) {
888             $context->addViolation('Other violation');
889         };
890
891         $this->metadata->addPropertyConstraint('firstName', new Callback(array(
892             'callback' => $callback1,
893             'groups' => 'Group',
894         )));
895         $this->metadata->addPropertyConstraint('lastName', new Callback(array(
896             'callback' => $callback2,
897             'groups' => 'Group',
898         )));
899
900         $violations = $this->validatePropertyValue(
901             $entity,
902             'firstName',
903             'Bernhard',
904             'Group'
905         );
906
907         /* @var ConstraintViolationInterface[] $violations */
908         $this->assertCount(1, $violations);
909         $this->assertSame('Message value', $violations[0]->getMessage());
910         $this->assertSame('Message %param%', $violations[0]->getMessageTemplate());
911         $this->assertSame(array('%param%' => 'value'), $violations[0]->getParameters());
912         $this->assertSame('firstName', $violations[0]->getPropertyPath());
913         $this->assertSame($entity, $violations[0]->getRoot());
914         $this->assertSame('Bernhard', $violations[0]->getInvalidValue());
915         $this->assertNull($violations[0]->getPlural());
916         $this->assertNull($violations[0]->getCode());
917     }
918
919     public function testValidatePropertyValueWithClassName()
920     {
921         $test = $this;
922
923         $callback1 = function ($value, ExecutionContextInterface $context) use ($test) {
924             $propertyMetadatas = $test->metadata->getPropertyMetadata('firstName');
925
926             $test->assertSame($test::ENTITY_CLASS, $context->getClassName());
927             $test->assertSame('firstName', $context->getPropertyName());
928             $test->assertSame('', $context->getPropertyPath());
929             $test->assertSame('Group', $context->getGroup());
930             $test->assertSame($propertyMetadatas[0], $context->getMetadata());
931             $test->assertSame('Bernhard', $context->getRoot());
932             $test->assertSame('Bernhard', $context->getValue());
933             $test->assertSame('Bernhard', $value);
934
935             $context->addViolation('Message %param%', array('%param%' => 'value'));
936         };
937
938         $callback2 = function ($value, ExecutionContextInterface $context) {
939             $context->addViolation('Other violation');
940         };
941
942         $this->metadata->addPropertyConstraint('firstName', new Callback(array(
943             'callback' => $callback1,
944             'groups' => 'Group',
945         )));
946         $this->metadata->addPropertyConstraint('lastName', new Callback(array(
947             'callback' => $callback2,
948             'groups' => 'Group',
949         )));
950
951         $violations = $this->validatePropertyValue(
952             self::ENTITY_CLASS,
953             'firstName',
954             'Bernhard',
955             'Group'
956         );
957
958         /* @var ConstraintViolationInterface[] $violations */
959         $this->assertCount(1, $violations);
960         $this->assertSame('Message value', $violations[0]->getMessage());
961         $this->assertSame('Message %param%', $violations[0]->getMessageTemplate());
962         $this->assertSame(array('%param%' => 'value'), $violations[0]->getParameters());
963         $this->assertSame('', $violations[0]->getPropertyPath());
964         $this->assertSame('Bernhard', $violations[0]->getRoot());
965         $this->assertSame('Bernhard', $violations[0]->getInvalidValue());
966         $this->assertNull($violations[0]->getPlural());
967         $this->assertNull($violations[0]->getCode());
968     }
969
970     /**
971      * Cannot be UnsupportedMetadataException for BC with Symfony < 2.5.
972      *
973      * @expectedException \Symfony\Component\Validator\Exception\ValidatorException
974      * @group legacy
975      */
976     public function testLegacyValidatePropertyValueFailsIfPropertiesNotSupported()
977     {
978         // $metadata does not implement PropertyMetadataContainerInterface
979         $metadata = $this->getMockBuilder('Symfony\Component\Validator\MetadataInterface')->getMock();
980
981         $this->metadataFactory->addMetadataForValue('VALUE', $metadata);
982
983         $this->validatePropertyValue('VALUE', 'someProperty', 'someValue');
984     }
985
986     /**
987      * https://github.com/symfony/symfony/issues/11604.
988      */
989     public function testValidatePropertyValueWithoutConstraints()
990     {
991         $entity = new Entity();
992         $violations = $this->validatePropertyValue($entity, 'lastName', 'foo');
993
994         $this->assertCount(0, $violations, '->validatePropertyValue() returns no violations if no constraints have been configured for the property being validated');
995     }
996
997     public function testValidateObjectOnlyOncePerGroup()
998     {
999         $entity = new Entity();
1000         $entity->reference = new Reference();
1001         $entity->reference2 = $entity->reference;
1002
1003         $callback = function ($value, ExecutionContextInterface $context) {
1004             $context->addViolation('Message');
1005         };
1006
1007         $this->metadata->addPropertyConstraint('reference', new Valid());
1008         $this->metadata->addPropertyConstraint('reference2', new Valid());
1009         $this->referenceMetadata->addConstraint(new Callback($callback));
1010
1011         $violations = $this->validate($entity);
1012
1013         /* @var ConstraintViolationInterface[] $violations */
1014         $this->assertCount(1, $violations);
1015     }
1016
1017     public function testValidateDifferentObjectsSeparately()
1018     {
1019         $entity = new Entity();
1020         $entity->reference = new Reference();
1021         $entity->reference2 = new Reference();
1022
1023         $callback = function ($value, ExecutionContextInterface $context) {
1024             $context->addViolation('Message');
1025         };
1026
1027         $this->metadata->addPropertyConstraint('reference', new Valid());
1028         $this->metadata->addPropertyConstraint('reference2', new Valid());
1029         $this->referenceMetadata->addConstraint(new Callback($callback));
1030
1031         $violations = $this->validate($entity);
1032
1033         /* @var ConstraintViolationInterface[] $violations */
1034         $this->assertCount(2, $violations);
1035     }
1036
1037     public function testValidateSingleGroup()
1038     {
1039         $entity = new Entity();
1040
1041         $callback = function ($value, ExecutionContextInterface $context) {
1042             $context->addViolation('Message');
1043         };
1044
1045         $this->metadata->addConstraint(new Callback(array(
1046             'callback' => $callback,
1047             'groups' => 'Group 1',
1048         )));
1049         $this->metadata->addConstraint(new Callback(array(
1050             'callback' => $callback,
1051             'groups' => 'Group 2',
1052         )));
1053
1054         $violations = $this->validate($entity, null, 'Group 2');
1055
1056         /* @var ConstraintViolationInterface[] $violations */
1057         $this->assertCount(1, $violations);
1058     }
1059
1060     public function testValidateMultipleGroups()
1061     {
1062         $entity = new Entity();
1063
1064         $callback = function ($value, ExecutionContextInterface $context) {
1065             $context->addViolation('Message');
1066         };
1067
1068         $this->metadata->addConstraint(new Callback(array(
1069             'callback' => $callback,
1070             'groups' => 'Group 1',
1071         )));
1072         $this->metadata->addConstraint(new Callback(array(
1073             'callback' => $callback,
1074             'groups' => 'Group 2',
1075         )));
1076
1077         $violations = $this->validate($entity, null, array('Group 1', 'Group 2'));
1078
1079         /* @var ConstraintViolationInterface[] $violations */
1080         $this->assertCount(2, $violations);
1081     }
1082
1083     public function testReplaceDefaultGroupByGroupSequenceObject()
1084     {
1085         $entity = new Entity();
1086
1087         $callback1 = function ($value, ExecutionContextInterface $context) {
1088             $context->addViolation('Violation in Group 2');
1089         };
1090         $callback2 = function ($value, ExecutionContextInterface $context) {
1091             $context->addViolation('Violation in Group 3');
1092         };
1093
1094         $this->metadata->addConstraint(new Callback(array(
1095             'callback' => function () {},
1096             'groups' => 'Group 1',
1097         )));
1098         $this->metadata->addConstraint(new Callback(array(
1099             'callback' => $callback1,
1100             'groups' => 'Group 2',
1101         )));
1102         $this->metadata->addConstraint(new Callback(array(
1103             'callback' => $callback2,
1104             'groups' => 'Group 3',
1105         )));
1106
1107         $sequence = new GroupSequence(array('Group 1', 'Group 2', 'Group 3', 'Entity'));
1108         $this->metadata->setGroupSequence($sequence);
1109
1110         $violations = $this->validate($entity, null, 'Default');
1111
1112         /* @var ConstraintViolationInterface[] $violations */
1113         $this->assertCount(1, $violations);
1114         $this->assertSame('Violation in Group 2', $violations[0]->getMessage());
1115     }
1116
1117     public function testReplaceDefaultGroupByGroupSequenceArray()
1118     {
1119         $entity = new Entity();
1120
1121         $callback1 = function ($value, ExecutionContextInterface $context) {
1122             $context->addViolation('Violation in Group 2');
1123         };
1124         $callback2 = function ($value, ExecutionContextInterface $context) {
1125             $context->addViolation('Violation in Group 3');
1126         };
1127
1128         $this->metadata->addConstraint(new Callback(array(
1129             'callback' => function () {},
1130             'groups' => 'Group 1',
1131         )));
1132         $this->metadata->addConstraint(new Callback(array(
1133             'callback' => $callback1,
1134             'groups' => 'Group 2',
1135         )));
1136         $this->metadata->addConstraint(new Callback(array(
1137             'callback' => $callback2,
1138             'groups' => 'Group 3',
1139         )));
1140
1141         $sequence = array('Group 1', 'Group 2', 'Group 3', 'Entity');
1142         $this->metadata->setGroupSequence($sequence);
1143
1144         $violations = $this->validate($entity, null, 'Default');
1145
1146         /* @var ConstraintViolationInterface[] $violations */
1147         $this->assertCount(1, $violations);
1148         $this->assertSame('Violation in Group 2', $violations[0]->getMessage());
1149     }
1150
1151     public function testPropagateDefaultGroupToReferenceWhenReplacingDefaultGroup()
1152     {
1153         $entity = new Entity();
1154         $entity->reference = new Reference();
1155
1156         $callback1 = function ($value, ExecutionContextInterface $context) {
1157             $context->addViolation('Violation in Default group');
1158         };
1159         $callback2 = function ($value, ExecutionContextInterface $context) {
1160             $context->addViolation('Violation in group sequence');
1161         };
1162
1163         $this->metadata->addPropertyConstraint('reference', new Valid());
1164         $this->referenceMetadata->addConstraint(new Callback(array(
1165             'callback' => $callback1,
1166             'groups' => 'Default',
1167         )));
1168         $this->referenceMetadata->addConstraint(new Callback(array(
1169             'callback' => $callback2,
1170             'groups' => 'Group 1',
1171         )));
1172
1173         $sequence = new GroupSequence(array('Group 1', 'Entity'));
1174         $this->metadata->setGroupSequence($sequence);
1175
1176         $violations = $this->validate($entity, null, 'Default');
1177
1178         /* @var ConstraintViolationInterface[] $violations */
1179         $this->assertCount(1, $violations);
1180         $this->assertSame('Violation in Default group', $violations[0]->getMessage());
1181     }
1182
1183     public function testValidateCustomGroupWhenDefaultGroupWasReplaced()
1184     {
1185         $entity = new Entity();
1186
1187         $callback1 = function ($value, ExecutionContextInterface $context) {
1188             $context->addViolation('Violation in other group');
1189         };
1190         $callback2 = function ($value, ExecutionContextInterface $context) {
1191             $context->addViolation('Violation in group sequence');
1192         };
1193
1194         $this->metadata->addConstraint(new Callback(array(
1195             'callback' => $callback1,
1196             'groups' => 'Other Group',
1197         )));
1198         $this->metadata->addConstraint(new Callback(array(
1199             'callback' => $callback2,
1200             'groups' => 'Group 1',
1201         )));
1202
1203         $sequence = new GroupSequence(array('Group 1', 'Entity'));
1204         $this->metadata->setGroupSequence($sequence);
1205
1206         $violations = $this->validate($entity, null, 'Other Group');
1207
1208         /* @var ConstraintViolationInterface[] $violations */
1209         $this->assertCount(1, $violations);
1210         $this->assertSame('Violation in other group', $violations[0]->getMessage());
1211     }
1212
1213     public function testReplaceDefaultGroupWithObjectFromGroupSequenceProvider()
1214     {
1215         $sequence = new GroupSequence(array('Group 1', 'Group 2', 'Group 3', 'Entity'));
1216         $entity = new GroupSequenceProviderEntity($sequence);
1217
1218         $callback1 = function ($value, ExecutionContextInterface $context) {
1219             $context->addViolation('Violation in Group 2');
1220         };
1221         $callback2 = function ($value, ExecutionContextInterface $context) {
1222             $context->addViolation('Violation in Group 3');
1223         };
1224
1225         $metadata = new ClassMetadata(get_class($entity));
1226         $metadata->addConstraint(new Callback(array(
1227             'callback' => function () {},
1228             'groups' => 'Group 1',
1229         )));
1230         $metadata->addConstraint(new Callback(array(
1231             'callback' => $callback1,
1232             'groups' => 'Group 2',
1233         )));
1234         $metadata->addConstraint(new Callback(array(
1235             'callback' => $callback2,
1236             'groups' => 'Group 3',
1237         )));
1238         $metadata->setGroupSequenceProvider(true);
1239
1240         $this->metadataFactory->addMetadata($metadata);
1241
1242         $violations = $this->validate($entity, null, 'Default');
1243
1244         /* @var ConstraintViolationInterface[] $violations */
1245         $this->assertCount(1, $violations);
1246         $this->assertSame('Violation in Group 2', $violations[0]->getMessage());
1247     }
1248
1249     public function testReplaceDefaultGroupWithArrayFromGroupSequenceProvider()
1250     {
1251         $sequence = array('Group 1', 'Group 2', 'Group 3', 'Entity');
1252         $entity = new GroupSequenceProviderEntity($sequence);
1253
1254         $callback1 = function ($value, ExecutionContextInterface $context) {
1255             $context->addViolation('Violation in Group 2');
1256         };
1257         $callback2 = function ($value, ExecutionContextInterface $context) {
1258             $context->addViolation('Violation in Group 3');
1259         };
1260
1261         $metadata = new ClassMetadata(get_class($entity));
1262         $metadata->addConstraint(new Callback(array(
1263             'callback' => function () {},
1264             'groups' => 'Group 1',
1265         )));
1266         $metadata->addConstraint(new Callback(array(
1267             'callback' => $callback1,
1268             'groups' => 'Group 2',
1269         )));
1270         $metadata->addConstraint(new Callback(array(
1271             'callback' => $callback2,
1272             'groups' => 'Group 3',
1273         )));
1274         $metadata->setGroupSequenceProvider(true);
1275
1276         $this->metadataFactory->addMetadata($metadata);
1277
1278         $violations = $this->validate($entity, null, 'Default');
1279
1280         /* @var ConstraintViolationInterface[] $violations */
1281         $this->assertCount(1, $violations);
1282         $this->assertSame('Violation in Group 2', $violations[0]->getMessage());
1283     }
1284 }