|
14 | 14 | use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
|
15 | 15 | use Symfony\Component\Validator\Constraints\Expression;
|
16 | 16 | use Symfony\Component\Validator\Constraints\ExpressionValidator;
|
| 17 | +use Symfony\Component\Validator\Constraints\IdenticalTo; |
| 18 | +use Symfony\Component\Validator\Constraints\IsNull; |
| 19 | +use Symfony\Component\Validator\Constraints\NotIdenticalTo; |
| 20 | +use Symfony\Component\Validator\Constraints\NotNull; |
| 21 | +use Symfony\Component\Validator\Constraints\Type; |
| 22 | +use Symfony\Component\Validator\Context\ExecutionContext; |
| 23 | +use Symfony\Component\Validator\Exception\ConstraintDefinitionException; |
| 24 | +use Symfony\Component\Validator\Mapping\ClassMetadata; |
17 | 25 | use Symfony\Component\Validator\Test\ConstraintValidatorTestCase;
|
18 | 26 | use Symfony\Component\Validator\Tests\Fixtures\Entity;
|
| 27 | +use Symfony\Component\Validator\Tests\Fixtures\FakeMetadataFactory; |
19 | 28 | use Symfony\Component\Validator\Tests\Fixtures\ToString;
|
| 29 | +use Symfony\Component\Validator\ValidatorBuilder; |
| 30 | +use Symfony\Contracts\Translation\TranslatorInterface; |
20 | 31 |
|
21 | 32 | class ExpressionValidatorTest extends ConstraintValidatorTestCase
|
22 | 33 | {
|
@@ -322,4 +333,108 @@ public function testPassingCustomValues()
|
322 | 333 |
|
323 | 334 | $this->assertNoViolation();
|
324 | 335 | }
|
| 336 | + |
| 337 | + public function testExistingIsValidFunctionIsNotOverridden() |
| 338 | + { |
| 339 | + $used = false; |
| 340 | + |
| 341 | + $el = $el = new ExpressionLanguage(); |
| 342 | + $el->register('is_valid', function () {}, function () use (&$used) { |
| 343 | + $used = true; |
| 344 | + }); |
| 345 | + |
| 346 | + $validator = new ExpressionValidator($el); |
| 347 | + $validator->initialize($this->context); |
| 348 | + |
| 349 | + $validator->validate('foo', new Expression('is_valid()')); |
| 350 | + |
| 351 | + $this->assertTrue($used); |
| 352 | + } |
| 353 | + |
| 354 | + /** |
| 355 | + * @dataProvider isValidFunctionWithInvalidArgumentsProvider |
| 356 | + */ |
| 357 | + public function testIsValidFunctionWithInvalidArguments(string $expectedMessage, $value, string $expression, array $values) |
| 358 | + { |
| 359 | + $this->expectException(ConstraintDefinitionException::class); |
| 360 | + $this->expectExceptionMessage($expectedMessage); |
| 361 | + |
| 362 | + $this->validator->validate($value, new Expression([ |
| 363 | + 'expression' => $expression, |
| 364 | + 'values' => $values, |
| 365 | + ])); |
| 366 | + } |
| 367 | + |
| 368 | + public function isValidFunctionWithInvalidArgumentsProvider() |
| 369 | + { |
| 370 | + return [ |
| 371 | + ['The "is_valid" function requires at least one argument.', null, 'is_valid()', []], |
| 372 | + ['The "is_valid" function only accepts instances of "Symfony\Component\Validator\Constraint", arrays of "Symfony\Component\Validator\Constraint", or strings that represent properties paths (when validating an object), "ArrayIterator" given.', null, 'is_valid(a)', ['a' => new \ArrayIterator()]], |
| 373 | + ['The "is_valid" function only accepts instances of "Symfony\Component\Validator\Constraint", arrays of "Symfony\Component\Validator\Constraint", or strings that represent properties paths (when validating an object), "NULL" given.', null, 'is_valid(a)', ['a' => null]], |
| 374 | + ['The "is_valid" function only accepts arrays that contain instances of "Symfony\Component\Validator\Constraint" exclusively, "ArrayIterator" given.', null, 'is_valid(a)', ['a' => [new \ArrayIterator()]]], |
| 375 | + ['The "is_valid" function only accepts arrays that contain instances of "Symfony\Component\Validator\Constraint" exclusively, "string" given.', null, 'is_valid(a)', ['a' => ['foo']]], |
| 376 | + ['The "is_valid" function only accepts strings that represent properties paths when validating an object.', 'foo', 'is_valid("bar")', []], |
| 377 | + ]; |
| 378 | + } |
| 379 | + |
| 380 | + /** |
| 381 | + * @dataProvider isValidFunctionProvider |
| 382 | + */ |
| 383 | + public function testIsValidFunction(bool $shouldBeValid, $value, string $expression, array $values = [], string $group = null, array $propertiesConstraints = []) |
| 384 | + { |
| 385 | + $translator = $this->createMock(TranslatorInterface::class); |
| 386 | + $translator->method('trans')->willReturnArgument(0); |
| 387 | + |
| 388 | + $validatorBuilder = new ValidatorBuilder(); |
| 389 | + |
| 390 | + $classMetadata = null; |
| 391 | + if ($valueIsObject = \is_object($value)) { |
| 392 | + $classMetadata = new ClassMetadata(\get_class($value)); |
| 393 | + foreach ($propertiesConstraints as $property => $constraints) { |
| 394 | + $classMetadata->addPropertyConstraints($property, $constraints); |
| 395 | + } |
| 396 | + |
| 397 | + $validatorBuilder->setMetadataFactory((new FakeMetadataFactory())->addMetadata($classMetadata)); |
| 398 | + } |
| 399 | + |
| 400 | + $this->validator->initialize($executionContext = new ExecutionContext( |
| 401 | + $validatorBuilder->getValidator(), |
| 402 | + $this->root, |
| 403 | + $translator |
| 404 | + )); |
| 405 | + |
| 406 | + $executionContext->setConstraint($constraint = new Expression([ |
| 407 | + 'expression' => $expression, |
| 408 | + 'values' => $values, |
| 409 | + ])); |
| 410 | + $executionContext->setGroup($group); |
| 411 | + $executionContext->setNode($value, $valueIsObject ? $value : null, $classMetadata, ''); |
| 412 | + |
| 413 | + $this->validator->validate($value, $constraint); |
| 414 | + |
| 415 | + $this->assertSame($shouldBeValid, !(bool) $executionContext->getViolations()->count()); |
| 416 | + } |
| 417 | + |
| 418 | + public function isValidFunctionProvider() |
| 419 | + { |
| 420 | + return [ |
| 421 | + [true, 'foo', 'is_valid(a) or is_valid(b)', ['a' => new NotIdenticalTo('foo'), 'b' => new IdenticalTo('foo')]], |
| 422 | + [false, 'foo', 'is_valid(a) and is_valid(b)', ['a' => new NotIdenticalTo('foo'), 'b' => new IdenticalTo('foo')]], |
| 423 | + [false, 'foo', 'is_valid(a, b)', ['a' => new NotIdenticalTo('foo'), 'b' => new IdenticalTo('foo')]], |
| 424 | + [false, 'foo', 'is_valid(a)', ['a' => new NotIdenticalTo('foo')]], |
| 425 | + [true, 'foo', 'is_valid(a)', ['a' => [new IdenticalTo('foo')]]], |
| 426 | + [true, 'foo', 'is_valid(a)', ['a' => new NotIdenticalTo(['value' => 'foo', 'groups' => 'g1'])], 'g2'], |
| 427 | + [false, new TestExpressionValidatorObject(), 'is_valid("foo")', [], null, ['foo' => [new NotNull()]]], |
| 428 | + [true, new TestExpressionValidatorObject(), 'is_valid("foo")', [], null, ['foo' => [new IsNull()]]], |
| 429 | + [true, new TestExpressionValidatorObject(), 'is_valid("foo")'], |
| 430 | + [true, new TestExpressionValidatorObject(), 'is_valid("any string")'], |
| 431 | + [false, new TestExpressionValidatorObject(), 'is_valid("foo", a)', ['a' => new IsNull()], null, ['foo' => [new IsNull()]]], |
| 432 | + [true, new TestExpressionValidatorObject(), 'is_valid(a, "foo")', ['a' => new Type(TestExpressionValidatorObject::class)], null, ['foo' => [new IsNull()]]], |
| 433 | + ]; |
| 434 | + } |
| 435 | +} |
| 436 | + |
| 437 | +final class TestExpressionValidatorObject |
| 438 | +{ |
| 439 | + public $foo = null; |
325 | 440 | }
|
0 commit comments