db backup prior to drupal security update
[yaffs-website] / vendor / symfony / validator / Tests / Validator / Abstract2Dot5ApiTest.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 Symfony\Component\Validator\Constraints\Callback;
15 use Symfony\Component\Validator\Constraints\Collection;
16 use Symfony\Component\Validator\Constraints\GroupSequence;
17 use Symfony\Component\Validator\Constraints\NotNull;
18 use Symfony\Component\Validator\Constraints\Traverse;
19 use Symfony\Component\Validator\Constraints\Valid;
20 use Symfony\Component\Validator\ConstraintViolationInterface;
21 use Symfony\Component\Validator\Context\ExecutionContextInterface;
22 use Symfony\Component\Validator\Mapping\ClassMetadata;
23 use Symfony\Component\Validator\MetadataFactoryInterface;
24 use Symfony\Component\Validator\Tests\Fixtures\Entity;
25 use Symfony\Component\Validator\Tests\Fixtures\FailingConstraint;
26 use Symfony\Component\Validator\Tests\Fixtures\FakeClassMetadata;
27 use Symfony\Component\Validator\Tests\Fixtures\Reference;
28 use Symfony\Component\Validator\Validator\ValidatorInterface;
29
30 /**
31  * Verifies that a validator satisfies the API of Symfony 2.5+.
32  *
33  * @author Bernhard Schussek <bschussek@gmail.com>
34  */
35 abstract class Abstract2Dot5ApiTest extends AbstractValidatorTest
36 {
37     /**
38      * @var ValidatorInterface
39      */
40     protected $validator;
41
42     /**
43      * @param MetadataFactoryInterface $metadataFactory
44      * @param array                    $objectInitializers
45      *
46      * @return ValidatorInterface
47      */
48     abstract protected function createValidator(MetadataFactoryInterface $metadataFactory, array $objectInitializers = array());
49
50     protected function setUp()
51     {
52         parent::setUp();
53
54         $this->validator = $this->createValidator($this->metadataFactory);
55     }
56
57     protected function validate($value, $constraints = null, $groups = null)
58     {
59         return $this->validator->validate($value, $constraints, $groups);
60     }
61
62     protected function validateProperty($object, $propertyName, $groups = null)
63     {
64         return $this->validator->validateProperty($object, $propertyName, $groups);
65     }
66
67     protected function validatePropertyValue($object, $propertyName, $value, $groups = null)
68     {
69         return $this->validator->validatePropertyValue($object, $propertyName, $value, $groups);
70     }
71
72     public function testValidateConstraintWithoutGroup()
73     {
74         $violations = $this->validator->validate(null, new NotNull());
75
76         $this->assertCount(1, $violations);
77     }
78
79     public function testValidateWithEmptyArrayAsConstraint()
80     {
81         $violations = $this->validator->validate('value', array());
82         $this->assertCount(0, $violations);
83     }
84
85     public function testGroupSequenceAbortsAfterFailedGroup()
86     {
87         $entity = new Entity();
88
89         $callback1 = function ($value, ExecutionContextInterface $context) {
90             $context->addViolation('Message 1');
91         };
92         $callback2 = function ($value, ExecutionContextInterface $context) {
93             $context->addViolation('Message 2');
94         };
95
96         $this->metadata->addConstraint(new Callback(array(
97             'callback' => function () {},
98             'groups' => 'Group 1',
99         )));
100         $this->metadata->addConstraint(new Callback(array(
101             'callback' => $callback1,
102             'groups' => 'Group 2',
103         )));
104         $this->metadata->addConstraint(new Callback(array(
105             'callback' => $callback2,
106             'groups' => 'Group 3',
107         )));
108
109         $sequence = new GroupSequence(array('Group 1', 'Group 2', 'Group 3'));
110         $violations = $this->validator->validate($entity, new Valid(), $sequence);
111
112         /* @var ConstraintViolationInterface[] $violations */
113         $this->assertCount(1, $violations);
114         $this->assertSame('Message 1', $violations[0]->getMessage());
115     }
116
117     public function testGroupSequenceIncludesReferences()
118     {
119         $entity = new Entity();
120         $entity->reference = new Reference();
121
122         $callback1 = function ($value, ExecutionContextInterface $context) {
123             $context->addViolation('Reference violation 1');
124         };
125         $callback2 = function ($value, ExecutionContextInterface $context) {
126             $context->addViolation('Reference violation 2');
127         };
128
129         $this->metadata->addPropertyConstraint('reference', new Valid());
130         $this->referenceMetadata->addConstraint(new Callback(array(
131             'callback' => $callback1,
132             'groups' => 'Group 1',
133         )));
134         $this->referenceMetadata->addConstraint(new Callback(array(
135             'callback' => $callback2,
136             'groups' => 'Group 2',
137         )));
138
139         $sequence = new GroupSequence(array('Group 1', 'Entity'));
140         $violations = $this->validator->validate($entity, new Valid(), $sequence);
141
142         /* @var ConstraintViolationInterface[] $violations */
143         $this->assertCount(1, $violations);
144         $this->assertSame('Reference violation 1', $violations[0]->getMessage());
145     }
146
147     public function testValidateInSeparateContext()
148     {
149         $test = $this;
150         $entity = new Entity();
151         $entity->reference = new Reference();
152
153         $callback1 = function ($value, ExecutionContextInterface $context) use ($test, $entity) {
154             $violations = $context
155                 ->getValidator()
156                 // Since the validator is not context aware, the group must
157                 // be passed explicitly
158                 ->validate($value->reference, new Valid(), 'Group')
159             ;
160
161             /* @var ConstraintViolationInterface[] $violations */
162             $test->assertCount(1, $violations);
163             $test->assertSame('Message value', $violations[0]->getMessage());
164             $test->assertSame('Message %param%', $violations[0]->getMessageTemplate());
165             $test->assertSame(array('%param%' => 'value'), $violations[0]->getParameters());
166             $test->assertSame('', $violations[0]->getPropertyPath());
167             // The root is different as we're in a new context
168             $test->assertSame($entity->reference, $violations[0]->getRoot());
169             $test->assertSame($entity->reference, $violations[0]->getInvalidValue());
170             $test->assertNull($violations[0]->getPlural());
171             $test->assertNull($violations[0]->getCode());
172
173             // Verify that this method is called
174             $context->addViolation('Separate violation');
175         };
176
177         $callback2 = function ($value, ExecutionContextInterface $context) use ($test, $entity) {
178             $test->assertSame($test::REFERENCE_CLASS, $context->getClassName());
179             $test->assertNull($context->getPropertyName());
180             $test->assertSame('', $context->getPropertyPath());
181             $test->assertSame('Group', $context->getGroup());
182             $test->assertSame($test->referenceMetadata, $context->getMetadata());
183             $test->assertSame($entity->reference, $context->getRoot());
184             $test->assertSame($entity->reference, $context->getValue());
185             $test->assertSame($entity->reference, $value);
186
187             $context->addViolation('Message %param%', array('%param%' => 'value'));
188         };
189
190         $this->metadata->addConstraint(new Callback(array(
191             'callback' => $callback1,
192             'groups' => 'Group',
193         )));
194         $this->referenceMetadata->addConstraint(new Callback(array(
195             'callback' => $callback2,
196             'groups' => 'Group',
197         )));
198
199         $violations = $this->validator->validate($entity, new Valid(), 'Group');
200
201         /* @var ConstraintViolationInterface[] $violations */
202         $this->assertCount(1, $violations);
203         $test->assertSame('Separate violation', $violations[0]->getMessage());
204     }
205
206     public function testValidateInContext()
207     {
208         $test = $this;
209         $entity = new Entity();
210         $entity->reference = new Reference();
211
212         $callback1 = function ($value, ExecutionContextInterface $context) use ($test) {
213             $previousValue = $context->getValue();
214             $previousObject = $context->getObject();
215             $previousMetadata = $context->getMetadata();
216             $previousPath = $context->getPropertyPath();
217             $previousGroup = $context->getGroup();
218
219             $context
220                 ->getValidator()
221                 ->inContext($context)
222                 ->atPath('subpath')
223                 ->validate($value->reference)
224             ;
225
226             // context changes shouldn't leak out of the validate() call
227             $test->assertSame($previousValue, $context->getValue());
228             $test->assertSame($previousObject, $context->getObject());
229             $test->assertSame($previousMetadata, $context->getMetadata());
230             $test->assertSame($previousPath, $context->getPropertyPath());
231             $test->assertSame($previousGroup, $context->getGroup());
232         };
233
234         $callback2 = function ($value, ExecutionContextInterface $context) use ($test, $entity) {
235             $test->assertSame($test::REFERENCE_CLASS, $context->getClassName());
236             $test->assertNull($context->getPropertyName());
237             $test->assertSame('subpath', $context->getPropertyPath());
238             $test->assertSame('Group', $context->getGroup());
239             $test->assertSame($test->referenceMetadata, $context->getMetadata());
240             $test->assertSame($entity, $context->getRoot());
241             $test->assertSame($entity->reference, $context->getValue());
242             $test->assertSame($entity->reference, $value);
243
244             $context->addViolation('Message %param%', array('%param%' => 'value'));
245         };
246
247         $this->metadata->addConstraint(new Callback(array(
248             'callback' => $callback1,
249             'groups' => 'Group',
250         )));
251         $this->referenceMetadata->addConstraint(new Callback(array(
252             'callback' => $callback2,
253             'groups' => 'Group',
254         )));
255
256         $violations = $this->validator->validate($entity, new Valid(), 'Group');
257
258         /* @var ConstraintViolationInterface[] $violations */
259         $this->assertCount(1, $violations);
260         $this->assertSame('Message value', $violations[0]->getMessage());
261         $this->assertSame('Message %param%', $violations[0]->getMessageTemplate());
262         $this->assertSame(array('%param%' => 'value'), $violations[0]->getParameters());
263         $this->assertSame('subpath', $violations[0]->getPropertyPath());
264         $this->assertSame($entity, $violations[0]->getRoot());
265         $this->assertSame($entity->reference, $violations[0]->getInvalidValue());
266         $this->assertNull($violations[0]->getPlural());
267         $this->assertNull($violations[0]->getCode());
268     }
269
270     public function testValidateArrayInContext()
271     {
272         $test = $this;
273         $entity = new Entity();
274         $entity->reference = new Reference();
275
276         $callback1 = function ($value, ExecutionContextInterface $context) use ($test) {
277             $previousValue = $context->getValue();
278             $previousObject = $context->getObject();
279             $previousMetadata = $context->getMetadata();
280             $previousPath = $context->getPropertyPath();
281             $previousGroup = $context->getGroup();
282
283             $context
284                 ->getValidator()
285                 ->inContext($context)
286                 ->atPath('subpath')
287                 ->validate(array('key' => $value->reference))
288             ;
289
290             // context changes shouldn't leak out of the validate() call
291             $test->assertSame($previousValue, $context->getValue());
292             $test->assertSame($previousObject, $context->getObject());
293             $test->assertSame($previousMetadata, $context->getMetadata());
294             $test->assertSame($previousPath, $context->getPropertyPath());
295             $test->assertSame($previousGroup, $context->getGroup());
296         };
297
298         $callback2 = function ($value, ExecutionContextInterface $context) use ($test, $entity) {
299             $test->assertSame($test::REFERENCE_CLASS, $context->getClassName());
300             $test->assertNull($context->getPropertyName());
301             $test->assertSame('subpath[key]', $context->getPropertyPath());
302             $test->assertSame('Group', $context->getGroup());
303             $test->assertSame($test->referenceMetadata, $context->getMetadata());
304             $test->assertSame($entity, $context->getRoot());
305             $test->assertSame($entity->reference, $context->getValue());
306             $test->assertSame($entity->reference, $value);
307
308             $context->addViolation('Message %param%', array('%param%' => 'value'));
309         };
310
311         $this->metadata->addConstraint(new Callback(array(
312             'callback' => $callback1,
313             'groups' => 'Group',
314         )));
315         $this->referenceMetadata->addConstraint(new Callback(array(
316             'callback' => $callback2,
317             'groups' => 'Group',
318         )));
319
320         $violations = $this->validator->validate($entity, new Valid(), 'Group');
321
322         /* @var ConstraintViolationInterface[] $violations */
323         $this->assertCount(1, $violations);
324         $this->assertSame('Message value', $violations[0]->getMessage());
325         $this->assertSame('Message %param%', $violations[0]->getMessageTemplate());
326         $this->assertSame(array('%param%' => 'value'), $violations[0]->getParameters());
327         $this->assertSame('subpath[key]', $violations[0]->getPropertyPath());
328         $this->assertSame($entity, $violations[0]->getRoot());
329         $this->assertSame($entity->reference, $violations[0]->getInvalidValue());
330         $this->assertNull($violations[0]->getPlural());
331         $this->assertNull($violations[0]->getCode());
332     }
333
334     public function testTraverseTraversableByDefault()
335     {
336         $test = $this;
337         $entity = new Entity();
338         $traversable = new \ArrayIterator(array('key' => $entity));
339
340         $callback = function ($value, ExecutionContextInterface $context) use ($test, $entity, $traversable) {
341             $test->assertSame($test::ENTITY_CLASS, $context->getClassName());
342             $test->assertNull($context->getPropertyName());
343             $test->assertSame('[key]', $context->getPropertyPath());
344             $test->assertSame('Group', $context->getGroup());
345             $test->assertSame($test->metadata, $context->getMetadata());
346             $test->assertSame($traversable, $context->getRoot());
347             $test->assertSame($entity, $context->getValue());
348             $test->assertSame($entity, $value);
349
350             $context->addViolation('Message %param%', array('%param%' => 'value'));
351         };
352
353         $this->metadataFactory->addMetadata(new ClassMetadata('ArrayIterator'));
354         $this->metadata->addConstraint(new Callback(array(
355             'callback' => $callback,
356             'groups' => 'Group',
357         )));
358
359         $violations = $this->validate($traversable, new Valid(), 'Group');
360
361         /* @var ConstraintViolationInterface[] $violations */
362         $this->assertCount(1, $violations);
363         $this->assertSame('Message value', $violations[0]->getMessage());
364         $this->assertSame('Message %param%', $violations[0]->getMessageTemplate());
365         $this->assertSame(array('%param%' => 'value'), $violations[0]->getParameters());
366         $this->assertSame('[key]', $violations[0]->getPropertyPath());
367         $this->assertSame($traversable, $violations[0]->getRoot());
368         $this->assertSame($entity, $violations[0]->getInvalidValue());
369         $this->assertNull($violations[0]->getPlural());
370         $this->assertNull($violations[0]->getCode());
371     }
372
373     public function testTraversalEnabledOnClass()
374     {
375         $entity = new Entity();
376         $traversable = new \ArrayIterator(array('key' => $entity));
377
378         $callback = function ($value, ExecutionContextInterface $context) {
379             $context->addViolation('Message');
380         };
381
382         $traversableMetadata = new ClassMetadata('ArrayIterator');
383         $traversableMetadata->addConstraint(new Traverse(true));
384
385         $this->metadataFactory->addMetadata($traversableMetadata);
386         $this->metadata->addConstraint(new Callback(array(
387             'callback' => $callback,
388             'groups' => 'Group',
389         )));
390
391         $violations = $this->validate($traversable, new Valid(), 'Group');
392
393         /* @var ConstraintViolationInterface[] $violations */
394         $this->assertCount(1, $violations);
395     }
396
397     public function testTraversalDisabledOnClass()
398     {
399         $test = $this;
400         $entity = new Entity();
401         $traversable = new \ArrayIterator(array('key' => $entity));
402
403         $callback = function ($value, ExecutionContextInterface $context) use ($test) {
404             $test->fail('Should not be called');
405         };
406
407         $traversableMetadata = new ClassMetadata('ArrayIterator');
408         $traversableMetadata->addConstraint(new Traverse(false));
409
410         $this->metadataFactory->addMetadata($traversableMetadata);
411         $this->metadata->addConstraint(new Callback(array(
412             'callback' => $callback,
413             'groups' => 'Group',
414         )));
415
416         $violations = $this->validate($traversable, new Valid(), 'Group');
417
418         /* @var ConstraintViolationInterface[] $violations */
419         $this->assertCount(0, $violations);
420     }
421
422     /**
423      * @expectedException \Symfony\Component\Validator\Exception\ConstraintDefinitionException
424      */
425     public function testExpectTraversableIfTraversalEnabledOnClass()
426     {
427         $entity = new Entity();
428
429         $this->metadata->addConstraint(new Traverse(true));
430
431         $this->validator->validate($entity);
432     }
433
434     public function testReferenceTraversalDisabledOnClass()
435     {
436         $test = $this;
437         $entity = new Entity();
438         $entity->reference = new \ArrayIterator(array('key' => new Reference()));
439
440         $callback = function ($value, ExecutionContextInterface $context) use ($test) {
441             $test->fail('Should not be called');
442         };
443
444         $traversableMetadata = new ClassMetadata('ArrayIterator');
445         $traversableMetadata->addConstraint(new Traverse(false));
446
447         $this->metadataFactory->addMetadata($traversableMetadata);
448         $this->referenceMetadata->addConstraint(new Callback(array(
449             'callback' => $callback,
450             'groups' => 'Group',
451         )));
452         $this->metadata->addPropertyConstraint('reference', new Valid());
453
454         $violations = $this->validate($entity, new Valid(), 'Group');
455
456         /* @var ConstraintViolationInterface[] $violations */
457         $this->assertCount(0, $violations);
458     }
459
460     public function testReferenceTraversalEnabledOnReferenceDisabledOnClass()
461     {
462         $test = $this;
463         $entity = new Entity();
464         $entity->reference = new \ArrayIterator(array('key' => new Reference()));
465
466         $callback = function ($value, ExecutionContextInterface $context) use ($test) {
467             $test->fail('Should not be called');
468         };
469
470         $traversableMetadata = new ClassMetadata('ArrayIterator');
471         $traversableMetadata->addConstraint(new Traverse(false));
472
473         $this->metadataFactory->addMetadata($traversableMetadata);
474         $this->referenceMetadata->addConstraint(new Callback(array(
475             'callback' => $callback,
476             'groups' => 'Group',
477         )));
478         $this->metadata->addPropertyConstraint('reference', new Valid(array(
479             'traverse' => true,
480         )));
481
482         $violations = $this->validate($entity, new Valid(), 'Group');
483
484         /* @var ConstraintViolationInterface[] $violations */
485         $this->assertCount(0, $violations);
486     }
487
488     public function testReferenceTraversalDisabledOnReferenceEnabledOnClass()
489     {
490         $test = $this;
491         $entity = new Entity();
492         $entity->reference = new \ArrayIterator(array('key' => new Reference()));
493
494         $callback = function ($value, ExecutionContextInterface $context) use ($test) {
495             $test->fail('Should not be called');
496         };
497
498         $traversableMetadata = new ClassMetadata('ArrayIterator');
499         $traversableMetadata->addConstraint(new Traverse(true));
500
501         $this->metadataFactory->addMetadata($traversableMetadata);
502         $this->referenceMetadata->addConstraint(new Callback(array(
503             'callback' => $callback,
504             'groups' => 'Group',
505         )));
506         $this->metadata->addPropertyConstraint('reference', new Valid(array(
507             'traverse' => false,
508         )));
509
510         $violations = $this->validate($entity, new Valid(), 'Group');
511
512         /* @var ConstraintViolationInterface[] $violations */
513         $this->assertCount(0, $violations);
514     }
515
516     public function testAddCustomizedViolation()
517     {
518         $entity = new Entity();
519
520         $callback = function ($value, ExecutionContextInterface $context) {
521             $context->buildViolation('Message %param%')
522                 ->setParameter('%param%', 'value')
523                 ->setInvalidValue('Invalid value')
524                 ->setPlural(2)
525                 ->setCode(42)
526                 ->addViolation();
527         };
528
529         $this->metadata->addConstraint(new Callback($callback));
530
531         $violations = $this->validator->validate($entity);
532
533         /* @var ConstraintViolationInterface[] $violations */
534         $this->assertCount(1, $violations);
535         $this->assertSame('Message value', $violations[0]->getMessage());
536         $this->assertSame('Message %param%', $violations[0]->getMessageTemplate());
537         $this->assertSame(array('%param%' => 'value'), $violations[0]->getParameters());
538         $this->assertSame('', $violations[0]->getPropertyPath());
539         $this->assertSame($entity, $violations[0]->getRoot());
540         $this->assertSame('Invalid value', $violations[0]->getInvalidValue());
541         $this->assertSame(2, $violations[0]->getPlural());
542         $this->assertSame(42, $violations[0]->getCode());
543     }
544
545     /**
546      * @expectedException \Symfony\Component\Validator\Exception\UnsupportedMetadataException
547      * @group legacy
548      */
549     public function testMetadataMustImplementClassMetadataInterface()
550     {
551         $entity = new Entity();
552
553         $metadata = $this->getMockBuilder('Symfony\Component\Validator\Tests\Fixtures\LegacyClassMetadata')->getMock();
554         $metadata->expects($this->any())
555             ->method('getClassName')
556             ->will($this->returnValue(get_class($entity)));
557
558         $this->metadataFactory->addMetadata($metadata);
559
560         $this->validator->validate($entity);
561     }
562
563     /**
564      * @expectedException \Symfony\Component\Validator\Exception\UnsupportedMetadataException
565      * @group legacy
566      */
567     public function testReferenceMetadataMustImplementClassMetadataInterface()
568     {
569         $entity = new Entity();
570         $entity->reference = new Reference();
571
572         $metadata = $this->getMockBuilder('Symfony\Component\Validator\Tests\Fixtures\LegacyClassMetadata')->getMock();
573         $metadata->expects($this->any())
574             ->method('getClassName')
575             ->will($this->returnValue(get_class($entity->reference)));
576
577         $this->metadataFactory->addMetadata($metadata);
578
579         $this->metadata->addPropertyConstraint('reference', new Valid());
580
581         $this->validator->validate($entity);
582     }
583
584     /**
585      * @expectedException \Symfony\Component\Validator\Exception\UnsupportedMetadataException
586      * @group legacy
587      */
588     public function testLegacyPropertyMetadataMustImplementPropertyMetadataInterface()
589     {
590         $entity = new Entity();
591
592         // Legacy interface
593         $propertyMetadata = $this->getMockBuilder('Symfony\Component\Validator\MetadataInterface')->getMock();
594         $metadata = new FakeClassMetadata(get_class($entity));
595         $metadata->addCustomPropertyMetadata('firstName', $propertyMetadata);
596
597         $this->metadataFactory->addMetadata($metadata);
598
599         $this->validator->validate($entity);
600     }
601
602     public function testNoDuplicateValidationIfClassConstraintInMultipleGroups()
603     {
604         $entity = new Entity();
605
606         $callback = function ($value, ExecutionContextInterface $context) {
607             $context->addViolation('Message');
608         };
609
610         $this->metadata->addConstraint(new Callback(array(
611             'callback' => $callback,
612             'groups' => array('Group 1', 'Group 2'),
613         )));
614
615         $violations = $this->validator->validate($entity, new Valid(), array('Group 1', 'Group 2'));
616
617         /* @var ConstraintViolationInterface[] $violations */
618         $this->assertCount(1, $violations);
619     }
620
621     public function testNoDuplicateValidationIfPropertyConstraintInMultipleGroups()
622     {
623         $entity = new Entity();
624
625         $callback = function ($value, ExecutionContextInterface $context) {
626             $context->addViolation('Message');
627         };
628
629         $this->metadata->addPropertyConstraint('firstName', new Callback(array(
630             'callback' => $callback,
631             'groups' => array('Group 1', 'Group 2'),
632         )));
633
634         $violations = $this->validator->validate($entity, new Valid(), array('Group 1', 'Group 2'));
635
636         /* @var ConstraintViolationInterface[] $violations */
637         $this->assertCount(1, $violations);
638     }
639
640     /**
641      * @expectedException \Symfony\Component\Validator\Exception\RuntimeException
642      */
643     public function testValidateFailsIfNoConstraintsAndNoObjectOrArray()
644     {
645         $this->validate('Foobar');
646     }
647
648     public function testAccessCurrentObject()
649     {
650         $test = $this;
651         $called = false;
652         $entity = new Entity();
653         $entity->firstName = 'Bernhard';
654
655         $callback = function ($value, ExecutionContextInterface $context) use ($test, $entity, &$called) {
656             $called = true;
657             $test->assertSame($entity, $context->getObject());
658         };
659
660         $this->metadata->addConstraint(new Callback($callback));
661         $this->metadata->addPropertyConstraint('firstName', new Callback($callback));
662
663         $this->validator->validate($entity);
664
665         $this->assertTrue($called);
666     }
667
668     public function testInitializeObjectsOnFirstValidation()
669     {
670         $test = $this;
671         $entity = new Entity();
672         $entity->initialized = false;
673
674         // prepare initializers that set "initialized" to true
675         $initializer1 = $this->getMockBuilder('Symfony\\Component\\Validator\\ObjectInitializerInterface')->getMock();
676         $initializer2 = $this->getMockBuilder('Symfony\\Component\\Validator\\ObjectInitializerInterface')->getMock();
677
678         $initializer1->expects($this->once())
679             ->method('initialize')
680             ->with($entity)
681             ->will($this->returnCallback(function ($object) {
682                 $object->initialized = true;
683             }));
684
685         $initializer2->expects($this->once())
686             ->method('initialize')
687             ->with($entity);
688
689         $this->validator = $this->createValidator($this->metadataFactory, array(
690             $initializer1,
691             $initializer2,
692         ));
693
694         // prepare constraint which
695         // * checks that "initialized" is set to true
696         // * validates the object again
697         $callback = function ($object, ExecutionContextInterface $context) use ($test) {
698             $test->assertTrue($object->initialized);
699
700             // validate again in same group
701             $validator = $context->getValidator()->inContext($context);
702
703             $validator->validate($object);
704
705             // validate again in other group
706             $validator->validate($object, null, 'SomeGroup');
707         };
708
709         $this->metadata->addConstraint(new Callback($callback));
710
711         $this->validate($entity);
712
713         $this->assertTrue($entity->initialized);
714     }
715
716     public function testPassConstraintToViolation()
717     {
718         $constraint = new FailingConstraint();
719         $violations = $this->validate('Foobar', $constraint);
720
721         $this->assertCount(1, $violations);
722         $this->assertSame($constraint, $violations[0]->getConstraint());
723     }
724
725     public function testCollectionConstraitViolationHasCorrectContext()
726     {
727         $data = array(
728             'foo' => 'fooValue',
729         );
730
731         // Missing field must not be the first in the collection validation
732         $constraint = new Collection(array(
733             'foo' => new NotNull(),
734             'bar' => new NotNull(),
735         ));
736
737         $violations = $this->validate($data, $constraint);
738
739         $this->assertCount(1, $violations);
740         $this->assertSame($constraint, $violations[0]->getConstraint());
741     }
742 }