From feb3d6f20233001c4d04e4c7ded948e554a58432 Mon Sep 17 00:00:00 2001 From: Bernhard Schussek Date: Wed, 19 Feb 2014 13:04:59 +0100 Subject: [PATCH] [Validator] Tested the validation in a separate context --- .../Validator/Context/ExecutionContext.php | 18 +- .../Context/ExecutionContextManager.php | 30 +--- .../Validator/NodeVisitor/NodeValidator.php | 2 - .../Tests/Validator/AbstractValidatorTest.php | 164 ++++++++++++++++++ .../Tests/Validator/LegacyValidatorTest.php | 25 ++- .../Tests/Validator/ValidatorTest.php | 10 +- 6 files changed, 206 insertions(+), 43 deletions(-) diff --git a/src/Symfony/Component/Validator/Context/ExecutionContext.php b/src/Symfony/Component/Validator/Context/ExecutionContext.php index 5b031aabbd..e2b582843f 100644 --- a/src/Symfony/Component/Validator/Context/ExecutionContext.php +++ b/src/Symfony/Component/Validator/Context/ExecutionContext.php @@ -137,19 +137,13 @@ class ExecutionContext implements ExecutionContextInterface return null; } - $poppedNode = $this->node; + // Remove the current node from the stack + $poppedNode = $this->nodeStack->pop(); - // After removing the last node, the stack is empty and the node - // is null - if (1 === count($this->nodeStack)) { - $this->nodeStack->pop(); - $this->node = null; - - return $poppedNode; - } - - $this->nodeStack->pop(); - $this->node = $this->nodeStack->top(); + // Adjust the current node to the previous node + $this->node = count($this->nodeStack) > 0 + ? $this->nodeStack->top() + : null; return $poppedNode; } diff --git a/src/Symfony/Component/Validator/Context/ExecutionContextManager.php b/src/Symfony/Component/Validator/Context/ExecutionContextManager.php index 369b6a062b..5625136b36 100644 --- a/src/Symfony/Component/Validator/Context/ExecutionContextManager.php +++ b/src/Symfony/Component/Validator/Context/ExecutionContextManager.php @@ -72,10 +72,6 @@ class ExecutionContextManager extends AbstractVisitor implements ExecutionContex // TODO error, call initialize() first } - if (null !== $this->currentContext) { - $this->contextStack->push($this->currentContext); - } - $this->currentContext = new LegacyExecutionContext( $root, $this->validator, @@ -83,29 +79,24 @@ class ExecutionContextManager extends AbstractVisitor implements ExecutionContex $this->translator, $this->translationDomain ); + $this->contextStack->push($this->currentContext); return $this->currentContext; } public function stopContext() { - $stoppedContext = $this->currentContext; - if (0 === count($this->contextStack)) { - $this->currentContext = null; - - return $stoppedContext; + return null; } - if (1 === count($this->contextStack)) { - $this->contextStack->pop(); - $this->currentContext = null; + // Remove the current context from the stack + $stoppedContext = $this->contextStack->pop(); - return $stoppedContext; - } - - $this->contextStack->pop(); - $this->currentContext = $this->contextStack->top(); + // Adjust the current context to the previous context + $this->currentContext = count($this->contextStack) > 0 + ? $this->contextStack->top() + : null; return $stoppedContext; } @@ -115,11 +106,6 @@ class ExecutionContextManager extends AbstractVisitor implements ExecutionContex return $this->currentContext; } - public function afterTraversal(array $nodes) - { - $this->contextStack = new \SplStack(); - } - public function enterNode(Node $node) { if (null === $this->currentContext) { diff --git a/src/Symfony/Component/Validator/NodeVisitor/NodeValidator.php b/src/Symfony/Component/Validator/NodeVisitor/NodeValidator.php index 662262a4a5..100c9b7d3b 100644 --- a/src/Symfony/Component/Validator/NodeVisitor/NodeValidator.php +++ b/src/Symfony/Component/Validator/NodeVisitor/NodeValidator.php @@ -47,8 +47,6 @@ class NodeValidator extends AbstractVisitor implements GroupManagerInterface private $currentGroup; - private $currentObjectHash; - private $objectHashStack; public function __construct(NodeTraverserInterface $nodeTraverser, ConstraintValidatorFactoryInterface $validatorFactory) diff --git a/src/Symfony/Component/Validator/Tests/Validator/AbstractValidatorTest.php b/src/Symfony/Component/Validator/Tests/Validator/AbstractValidatorTest.php index b7a9ee2e19..60e5ebf76e 100644 --- a/src/Symfony/Component/Validator/Tests/Validator/AbstractValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Validator/AbstractValidatorTest.php @@ -1423,6 +1423,58 @@ abstract class AbstractValidatorTest extends \PHPUnit_Framework_TestCase $entity = new Entity(); $entity->reference = new Reference(); + $callback1 = function ($value, ExecutionContextInterface $context) { + $context + ->getValidator() + ->inContext($context) + ->atPath('subpath') + ->validateObject($value->reference) + ; + }; + + $callback2 = function ($value, ExecutionContextInterface $context) use ($test, $entity) { + $test->assertSame($test::REFERENCE_CLASS, $context->getClassName()); + $test->assertNull($context->getPropertyName()); + $test->assertSame('subpath', $context->getPropertyPath()); + $test->assertSame('Group', $context->getGroup()); + $test->assertSame($test->referenceMetadata, $context->getMetadata()); + $test->assertSame($test->metadataFactory, $context->getMetadataFactory()); + $test->assertSame($entity, $context->getRoot()); + $test->assertSame($entity->reference, $context->getValue()); + $test->assertSame($entity->reference, $value); + + $context->addViolation('Message %param%', array('%param%' => 'value')); + }; + + $this->metadata->addConstraint(new Callback(array( + 'callback' => $callback1, + 'groups' => 'Group', + ))); + $this->referenceMetadata->addConstraint(new Callback(array( + 'callback' => $callback2, + 'groups' => 'Group', + ))); + + $violations = $this->validator->validate($entity, 'Group'); + + /** @var ConstraintViolationInterface[] $violations */ + $this->assertCount(1, $violations); + $this->assertSame('Message value', $violations[0]->getMessage()); + $this->assertSame('Message %param%', $violations[0]->getMessageTemplate()); + $this->assertSame(array('%param%' => 'value'), $violations[0]->getMessageParameters()); + $this->assertSame('subpath', $violations[0]->getPropertyPath()); + $this->assertSame($entity, $violations[0]->getRoot()); + $this->assertSame($entity->reference, $violations[0]->getInvalidValue()); + $this->assertNull($violations[0]->getMessagePluralization()); + $this->assertNull($violations[0]->getCode()); + } + + public function testValidateInContextLegacyApi() + { + $test = $this; + $entity = new Entity(); + $entity->reference = new Reference(); + $callback1 = function ($value, ExecutionContextInterface $context) { $context->validate($value->reference, 'subpath'); }; @@ -1470,6 +1522,58 @@ abstract class AbstractValidatorTest extends \PHPUnit_Framework_TestCase $entity = new Entity(); $entity->reference = new Reference(); + $callback1 = function ($value, ExecutionContextInterface $context) { + $context + ->getValidator() + ->inContext($context) + ->atPath('subpath') + ->validateCollection(array('key' => $value->reference)) + ; + }; + + $callback2 = function ($value, ExecutionContextInterface $context) use ($test, $entity) { + $test->assertSame($test::REFERENCE_CLASS, $context->getClassName()); + $test->assertNull($context->getPropertyName()); + $test->assertSame('subpath[key]', $context->getPropertyPath()); + $test->assertSame('Group', $context->getGroup()); + $test->assertSame($test->referenceMetadata, $context->getMetadata()); + $test->assertSame($test->metadataFactory, $context->getMetadataFactory()); + $test->assertSame($entity, $context->getRoot()); + $test->assertSame($entity->reference, $context->getValue()); + $test->assertSame($entity->reference, $value); + + $context->addViolation('Message %param%', array('%param%' => 'value')); + }; + + $this->metadata->addConstraint(new Callback(array( + 'callback' => $callback1, + 'groups' => 'Group', + ))); + $this->referenceMetadata->addConstraint(new Callback(array( + 'callback' => $callback2, + 'groups' => 'Group', + ))); + + $violations = $this->validator->validate($entity, 'Group'); + + /** @var ConstraintViolationInterface[] $violations */ + $this->assertCount(1, $violations); + $this->assertSame('Message value', $violations[0]->getMessage()); + $this->assertSame('Message %param%', $violations[0]->getMessageTemplate()); + $this->assertSame(array('%param%' => 'value'), $violations[0]->getMessageParameters()); + $this->assertSame('subpath[key]', $violations[0]->getPropertyPath()); + $this->assertSame($entity, $violations[0]->getRoot()); + $this->assertSame($entity->reference, $violations[0]->getInvalidValue()); + $this->assertNull($violations[0]->getMessagePluralization()); + $this->assertNull($violations[0]->getCode()); + } + + public function testValidateArrayInContextLegacyApi() + { + $test = $this; + $entity = new Entity(); + $entity->reference = new Reference(); + $callback1 = function ($value, ExecutionContextInterface $context) { $context->validate(array('key' => $value->reference), 'subpath'); }; @@ -1511,6 +1615,66 @@ abstract class AbstractValidatorTest extends \PHPUnit_Framework_TestCase $this->assertNull($violations[0]->getCode()); } + public function testValidateInSeparateContext() + { + $test = $this; + $entity = new Entity(); + $entity->reference = new Reference(); + + $callback1 = function ($value, ExecutionContextInterface $context) use ($test, $entity) { + $violations = $context + ->getValidator() + // Since the validator is not context aware, the group must + // be passed explicitly + ->validateObject($value->reference, 'Group') + ; + + /** @var ConstraintViolationInterface[] $violations */ + $test->assertCount(1, $violations); + $test->assertSame('Message value', $violations[0]->getMessage()); + $test->assertSame('Message %param%', $violations[0]->getMessageTemplate()); + $test->assertSame(array('%param%' => 'value'), $violations[0]->getMessageParameters()); + $test->assertSame('', $violations[0]->getPropertyPath()); + // The root is different as we're in a new context + $test->assertSame($entity->reference, $violations[0]->getRoot()); + $test->assertSame($entity->reference, $violations[0]->getInvalidValue()); + $test->assertNull($violations[0]->getMessagePluralization()); + $test->assertNull($violations[0]->getCode()); + + // Verify that this method is called + $context->addViolation('Separate violation'); + }; + + $callback2 = function ($value, ExecutionContextInterface $context) use ($test, $entity) { + $test->assertSame($test::REFERENCE_CLASS, $context->getClassName()); + $test->assertNull($context->getPropertyName()); + $test->assertSame('', $context->getPropertyPath()); + $test->assertSame('Group', $context->getGroup()); + $test->assertSame($test->referenceMetadata, $context->getMetadata()); + $test->assertSame($test->metadataFactory, $context->getMetadataFactory()); + $test->assertSame($entity->reference, $context->getRoot()); + $test->assertSame($entity->reference, $context->getValue()); + $test->assertSame($entity->reference, $value); + + $context->addViolation('Message %param%', array('%param%' => 'value')); + }; + + $this->metadata->addConstraint(new Callback(array( + 'callback' => $callback1, + 'groups' => 'Group', + ))); + $this->referenceMetadata->addConstraint(new Callback(array( + 'callback' => $callback2, + 'groups' => 'Group', + ))); + + $violations = $this->validator->validate($entity, 'Group'); + + /** @var ConstraintViolationInterface[] $violations */ + $this->assertCount(1, $violations); + $test->assertSame('Separate violation', $violations[0]->getMessage()); + } + public function testGetMetadataFactory() { $this->assertSame($this->metadataFactory, $this->validator->getMetadataFactory()); diff --git a/src/Symfony/Component/Validator/Tests/Validator/LegacyValidatorTest.php b/src/Symfony/Component/Validator/Tests/Validator/LegacyValidatorTest.php index eafbc4d128..c66cde30ea 100644 --- a/src/Symfony/Component/Validator/Tests/Validator/LegacyValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Validator/LegacyValidatorTest.php @@ -14,7 +14,7 @@ namespace Symfony\Component\Validator\Tests\Validator; use Symfony\Component\Validator\Constraints\Valid; use Symfony\Component\Validator\MetadataFactoryInterface; use Symfony\Component\Validator\Tests\Fixtures\Entity; -use Symfony\Component\Validator\Validator; +use Symfony\Component\Validator\Validator as LegacyValidator; use Symfony\Component\Validator\DefaultTranslator; use Symfony\Component\Validator\ConstraintValidatorFactory; @@ -22,22 +22,37 @@ class LegacyValidatorTest extends AbstractValidatorTest { protected function createValidator(MetadataFactoryInterface $metadataFactory) { - return new Validator($metadataFactory, new ConstraintValidatorFactory(), new DefaultTranslator()); + return new LegacyValidator($metadataFactory, new ConstraintValidatorFactory(), new DefaultTranslator()); } public function testNoDuplicateValidationIfConstraintInMultipleGroups() { - $this->markTestSkipped('Currently not supported'); + $this->markTestSkipped('Not supported in the legacy API'); } public function testGroupSequenceAbortsAfterFailedGroup() { - $this->markTestSkipped('Currently not supported'); + $this->markTestSkipped('Not supported in the legacy API'); } public function testGroupSequenceIncludesReferences() { - $this->markTestSkipped('Currently not supported'); + $this->markTestSkipped('Not supported in the legacy API'); + } + + public function testValidateInContext() + { + $this->markTestSkipped('Not supported in the legacy API'); + } + + public function testValidateArrayInContext() + { + $this->markTestSkipped('Not supported in the legacy API'); + } + + public function testValidateInSeparateContext() + { + $this->markTestSkipped('Not supported in the legacy API'); } /** diff --git a/src/Symfony/Component/Validator/Tests/Validator/ValidatorTest.php b/src/Symfony/Component/Validator/Tests/Validator/ValidatorTest.php index 57a08fbc94..2b0d00205e 100644 --- a/src/Symfony/Component/Validator/Tests/Validator/ValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Validator/ValidatorTest.php @@ -24,9 +24,15 @@ use Symfony\Component\Validator\NodeVisitor\NodeValidator; use Symfony\Component\Validator\NodeTraverser\NodeTraverser; use Symfony\Component\Validator\Tests\Fixtures\Entity; use Symfony\Component\Validator\Validator\LegacyValidator; +use Symfony\Component\Validator\Validator\ValidatorInterface; class ValidatorTest extends AbstractValidatorTest { + /** + * @var ValidatorInterface + */ + protected $validator; + protected function createValidator(MetadataFactoryInterface $metadataFactory) { $nodeTraverser = new NodeTraverser($metadataFactory); @@ -50,7 +56,7 @@ class ValidatorTest extends AbstractValidatorTest return $validator; } - public function testValidateValueAcceptsValid() + public function testValidateAcceptsValid() { $test = $this; $entity = new Entity(); @@ -75,7 +81,7 @@ class ValidatorTest extends AbstractValidatorTest ))); // This is the same as when calling validateObject() - $violations = $this->validator->validateValue($entity, new Valid(), 'Group'); + $violations = $this->validator->validate($entity, new Valid(), 'Group'); /** @var ConstraintViolationInterface[] $violations */ $this->assertCount(1, $violations);