diff --git a/src/Symfony/Component/Validator/CHANGELOG.md b/src/Symfony/Component/Validator/CHANGELOG.md index 509f3317672b6..d473514a90f13 100644 --- a/src/Symfony/Component/Validator/CHANGELOG.md +++ b/src/Symfony/Component/Validator/CHANGELOG.md @@ -8,7 +8,8 @@ CHANGELOG * added UATP cards support to `CardSchemeValidator` * added option `allowNull` to NotBlank constraint * added `Json` constraint - + * added a new `normalizer` option to the string constraints and to the `NotBlank` constraint + 4.2.0 ----- diff --git a/src/Symfony/Component/Validator/Constraints/Email.php b/src/Symfony/Component/Validator/Constraints/Email.php index c6c760c2c0d74..bb3ea5ce020ca 100644 --- a/src/Symfony/Component/Validator/Constraints/Email.php +++ b/src/Symfony/Component/Validator/Constraints/Email.php @@ -13,6 +13,7 @@ use Egulias\EmailValidator\EmailValidator as StrictEmailValidator; use Symfony\Component\Validator\Constraint; +use Symfony\Component\Validator\Exception\InvalidArgumentException; use Symfony\Component\Validator\Exception\LogicException; /** @@ -73,6 +74,7 @@ class Email extends Constraint */ public $strict; public $mode; + public $normalizer; public function __construct($options = null) { @@ -89,7 +91,7 @@ public function __construct($options = null) } if (\is_array($options) && \array_key_exists('mode', $options) && !\in_array($options['mode'], self::$validationModes, true)) { - throw new \InvalidArgumentException('The "mode" parameter value is not valid.'); + throw new InvalidArgumentException('The "mode" parameter value is not valid.'); } parent::__construct($options); @@ -98,5 +100,9 @@ public function __construct($options = null) // throw new LogicException(sprintf('The "egulias/email-validator" component is required to use the "%s" constraint in strict mode.', __CLASS__)); @trigger_error(sprintf('Using the "%s" constraint in strict mode without the "egulias/email-validator" component installed is deprecated since Symfony 4.2.', __CLASS__), E_USER_DEPRECATED); } + + if (null !== $this->normalizer && !\is_callable($this->normalizer)) { + throw new InvalidArgumentException(sprintf('The "normalizer" option must be a valid callable ("%s" given).', \is_object($this->normalizer) ? \get_class($this->normalizer) : \gettype($this->normalizer))); + } } } diff --git a/src/Symfony/Component/Validator/Constraints/EmailValidator.php b/src/Symfony/Component/Validator/Constraints/EmailValidator.php index 512695919ddb4..b7306d2b0e174 100644 --- a/src/Symfony/Component/Validator/Constraints/EmailValidator.php +++ b/src/Symfony/Component/Validator/Constraints/EmailValidator.php @@ -81,6 +81,10 @@ public function validate($value, Constraint $constraint) $value = (string) $value; + if (null !== $constraint->normalizer) { + $value = ($constraint->normalizer)($value); + } + if (null !== $constraint->strict) { @trigger_error(sprintf('The %s::$strict property is deprecated since Symfony 4.1. Use %s::mode="%s" instead.', Email::class, Email::class, Email::VALIDATION_MODE_STRICT), E_USER_DEPRECATED); diff --git a/src/Symfony/Component/Validator/Constraints/Ip.php b/src/Symfony/Component/Validator/Constraints/Ip.php index aff99d4672d77..3f75702558ff5 100644 --- a/src/Symfony/Component/Validator/Constraints/Ip.php +++ b/src/Symfony/Component/Validator/Constraints/Ip.php @@ -13,6 +13,7 @@ use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\Exception\ConstraintDefinitionException; +use Symfony\Component\Validator\Exception\InvalidArgumentException; /** * Validates that a value is a valid IP address. @@ -72,6 +73,8 @@ class Ip extends Constraint public $message = 'This is not a valid IP address.'; + public $normalizer; + /** * {@inheritdoc} */ @@ -82,5 +85,9 @@ public function __construct($options = null) if (!\in_array($this->version, self::$versions)) { throw new ConstraintDefinitionException(sprintf('The option "version" must be one of "%s"', implode('", "', self::$versions))); } + + if (null !== $this->normalizer && !\is_callable($this->normalizer)) { + throw new InvalidArgumentException(sprintf('The "normalizer" option must be a valid callable ("%s" given).', \is_object($this->normalizer) ? \get_class($this->normalizer) : \gettype($this->normalizer))); + } } } diff --git a/src/Symfony/Component/Validator/Constraints/IpValidator.php b/src/Symfony/Component/Validator/Constraints/IpValidator.php index b96e50623cc62..0f7d383587189 100644 --- a/src/Symfony/Component/Validator/Constraints/IpValidator.php +++ b/src/Symfony/Component/Validator/Constraints/IpValidator.php @@ -43,6 +43,10 @@ public function validate($value, Constraint $constraint) $value = (string) $value; + if (null !== $constraint->normalizer) { + $value = ($constraint->normalizer)($value); + } + switch ($constraint->version) { case Ip::V4: $flag = FILTER_FLAG_IPV4; diff --git a/src/Symfony/Component/Validator/Constraints/Length.php b/src/Symfony/Component/Validator/Constraints/Length.php index 79aa473204eaf..245e59d2d177c 100644 --- a/src/Symfony/Component/Validator/Constraints/Length.php +++ b/src/Symfony/Component/Validator/Constraints/Length.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Validator\Constraints; use Symfony\Component\Validator\Constraint; +use Symfony\Component\Validator\Exception\InvalidArgumentException; use Symfony\Component\Validator\Exception\MissingOptionsException; /** @@ -39,6 +40,7 @@ class Length extends Constraint public $max; public $min; public $charset = 'UTF-8'; + public $normalizer; public function __construct($options = null) { @@ -54,5 +56,9 @@ public function __construct($options = null) if (null === $this->min && null === $this->max) { throw new MissingOptionsException(sprintf('Either option "min" or "max" must be given for constraint %s', __CLASS__), ['min', 'max']); } + + if (null !== $this->normalizer && !\is_callable($this->normalizer)) { + throw new InvalidArgumentException(sprintf('The "normalizer" option must be a valid callable ("%s" given).', \is_object($this->normalizer) ? \get_class($this->normalizer) : \gettype($this->normalizer))); + } } } diff --git a/src/Symfony/Component/Validator/Constraints/LengthValidator.php b/src/Symfony/Component/Validator/Constraints/LengthValidator.php index 2fb3dba7980f2..f3cf245cf41dd 100644 --- a/src/Symfony/Component/Validator/Constraints/LengthValidator.php +++ b/src/Symfony/Component/Validator/Constraints/LengthValidator.php @@ -40,6 +40,10 @@ public function validate($value, Constraint $constraint) $stringValue = (string) $value; + if (null !== $constraint->normalizer) { + $stringValue = ($constraint->normalizer)($stringValue); + } + if (!$invalidCharset = !@mb_check_encoding($stringValue, $constraint->charset)) { $length = mb_strlen($stringValue, $constraint->charset); } diff --git a/src/Symfony/Component/Validator/Constraints/NotBlank.php b/src/Symfony/Component/Validator/Constraints/NotBlank.php index c94f365500563..5a5b68556db08 100644 --- a/src/Symfony/Component/Validator/Constraints/NotBlank.php +++ b/src/Symfony/Component/Validator/Constraints/NotBlank.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Validator\Constraints; use Symfony\Component\Validator\Constraint; +use Symfony\Component\Validator\Exception\InvalidArgumentException; /** * @Annotation @@ -30,4 +31,14 @@ class NotBlank extends Constraint public $message = 'This value should not be blank.'; public $allowNull = false; + public $normalizer; + + public function __construct($options = null) + { + parent::__construct($options); + + if (null !== $this->normalizer && !\is_callable($this->normalizer)) { + throw new InvalidArgumentException(sprintf('The "normalizer" option must be a valid callable ("%s" given).', \is_object($this->normalizer) ? \get_class($this->normalizer) : \gettype($this->normalizer))); + } + } } diff --git a/src/Symfony/Component/Validator/Constraints/NotBlankValidator.php b/src/Symfony/Component/Validator/Constraints/NotBlankValidator.php index 31798f28bf84f..d358cc90f0410 100644 --- a/src/Symfony/Component/Validator/Constraints/NotBlankValidator.php +++ b/src/Symfony/Component/Validator/Constraints/NotBlankValidator.php @@ -34,6 +34,10 @@ public function validate($value, Constraint $constraint) return; } + if (\is_string($value) && null !== $constraint->normalizer) { + $value = ($constraint->normalizer)($value); + } + if (false === $value || (empty($value) && '0' != $value)) { $this->context->buildViolation($constraint->message) ->setParameter('{{ value }}', $this->formatValue($value)) diff --git a/src/Symfony/Component/Validator/Constraints/Regex.php b/src/Symfony/Component/Validator/Constraints/Regex.php index dc9e5ea8859d9..c621bcbdc31e8 100644 --- a/src/Symfony/Component/Validator/Constraints/Regex.php +++ b/src/Symfony/Component/Validator/Constraints/Regex.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Validator\Constraints; use Symfony\Component\Validator\Constraint; +use Symfony\Component\Validator\Exception\InvalidArgumentException; /** * @Annotation @@ -31,6 +32,16 @@ class Regex extends Constraint public $pattern; public $htmlPattern; public $match = true; + public $normalizer; + + public function __construct($options = null) + { + parent::__construct($options); + + if (null !== $this->normalizer && !\is_callable($this->normalizer)) { + throw new InvalidArgumentException(sprintf('The "normalizer" option must be a valid callable ("%s" given).', \is_object($this->normalizer) ? \get_class($this->normalizer) : \gettype($this->normalizer))); + } + } /** * {@inheritdoc} diff --git a/src/Symfony/Component/Validator/Constraints/RegexValidator.php b/src/Symfony/Component/Validator/Constraints/RegexValidator.php index b88a5b1909369..5b8be6ec1d2b1 100644 --- a/src/Symfony/Component/Validator/Constraints/RegexValidator.php +++ b/src/Symfony/Component/Validator/Constraints/RegexValidator.php @@ -43,6 +43,10 @@ public function validate($value, Constraint $constraint) $value = (string) $value; + if (null !== $constraint->normalizer) { + $value = ($constraint->normalizer)($value); + } + if ($constraint->match xor preg_match($constraint->pattern, $value)) { $this->context->buildViolation($constraint->message) ->setParameter('{{ value }}', $this->formatValue($value)) diff --git a/src/Symfony/Component/Validator/Constraints/Url.php b/src/Symfony/Component/Validator/Constraints/Url.php index 815d73be7cd09..45d21c8ae281b 100644 --- a/src/Symfony/Component/Validator/Constraints/Url.php +++ b/src/Symfony/Component/Validator/Constraints/Url.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Validator\Constraints; use Symfony\Component\Validator\Constraint; +use Symfony\Component\Validator\Exception\InvalidArgumentException; /** * @Annotation @@ -105,6 +106,7 @@ class Url extends Constraint */ public $checkDNS = self::CHECK_DNS_TYPE_NONE; public $relativeProtocol = false; + public $normalizer; public function __construct($options = null) { @@ -118,5 +120,9 @@ public function __construct($options = null) } parent::__construct($options); + + if (null !== $this->normalizer && !\is_callable($this->normalizer)) { + throw new InvalidArgumentException(sprintf('The "normalizer" option must be a valid callable ("%s" given).', \is_object($this->normalizer) ? \get_class($this->normalizer) : \gettype($this->normalizer))); + } } } diff --git a/src/Symfony/Component/Validator/Constraints/UrlValidator.php b/src/Symfony/Component/Validator/Constraints/UrlValidator.php index 20d8ded87069e..0786bb2087241 100644 --- a/src/Symfony/Component/Validator/Constraints/UrlValidator.php +++ b/src/Symfony/Component/Validator/Constraints/UrlValidator.php @@ -62,6 +62,10 @@ public function validate($value, Constraint $constraint) return; } + if (null !== $constraint->normalizer) { + $value = ($constraint->normalizer)($value); + } + $pattern = $constraint->relativeProtocol ? str_replace('(%s):', '(?:(%s):)?', static::PATTERN) : static::PATTERN; $pattern = sprintf($pattern, implode('|', $constraint->protocols)); diff --git a/src/Symfony/Component/Validator/Constraints/Uuid.php b/src/Symfony/Component/Validator/Constraints/Uuid.php index 988f3c3b2dfd9..006cae1282c30 100644 --- a/src/Symfony/Component/Validator/Constraints/Uuid.php +++ b/src/Symfony/Component/Validator/Constraints/Uuid.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Validator\Constraints; use Symfony\Component\Validator\Constraint; +use Symfony\Component\Validator\Exception\InvalidArgumentException; /** * @Annotation @@ -74,4 +75,15 @@ class Uuid extends Constraint self::V4_RANDOM, self::V5_SHA1, ]; + + public $normalizer; + + public function __construct($options = null) + { + parent::__construct($options); + + if (null !== $this->normalizer && !\is_callable($this->normalizer)) { + throw new InvalidArgumentException(sprintf('The "normalizer" option must be a valid callable ("%s" given).', \is_object($this->normalizer) ? \get_class($this->normalizer) : \gettype($this->normalizer))); + } + } } diff --git a/src/Symfony/Component/Validator/Constraints/UuidValidator.php b/src/Symfony/Component/Validator/Constraints/UuidValidator.php index 52cb71ddc0876..c5de675b1ca5a 100644 --- a/src/Symfony/Component/Validator/Constraints/UuidValidator.php +++ b/src/Symfony/Component/Validator/Constraints/UuidValidator.php @@ -81,6 +81,10 @@ public function validate($value, Constraint $constraint) $value = (string) $value; + if (null !== $constraint->normalizer) { + $value = ($constraint->normalizer)($value); + } + if ($constraint->strict) { $this->validateStrict($value, $constraint); diff --git a/src/Symfony/Component/Validator/Tests/Constraints/EmailTest.php b/src/Symfony/Component/Validator/Tests/Constraints/EmailTest.php index 8a19263e003c8..086e43faf8f81 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/EmailTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/EmailTest.php @@ -35,11 +35,36 @@ public function testConstructorStrict() } /** - * @expectedException \InvalidArgumentException + * @expectedException \Symfony\Component\Validator\Exception\InvalidArgumentException * @expectedExceptionMessage The "mode" parameter value is not valid. */ public function testUnknownModesTriggerException() { new Email(['mode' => 'Unknown Mode']); } + + public function testNormalizerCanBeSet() + { + $email = new Email(['normalizer' => 'trim']); + + $this->assertEquals('trim', $email->normalizer); + } + + /** + * @expectedException \Symfony\Component\Validator\Exception\InvalidArgumentException + * @expectedExceptionMessage The "normalizer" option must be a valid callable ("string" given). + */ + public function testInvalidNormalizerThrowsException() + { + new Email(['normalizer' => 'Unknown Callable']); + } + + /** + * @expectedException \Symfony\Component\Validator\Exception\InvalidArgumentException + * @expectedExceptionMessage The "normalizer" option must be a valid callable ("stdClass" given). + */ + public function testInvalidNormalizerObjectThrowsException() + { + new Email(['normalizer' => new \stdClass()]); + } } diff --git a/src/Symfony/Component/Validator/Tests/Constraints/EmailValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/EmailValidatorTest.php index 51b528d46fa9e..c2ac90112512e 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/EmailValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/EmailValidatorTest.php @@ -94,6 +94,28 @@ public function getValidEmails() ]; } + /** + * @dataProvider getValidEmailsWithWhitespaces + */ + public function testValidNormalizedEmails($email) + { + $this->validator->validate($email, new Email(['normalizer' => 'trim'])); + + $this->assertNoViolation(); + } + + public function getValidEmailsWithWhitespaces() + { + return [ + ["\x20example@example.co.uk\x20"], + ["\x09\x09example@example.co..uk\x09\x09"], + ["\x0A{}~!@!@£$%%^&*().!@£$%^&*()\x0A"], + ["\x0D\x0Dexample@example.co..uk\x0D\x0D"], + ["\x00example@-example.com"], + ["example@example.com\x0B\x0B"], + ]; + } + /** * @dataProvider getValidEmailsHtml5 */ diff --git a/src/Symfony/Component/Validator/Tests/Constraints/IpTest.php b/src/Symfony/Component/Validator/Tests/Constraints/IpTest.php new file mode 100644 index 0000000000000..9aa851604b80b --- /dev/null +++ b/src/Symfony/Component/Validator/Tests/Constraints/IpTest.php @@ -0,0 +1,46 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Tests\Constraints; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Validator\Constraints\Ip; + +/** + * @author Renan Taranto + */ +class IpTest extends TestCase +{ + public function testNormalizerCanBeSet() + { + $ip = new Ip(['normalizer' => 'trim']); + + $this->assertEquals('trim', $ip->normalizer); + } + + /** + * @expectedException \Symfony\Component\Validator\Exception\InvalidArgumentException + * @expectedExceptionMessage The "normalizer" option must be a valid callable ("string" given). + */ + public function testInvalidNormalizerThrowsException() + { + new Ip(['normalizer' => 'Unknown Callable']); + } + + /** + * @expectedException \Symfony\Component\Validator\Exception\InvalidArgumentException + * @expectedExceptionMessage The "normalizer" option must be a valid callable ("stdClass" given). + */ + public function testInvalidNormalizerObjectThrowsException() + { + new Ip(['normalizer' => new \stdClass()]); + } +} diff --git a/src/Symfony/Component/Validator/Tests/Constraints/IpValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/IpValidatorTest.php index 06b51c3ba2d11..e589053083911 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/IpValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/IpValidatorTest.php @@ -80,6 +80,31 @@ public function getValidIpsV4() ]; } + /** + * @dataProvider getValidIpsV4WithWhitespaces + */ + public function testValidIpsV4WithWhitespaces($ip) + { + $this->validator->validate($ip, new Ip([ + 'version' => Ip::V4, + 'normalizer' => 'trim', + ])); + + $this->assertNoViolation(); + } + + public function getValidIpsV4WithWhitespaces() + { + return [ + ["\x200.0.0.0"], + ["\x09\x0910.0.0.0"], + ["123.45.67.178\x0A"], + ["172.16.0.0\x0D\x0D"], + ["\x00192.168.1.0\x00"], + ["\x0B\x0B224.0.0.1\x0B\x0B"], + ]; + } + /** * @dataProvider getValidIpsV6 */ diff --git a/src/Symfony/Component/Validator/Tests/Constraints/LengthTest.php b/src/Symfony/Component/Validator/Tests/Constraints/LengthTest.php new file mode 100644 index 0000000000000..6a20ff541ffc2 --- /dev/null +++ b/src/Symfony/Component/Validator/Tests/Constraints/LengthTest.php @@ -0,0 +1,46 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Tests\Constraints; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Validator\Constraints\Length; + +/** + * @author Renan Taranto + */ +class LengthTest extends TestCase +{ + public function testNormalizerCanBeSet() + { + $length = new Length(['min' => 0, 'max' => 10, 'normalizer' => 'trim']); + + $this->assertEquals('trim', $length->normalizer); + } + + /** + * @expectedException \Symfony\Component\Validator\Exception\InvalidArgumentException + * @expectedExceptionMessage The "normalizer" option must be a valid callable ("string" given). + */ + public function testInvalidNormalizerThrowsException() + { + new Length(['min' => 0, 'max' => 10, 'normalizer' => 'Unknown Callable']); + } + + /** + * @expectedException \Symfony\Component\Validator\Exception\InvalidArgumentException + * @expectedExceptionMessage The "normalizer" option must be a valid callable ("stdClass" given). + */ + public function testInvalidNormalizerObjectThrowsException() + { + new Length(['min' => 0, 'max' => 10, 'normalizer' => new \stdClass()]); + } +} diff --git a/src/Symfony/Component/Validator/Tests/Constraints/LengthValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/LengthValidatorTest.php index d12874896cb64..628a102516d36 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/LengthValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/LengthValidatorTest.php @@ -92,6 +92,18 @@ public function getOneCharset() ]; } + public function getThreeCharactersWithWhitespaces() + { + return [ + ["\x20ccc"], + ["\x09c\x09c"], + ["\x0Accc\x0A"], + ["ccc\x0D\x0D"], + ["\x00ccc\x00"], + ["\x0Bc\x0Bc\x0B"], + ]; + } + /** * @dataProvider getFiveOrMoreCharacters */ @@ -125,6 +137,17 @@ public function testValidValuesExact($value) $this->assertNoViolation(); } + /** + * @dataProvider getThreeCharactersWithWhitespaces + */ + public function testValidNormalizedValues($value) + { + $constraint = new Length(['min' => 3, 'max' => 3, 'normalizer' => 'trim']); + $this->validator->validate($value, $constraint); + + $this->assertNoViolation(); + } + /** * @dataProvider getThreeOrLessCharacters */ diff --git a/src/Symfony/Component/Validator/Tests/Constraints/NotBlankTest.php b/src/Symfony/Component/Validator/Tests/Constraints/NotBlankTest.php new file mode 100644 index 0000000000000..af3b047fd8095 --- /dev/null +++ b/src/Symfony/Component/Validator/Tests/Constraints/NotBlankTest.php @@ -0,0 +1,46 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Tests\Constraints; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Validator\Constraints\NotBlank; + +/** + * @author Renan Taranto + */ +class NotBlankTest extends TestCase +{ + public function testNormalizerCanBeSet() + { + $notBlank = new NotBlank(['normalizer' => 'trim']); + + $this->assertEquals('trim', $notBlank->normalizer); + } + + /** + * @expectedException \Symfony\Component\Validator\Exception\InvalidArgumentException + * @expectedExceptionMessage The "normalizer" option must be a valid callable ("string" given). + */ + public function testInvalidNormalizerThrowsException() + { + new NotBlank(['normalizer' => 'Unknown Callable']); + } + + /** + * @expectedException \Symfony\Component\Validator\Exception\InvalidArgumentException + * @expectedExceptionMessage The "normalizer" option must be a valid callable ("stdClass" given). + */ + public function testInvalidNormalizerObjectThrowsException() + { + new NotBlank(['normalizer' => new \stdClass()]); + } +} diff --git a/src/Symfony/Component/Validator/Tests/Constraints/NotBlankValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/NotBlankValidatorTest.php index f46e017f9a700..3bf322052759a 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/NotBlankValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/NotBlankValidatorTest.php @@ -124,4 +124,34 @@ public function testAllowNullFalse() ->setCode(NotBlank::IS_BLANK_ERROR) ->assertRaised(); } + + /** + * @dataProvider getWhitespaces + */ + public function testNormalizedStringIsInvalid($value) + { + $constraint = new NotBlank([ + 'message' => 'myMessage', + 'normalizer' => 'trim', + ]); + + $this->validator->validate($value, $constraint); + + $this->buildViolation('myMessage') + ->setParameter('{{ value }}', '""') + ->setCode(NotBlank::IS_BLANK_ERROR) + ->assertRaised(); + } + + public function getWhitespaces() + { + return [ + ["\x20"], + ["\x09\x09"], + ["\x0A"], + ["\x0D\x0D"], + ["\x00"], + ["\x0B\x0B"], + ]; + } } diff --git a/src/Symfony/Component/Validator/Tests/Constraints/RegexTest.php b/src/Symfony/Component/Validator/Tests/Constraints/RegexTest.php index 8dc1e4af7dea8..53bb257d17496 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/RegexTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/RegexTest.php @@ -85,4 +85,29 @@ public function testGetCustomHtmlPattern() $this->assertSame('((?![0-9]$|[a-z]+).)*', $constraint->pattern); $this->assertSame('foobar', $constraint->getHtmlPattern()); } + + public function testNormalizerCanBeSet() + { + $regex = new Regex(['pattern' => '/^[0-9]+$/', 'normalizer' => 'trim']); + + $this->assertEquals('trim', $regex->normalizer); + } + + /** + * @expectedException \Symfony\Component\Validator\Exception\InvalidArgumentException + * @expectedExceptionMessage The "normalizer" option must be a valid callable ("string" given). + */ + public function testInvalidNormalizerThrowsException() + { + new Regex(['pattern' => '/^[0-9]+$/', 'normalizer' => 'Unknown Callable']); + } + + /** + * @expectedException \Symfony\Component\Validator\Exception\InvalidArgumentException + * @expectedExceptionMessage The "normalizer" option must be a valid callable ("stdClass" given). + */ + public function testInvalidNormalizerObjectThrowsException() + { + new Regex(['pattern' => '/^[0-9]+$/', 'normalizer' => new \stdClass()]); + } } diff --git a/src/Symfony/Component/Validator/Tests/Constraints/RegexValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/RegexValidatorTest.php index b67846f878047..9a54af88a8e72 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/RegexValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/RegexValidatorTest.php @@ -55,6 +55,17 @@ public function testValidValues($value) $this->assertNoViolation(); } + /** + * @dataProvider getValidValuesWithWhitespaces + */ + public function testValidValuesWithWhitespaces($value) + { + $constraint = new Regex(['pattern' => '/^[0-9]+$/', 'normalizer' => 'trim']); + $this->validator->validate($value, $constraint); + + $this->assertNoViolation(); + } + public function getValidValues() { return [ @@ -71,6 +82,18 @@ public function __toString() ]; } + public function getValidValuesWithWhitespaces() + { + return [ + ["\x207"], + ["\x09\x09070707\x09\x09"], + ["70707\x0A"], + ["7\x0D\x0D"], + ["\x00070707\x00"], + ["\x0B\x0B70707\x0B\x0B"], + ]; + } + /** * @dataProvider getInvalidValues */ diff --git a/src/Symfony/Component/Validator/Tests/Constraints/UrlTest.php b/src/Symfony/Component/Validator/Tests/Constraints/UrlTest.php new file mode 100644 index 0000000000000..6a9c45d417858 --- /dev/null +++ b/src/Symfony/Component/Validator/Tests/Constraints/UrlTest.php @@ -0,0 +1,46 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Tests\Constraints; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Validator\Constraints\Url; + +/** + * @author Renan Taranto + */ +class UrlTest extends TestCase +{ + public function testNormalizerCanBeSet() + { + $url = new Url(['normalizer' => 'trim']); + + $this->assertEquals('trim', $url->normalizer); + } + + /** + * @expectedException \Symfony\Component\Validator\Exception\InvalidArgumentException + * @expectedExceptionMessage The "normalizer" option must be a valid callable ("string" given). + */ + public function testInvalidNormalizerThrowsException() + { + new Url(['normalizer' => 'Unknown Callable']); + } + + /** + * @expectedException \Symfony\Component\Validator\Exception\InvalidArgumentException + * @expectedExceptionMessage The "normalizer" option must be a valid callable ("stdClass" given). + */ + public function testInvalidNormalizerObjectThrowsException() + { + new Url(['normalizer' => new \stdClass()]); + } +} diff --git a/src/Symfony/Component/Validator/Tests/Constraints/UrlValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/UrlValidatorTest.php index 47b723311311e..93e799d8b43dd 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/UrlValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/UrlValidatorTest.php @@ -65,6 +65,16 @@ public function testValidUrls($url) $this->assertNoViolation(); } + /** + * @dataProvider getValidUrlsWithWhitespaces + */ + public function testValidUrlsWithWhitespaces($url) + { + $this->validator->validate($url, new Url(['normalizer' => 'trim'])); + + $this->assertNoViolation(); + } + /** * @dataProvider getValidRelativeUrls * @dataProvider getValidUrls @@ -154,6 +164,18 @@ public function getValidUrls() ]; } + public function getValidUrlsWithWhitespaces() + { + return [ + ["\x20http://www.google.com"], + ["\x09\x09http://www.google.com."], + ["http://symfony.fake/blog/\x0A"], + ["http://symfony.com/search?type=&q=url+validator\x0D\x0D"], + ["\x00https://google.com:80\x00"], + ["\x0B\x0Bhttp://username:password@symfony.com\x0B\x0B"], + ]; + } + /** * @dataProvider getInvalidUrls */ diff --git a/src/Symfony/Component/Validator/Tests/Constraints/UuidTest.php b/src/Symfony/Component/Validator/Tests/Constraints/UuidTest.php new file mode 100644 index 0000000000000..bfe3d5ed800d3 --- /dev/null +++ b/src/Symfony/Component/Validator/Tests/Constraints/UuidTest.php @@ -0,0 +1,46 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Tests\Constraints; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Validator\Constraints\Uuid; + +/** + * @author Renan Taranto + */ +class UuidTest extends TestCase +{ + public function testNormalizerCanBeSet() + { + $uuid = new Uuid(['normalizer' => 'trim']); + + $this->assertEquals('trim', $uuid->normalizer); + } + + /** + * @expectedException \Symfony\Component\Validator\Exception\InvalidArgumentException + * @expectedExceptionMessage The "normalizer" option must be a valid callable ("string" given). + */ + public function testInvalidNormalizerThrowsException() + { + new Uuid(['normalizer' => 'Unknown Callable']); + } + + /** + * @expectedException \Symfony\Component\Validator\Exception\InvalidArgumentException + * @expectedExceptionMessage The "normalizer" option must be a valid callable ("stdClass" given). + */ + public function testInvalidNormalizerObjectThrowsException() + { + new Uuid(['normalizer' => new \stdClass()]); + } +} diff --git a/src/Symfony/Component/Validator/Tests/Constraints/UuidValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/UuidValidatorTest.php index aa1f351b23026..878e5d423479a 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/UuidValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/UuidValidatorTest.php @@ -85,6 +85,34 @@ public function getValidStrictUuids() ]; } + /** + * @dataProvider getValidStrictUuidsWithWhitespaces + */ + public function testValidStrictUuidsWithWhitespaces($uuid, $versions = null) + { + $constraint = new Uuid(['normalizer' => 'trim']); + + if (null !== $versions) { + $constraint->versions = $versions; + } + + $this->validator->validate($uuid, $constraint); + + $this->assertNoViolation(); + } + + public function getValidStrictUuidsWithWhitespaces() + { + return [ + ["\x20216fff40-98d9-11e3-a5e2-0800200c9a66"], // Version 1 UUID in lowercase + ["\x09\x09216fff40-98d9-11e3-a5e2-0800200c9a66", [Uuid::V1_MAC]], + ["216FFF40-98D9-11E3-A5E2-0800200C9A66\x0A"], // Version 1 UUID in UPPERCASE + ["456daefb-5aa6-41b5-8dbc-068b05a8b201\x0D\x0D"], // Version 4 UUID in lowercase + ["\x00456daEFb-5AA6-41B5-8DBC-068B05A8B201\x00"], // Version 4 UUID in mixed case + ["\x0B\x0B456daEFb-5AA6-41B5-8DBC-068B05A8B201\x0B\x0B", [Uuid::V4_RANDOM]], + ]; + } + /** * @dataProvider getInvalidStrictUuids */