This repository has been archived on 2023-08-20. You can view files and clone it, but cannot push or open issues or pull requests.
symfony/src/Symfony/Component/Validator/Tests/ValidationVisitorTest.php
2013-01-08 14:59:49 +01:00

565 lines
18 KiB
PHP

<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Validator\Tests;
use Symfony\Component\Validator\Tests\Fixtures\FakeMetadataFactory;
use Symfony\Component\Validator\Constraints\Valid;
use Symfony\Component\Validator\Tests\Fixtures\Reference;
use Symfony\Component\Validator\DefaultTranslator;
use Symfony\Component\Validator\ConstraintViolation;
use Symfony\Component\Validator\ConstraintViolationList;
use Symfony\Component\Validator\Tests\Fixtures\FailingConstraint;
use Symfony\Component\Validator\Tests\Fixtures\ConstraintAValidator;
use Symfony\Component\Validator\Tests\Fixtures\Entity;
use Symfony\Component\Validator\Tests\Fixtures\ConstraintA;
use Symfony\Component\Validator\Mapping\ClassMetadata;
use Symfony\Component\Validator\ConstraintValidatorFactory;
use Symfony\Component\Validator\ValidationVisitor;
/**
* @author Bernhard Schussek <bschussek@gmail.com>
*/
class ValidationVisitorTest extends \PHPUnit_Framework_TestCase
{
const CLASS_NAME = 'Symfony\Component\Validator\Tests\Fixtures\Entity';
/**
* @var ValidationVisitor
*/
private $visitor;
/**
* @var FakeMetadataFactory
*/
private $metadataFactory;
/**
* @var ClassMetadata
*/
private $metadata;
protected function setUp()
{
$this->metadataFactory = new FakeMetadataFactory();
$this->visitor = new ValidationVisitor('Root', $this->metadataFactory, new ConstraintValidatorFactory(), new DefaultTranslator());
$this->metadata = new ClassMetadata(self::CLASS_NAME);
$this->metadataFactory->addMetadata($this->metadata);
}
protected function tearDown()
{
$this->metadataFactory = null;
$this->visitor = null;
$this->metadata = null;
}
public function testValidatePassesCorrectClassAndProperty()
{
$this->metadata->addConstraint(new ConstraintA());
$entity = new Entity();
$this->visitor->validate($entity, 'Default', '');
$context = ConstraintAValidator::$passedContext;
$this->assertEquals('Symfony\Component\Validator\Tests\Fixtures\Entity', $context->getClassName());
$this->assertNull($context->getPropertyName());
}
public function testValidateConstraints()
{
$this->metadata->addConstraint(new ConstraintA());
$this->visitor->validate(new Entity(), 'Default', '');
$this->assertCount(1, $this->visitor->getViolations());
}
public function testValidateTwiceValidatesConstraintsOnce()
{
$this->metadata->addConstraint(new ConstraintA());
$entity = new Entity();
$this->visitor->validate($entity, 'Default', '');
$this->visitor->validate($entity, 'Default', '');
$this->assertCount(1, $this->visitor->getViolations());
}
public function testValidateDifferentObjectsValidatesTwice()
{
$this->metadata->addConstraint(new ConstraintA());
$this->visitor->validate(new Entity(), 'Default', '');
$this->visitor->validate(new Entity(), 'Default', '');
$this->assertCount(2, $this->visitor->getViolations());
}
public function testValidateTwiceInDifferentGroupsValidatesTwice()
{
$this->metadata->addConstraint(new ConstraintA());
$this->metadata->addConstraint(new ConstraintA(array('groups' => 'Custom')));
$entity = new Entity();
$this->visitor->validate($entity, 'Default', '');
$this->visitor->validate($entity, 'Custom', '');
$this->assertCount(2, $this->visitor->getViolations());
}
public function testValidatePropertyConstraints()
{
$this->metadata->addPropertyConstraint('firstName', new ConstraintA());
$this->visitor->validate(new Entity(), 'Default', '');
$this->assertCount(1, $this->visitor->getViolations());
}
public function testValidateGetterConstraints()
{
$this->metadata->addGetterConstraint('lastName', new ConstraintA());
$this->visitor->validate(new Entity(), 'Default', '');
$this->assertCount(1, $this->visitor->getViolations());
}
public function testValidateInDefaultGroupTraversesGroupSequence()
{
$entity = new Entity();
$this->metadata->addPropertyConstraint('firstName', new FailingConstraint(array(
'groups' => 'First',
)));
$this->metadata->addGetterConstraint('lastName', new FailingConstraint(array(
'groups' => 'Default',
)));
$this->metadata->setGroupSequence(array('First', $this->metadata->getDefaultGroup()));
$this->visitor->validate($entity, 'Default', '');
// After validation of group "First" failed, no more group was
// validated
$violations = new ConstraintViolationList(array(
new ConstraintViolation(
'Failed',
'Failed',
array(),
'Root',
'firstName',
''
),
));
$this->assertEquals($violations, $this->visitor->getViolations());
}
public function testValidateInGroupSequencePropagatesDefaultGroup()
{
$entity = new Entity();
$entity->reference = new Reference();
$this->metadata->addPropertyConstraint('reference', new Valid());
$this->metadata->setGroupSequence(array($this->metadata->getDefaultGroup()));
$referenceMetadata = new ClassMetadata(get_class($entity->reference));
$referenceMetadata->addConstraint(new FailingConstraint(array(
// this constraint is only evaluated if group "Default" is
// propagated to the reference
'groups' => 'Default',
)));
$this->metadataFactory->addMetadata($referenceMetadata);
$this->visitor->validate($entity, 'Default', '');
// The validation of the reference's FailingConstraint in group
// "Default" was launched
$violations = new ConstraintViolationList(array(
new ConstraintViolation(
'Failed',
'Failed',
array(),
'Root',
'reference',
$entity->reference
),
));
$this->assertEquals($violations, $this->visitor->getViolations());
}
public function testValidateInOtherGroupTraversesNoGroupSequence()
{
$entity = new Entity();
$this->metadata->addPropertyConstraint('firstName', new FailingConstraint(array(
'groups' => 'First',
)));
$this->metadata->addGetterConstraint('lastName', new FailingConstraint(array(
'groups' => $this->metadata->getDefaultGroup(),
)));
$this->metadata->setGroupSequence(array('First', $this->metadata->getDefaultGroup()));
$this->visitor->validate($entity, $this->metadata->getDefaultGroup(), '');
// Only group "Second" was validated
$violations = new ConstraintViolationList(array(
new ConstraintViolation(
'Failed',
'Failed',
array(),
'Root',
'lastName',
''
),
));
$this->assertEquals($violations, $this->visitor->getViolations());
}
public function testValidateCascadedPropertyValidatesReferences()
{
$entity = new Entity();
$entity->reference = new Entity();
// add a constraint for the entity that always fails
$this->metadata->addConstraint(new FailingConstraint());
// validate entity when validating the property "reference"
$this->metadata->addPropertyConstraint('reference', new Valid());
// invoke validation on an object
$this->visitor->validate($entity, 'Default', '');
$violations = new ConstraintViolationList(array(
// generated by the root object
new ConstraintViolation(
'Failed',
'Failed',
array(),
'Root',
'',
$entity
),
// generated by the reference
new ConstraintViolation(
'Failed',
'Failed',
array(),
'Root',
'reference',
$entity->reference
),
));
$this->assertEquals($violations, $this->visitor->getViolations());
}
public function testValidateCascadedPropertyValidatesArraysByDefault()
{
$entity = new Entity();
$entity->reference = array('key' => new Entity());
// add a constraint for the entity that always fails
$this->metadata->addConstraint(new FailingConstraint());
// validate array when validating the property "reference"
$this->metadata->addPropertyConstraint('reference', new Valid());
$this->visitor->validate($entity, 'Default', '');
$violations = new ConstraintViolationList(array(
// generated by the root object
new ConstraintViolation(
'Failed',
'Failed',
array(),
'Root',
'',
$entity
),
// generated by the reference
new ConstraintViolation(
'Failed',
'Failed',
array(),
'Root',
'reference[key]',
$entity->reference['key']
),
));
$this->assertEquals($violations, $this->visitor->getViolations());
}
public function testValidateCascadedPropertyValidatesTraversableByDefault()
{
$entity = new Entity();
$entity->reference = new \ArrayIterator(array('key' => new Entity()));
// add a constraint for the entity that always fails
$this->metadata->addConstraint(new FailingConstraint());
// validate array when validating the property "reference"
$this->metadata->addPropertyConstraint('reference', new Valid());
$this->visitor->validate($entity, 'Default', '');
$violations = new ConstraintViolationList(array(
// generated by the root object
new ConstraintViolation(
'Failed',
'Failed',
array(),
'Root',
'',
$entity
),
// generated by the reference
new ConstraintViolation(
'Failed',
'Failed',
array(),
'Root',
'reference[key]',
$entity->reference['key']
),
));
$this->assertEquals($violations, $this->visitor->getViolations());
}
public function testValidateCascadedPropertyDoesNotValidateTraversableIfDisabled()
{
$entity = new Entity();
$entity->reference = new \ArrayIterator(array('key' => new Entity()));
$this->metadataFactory->addMetadata(new ClassMetadata('ArrayIterator'));
// add a constraint for the entity that always fails
$this->metadata->addConstraint(new FailingConstraint());
// validate array when validating the property "reference"
$this->metadata->addPropertyConstraint('reference', new Valid(array(
'traverse' => false,
)));
$this->visitor->validate($entity, 'Default', '');
$violations = new ConstraintViolationList(array(
// generated by the root object
new ConstraintViolation(
'Failed',
'Failed',
array(),
'Root',
'',
$entity
),
// nothing generated by the reference!
));
$this->assertEquals($violations, $this->visitor->getViolations());
}
public function testMetadataMayNotExistIfTraversalIsEnabled()
{
$entity = new Entity();
$entity->reference = new \ArrayIterator();
$this->metadata->addPropertyConstraint('reference', new Valid(array(
'traverse' => true,
)));
$this->visitor->validate($entity, 'Default', '');
}
/**
* @expectedException \Symfony\Component\Validator\Exception\NoSuchMetadataException
*/
public function testMetadataMustExistIfTraversalIsDisabled()
{
$entity = new Entity();
$entity->reference = new \ArrayIterator();
$this->metadata->addPropertyConstraint('reference', new Valid(array(
'traverse' => false,
)));
$this->visitor->validate($entity, 'Default', '');
}
public function testValidateCascadedPropertyDoesNotRecurseByDefault()
{
$entity = new Entity();
$entity->reference = new \ArrayIterator(array(
// The inner iterator should not be traversed by default
'key' => new \ArrayIterator(array(
'nested' => new Entity(),
)),
));
$this->metadataFactory->addMetadata(new ClassMetadata('ArrayIterator'));
// add a constraint for the entity that always fails
$this->metadata->addConstraint(new FailingConstraint());
// validate iterator when validating the property "reference"
$this->metadata->addPropertyConstraint('reference', new Valid());
$this->visitor->validate($entity, 'Default', '');
$violations = new ConstraintViolationList(array(
// generated by the root object
new ConstraintViolation(
'Failed',
'Failed',
array(),
'Root',
'',
$entity
),
// nothing generated by the reference!
));
$this->assertEquals($violations, $this->visitor->getViolations());
}
// https://github.com/symfony/symfony/issues/6246
public function testValidateCascadedPropertyRecursesArraysByDefault()
{
$entity = new Entity();
$entity->reference = array(
'key' => array(
'nested' => new Entity(),
),
);
// add a constraint for the entity that always fails
$this->metadata->addConstraint(new FailingConstraint());
// validate iterator when validating the property "reference"
$this->metadata->addPropertyConstraint('reference', new Valid());
$this->visitor->validate($entity, 'Default', '');
$violations = new ConstraintViolationList(array(
// generated by the root object
new ConstraintViolation(
'Failed',
'Failed',
array(),
'Root',
'',
$entity
),
// nothing generated by the reference!
new ConstraintViolation(
'Failed',
'Failed',
array(),
'Root',
'reference[key][nested]',
$entity->reference['key']['nested']
),
));
$this->assertEquals($violations, $this->visitor->getViolations());
}
public function testValidateCascadedPropertyRecursesIfDeepIsSet()
{
$entity = new Entity();
$entity->reference = new \ArrayIterator(array(
// The inner iterator should now be traversed
'key' => new \ArrayIterator(array(
'nested' => new Entity(),
)),
));
// add a constraint for the entity that always fails
$this->metadata->addConstraint(new FailingConstraint());
// validate iterator when validating the property "reference"
$this->metadata->addPropertyConstraint('reference', new Valid(array(
'deep' => true,
)));
$this->visitor->validate($entity, 'Default', '');
$violations = new ConstraintViolationList(array(
// generated by the root object
new ConstraintViolation(
'Failed',
'Failed',
array(),
'Root',
'',
$entity
),
// nothing generated by the reference!
new ConstraintViolation(
'Failed',
'Failed',
array(),
'Root',
'reference[key][nested]',
$entity->reference['key']['nested']
),
));
$this->assertEquals($violations, $this->visitor->getViolations());
}
public function testValidateCascadedPropertyDoesNotValidateNestedScalarValues()
{
$entity = new Entity();
$entity->reference = array('scalar', 'values');
// validate array when validating the property "reference"
$this->metadata->addPropertyConstraint('reference', new Valid());
$this->visitor->validate($entity, 'Default', '');
$this->assertCount(0, $this->visitor->getViolations());
}
public function testValidateCascadedPropertyDoesNotValidateNullValues()
{
$entity = new Entity();
$entity->reference = null;
$this->metadata->addPropertyConstraint('reference', new Valid());
$this->visitor->validate($entity, 'Default', '');
$this->assertCount(0, $this->visitor->getViolations());
}
/**
* @expectedException \Symfony\Component\Validator\Exception\NoSuchMetadataException
*/
public function testValidateCascadedPropertyRequiresObjectOrArray()
{
$entity = new Entity();
$entity->reference = 'no object';
$this->metadata->addPropertyConstraint('reference', new Valid());
$this->visitor->validate($entity, 'Default', '');
}
}