Fix some issues with the "KeyValue" rule

There are a couple of issues with the "KeyValue" rule:

* When using it with "Not" it does not fetch the exception from the rule
  that it creates during the validation.

* It creates a "Validator" rule, which means that it creates two rules
  (Validator and the real rule) every time it validates an input.

This commit will fix these two issues and also create integration tests
that will ensure its behavior in case of change.

Co-authored-by: Danilo Correa <danilosilva87@gmail.com>
Signed-off-by: Henrique Moody <henriquemoody@gmail.com>
This commit is contained in:
Henrique Moody 2019-04-23 19:35:37 +02:00
parent d2d4728883
commit 2ac0aecf0c
No known key found for this signature in database
GPG key ID: 221E9281655813A6
8 changed files with 131 additions and 250 deletions

View file

@ -15,8 +15,8 @@ namespace Respect\Validation\Rules;
use Respect\Validation\Exceptions\ComponentException;
use Respect\Validation\Exceptions\ValidationException;
use Respect\Validation\Factory;
use Respect\Validation\Validatable;
use Respect\Validation\Validator;
use function array_keys;
use function in_array;
@ -57,18 +57,18 @@ final class KeyValue extends AbstractRule
private function getRule($input): Validatable
{
if (!isset($input[$this->comparedKey])) {
throw $this->reportError($this->comparedKey);
throw parent::reportError($this->comparedKey);
}
if (!isset($input[$this->baseKey])) {
throw $this->reportError($this->baseKey);
throw parent::reportError($this->baseKey);
}
try {
$rule = Validator::__callStatic($this->ruleName, [$input[$this->baseKey]]);
$rule = Factory::getDefaultInstance()->rule($this->ruleName, [$input[$this->baseKey]]);
$rule->setName($this->comparedKey);
} catch (ComponentException $exception) {
throw $this->reportError($input, ['component' => true]);
throw parent::reportError($input, ['component' => true]);
}
return $rule;
@ -132,4 +132,16 @@ final class KeyValue extends AbstractRule
return $rule->validate($input[$this->comparedKey]);
}
/**
* {@inheritDoc}
*/
public function reportError($input, array $extraParams = []): ValidationException
{
try {
return $this->overwriteExceptionParams($this->getRule($input)->reportError($input));
} catch (ValidationException $exception) {
return $this->overwriteExceptionParams($exception);
}
}
}

View file

@ -0,0 +1,87 @@
--CREDITS--
Danilo Correa <danilosilva87@gmail.com>
Edson Lima <dddwebdeveloper@gmail.com>
Henrique Moody <henriquemoody@gmail.com>
Ian Nisbet <ian@glutenite.co.uk>
--FILE--
<?php
declare(strict_types=1);
require 'vendor/autoload.php';
use Respect\Validation\Exceptions\NestedValidationException;
use Respect\Validation\Exceptions\ValidationException;
use Respect\Validation\Validator as v;
try {
v::keyValue('foo', 'equals', 'bar')->check(['bar' => 42]);
} catch (ValidationException $exception) {
echo $exception->getMessage().PHP_EOL;
}
try {
v::keyValue('foo', 'equals', 'bar')->check(['foo' => 42]);
} catch (ValidationException $exception) {
echo $exception->getMessage().PHP_EOL;
}
try {
v::keyValue('foo', 'json', 'bar')->check(['foo' => 42, 'bar' => 43]);
} catch (ValidationException $exception) {
echo $exception->getMessage().PHP_EOL;
}
try {
v::keyValue('foo', 'equals', 'bar')->check(['foo' => 1, 'bar' => 2]);
} catch (ValidationException $exception) {
echo $exception->getMessage().PHP_EOL;
}
try {
v::not(v::keyValue('foo', 'equals', 'bar'))->check(['foo' => 1, 'bar' => 1]);
} catch (ValidationException $exception) {
echo $exception->getMessage().PHP_EOL;
}
try {
v::keyValue('foo', 'equals', 'bar')->assert(['bar' => 42]);
} catch (NestedValidationException $exception) {
echo $exception->getFullMessage().PHP_EOL;
}
try {
v::keyValue('foo', 'equals', 'bar')->assert(['foo' => 42]);
} catch (NestedValidationException $exception) {
echo $exception->getFullMessage().PHP_EOL;
}
try {
v::keyValue('foo', 'json', 'bar')->assert(['foo' => 42, 'bar' => 43]);
} catch (NestedValidationException $exception) {
echo $exception->getFullMessage().PHP_EOL;
}
try {
v::keyValue('foo', 'equals', 'bar')->assert(['foo' => 1, 'bar' => 2]);
} catch (NestedValidationException $exception) {
echo $exception->getFullMessage().PHP_EOL;
}
try {
v::not(v::keyValue('foo', 'equals', 'bar'))->assert(['foo' => 1, 'bar' => 1]);
} catch (NestedValidationException $exception) {
echo $exception->getFullMessage().PHP_EOL;
}
?>
--EXPECT--
Key "foo" must be present
Key "bar" must be present
"bar" must be valid to validate "foo"
foo must equal "bar"
foo must not equal "bar"
- Key "foo" must be present
- Key "bar" must be present
- "bar" must be valid to validate "foo"
- foo must equal "bar"
- foo must not equal "bar"

View file

@ -1,22 +0,0 @@
--CREDITS--
Edson Lima <dddwebdeveloper@gmail.com>
Henrique Moody <henriquemoody@gmail.com>
--FILE--
<?php
declare(strict_types=1);
require 'vendor/autoload.php';
use Respect\Validation\Validator as v;
$data = [
'password' => 'shuberry',
'password_confirmation' => 'shuberry',
'valid_passwords' => ['shuberry', 'monty-python'],
];
v::keyValue('password', 'equals', 'password_confirmation')->check($data);
v::keyValue('password', 'in', 'valid_passwords')->assert($data);
?>
--EXPECT--

View file

@ -1,27 +0,0 @@
--CREDITS--
Edson Lima <dddwebdeveloper@gmail.com>
Henrique Moody <henriquemoody@gmail.com>
Ian Nisbet <ian@glutenite.co.uk>
--FILE--
<?php
declare(strict_types=1);
require 'vendor/autoload.php';
use Respect\Validation\Exceptions\EqualsException;
use Respect\Validation\Validator as v;
$data = [
'password' => 'shuberry',
'password_confirmation' => '_shuberry_',
];
try {
v::keyValue('password', 'equals', 'password_confirmation')->check($data);
} catch (EqualsException $e) {
echo $e->getMessage();
}
?>
--EXPECT--
password must equal "password_confirmation"

View file

@ -1,26 +0,0 @@
--CREDITS--
Edson Lima <dddwebdeveloper@gmail.com>
Henrique Moody <henriquemoody@gmail.com>
--FILE--
<?php
declare(strict_types=1);
require 'vendor/autoload.php';
use Respect\Validation\Exceptions\AllOfException;
use Respect\Validation\Validator as v;
$data = [
'password' => 'shazam',
'password_confirmation' => 'batman',
];
try {
v::keyValue('password', 'equals', 'password_confirmation')->assert($data);
} catch (AllOfException $e) {
echo $e->getMessage();
}
?>
--EXPECT--
All of the required rules must pass for `{ "password": "shazam", "password_confirmation": "batman" }`

View file

@ -1,25 +0,0 @@
--CREDITS--
Edson Lima <dddwebdeveloper@gmail.com>
Henrique Moody <henriquemoody@gmail.com>
--FILE--
<?php
declare(strict_types=1);
require 'vendor/autoload.php';
use Respect\Validation\Validator as v;
$data = [
'password' => '123',
'invalid_passwords' => ['123', 'secreta'],
];
try {
v::not(v::keyValue('password', 'in', 'invalid_passwords'))->check($data);
} catch (Throwable $e) {
echo $e->getMessage();
}
?>
--EXPECT--
Key `{ "password": "123", "invalid_passwords": { "123", "secreta" } }` must not be present

View file

@ -1,26 +0,0 @@
--CREDITS--
Edson Lima <dddwebdeveloper@gmail.com>
Henrique Moody <henriquemoody@gmail.com>
--FILE--
<?php
declare(strict_types=1);
require 'vendor/autoload.php';
use Respect\Validation\Exceptions\AllOfException;
use Respect\Validation\Validator as v;
$data = [
'password' => '123',
'invalid_passwords' => ['123', 'secreta'],
];
try {
v::not(v::keyValue('password', 'in', 'invalid_passwords'))->assert($data);
} catch (AllOfException $e) {
echo $e->getFullMessage();
}
?>
--EXPECT--
- Key `{ "password": "123", "invalid_passwords": { "123", "secreta" } }` must not be present

View file

@ -13,140 +13,48 @@ declare(strict_types=1);
namespace Respect\Validation\Rules;
use Respect\Validation\Test\TestCase;
use Respect\Validation\Test\RuleTestCase;
/**
* @group rule
* @covers \Respect\Validation\Exceptions\KeyValueException
* @group rule
*
* @covers \Respect\Validation\Rules\KeyValue
*
* @author Gabriel Caruso <carusogabriel34@gmail.com>
* @author Danilo Correa <danilosilva87@gmail.com>
* @author Henrique Moody <henriquemoody@gmail.com>
* @author Ian Nisbet <ian@glutenite.co.uk>
*/
final class KeyValueTest extends TestCase
final class KeyValueTest extends RuleTestCase
{
/**
* @test
* {@inheritdoc}
*/
public function shouldDefineValuesOnConstructor(): void
public function providerForValidInput(): array
{
$comparedKey = 'foo';
$ruleName = 'equals';
$baseKey = 'bar';
$rule = new KeyValue($comparedKey, $ruleName, $baseKey);
self::assertAttributeSame($comparedKey, 'comparedKey', $rule);
self::assertAttributeSame($ruleName, 'ruleName', $rule);
self::assertAttributeSame($baseKey, 'baseKey', $rule);
return [
'Equal values' => [new KeyValue('foo', 'equals', 'bar'), ['foo' => 42, 'bar' => 42]],
'A value contained in an array' => [
new KeyValue('password', 'in', 'valid_passwords'),
[
'password' => 'shuberry',
'password_confirmation' => 'shuberry',
'valid_passwords' => ['shuberry', 'monty-python'],
],
],
];
}
/**
* @test
* {@inheritdoc}
*/
public function shouldNotValidateWhenComparedKeyDoesNotExist(): void
public function providerForInvalidInput(): array
{
$rule = new KeyValue('foo', 'equals', 'bar');
$keyValue = new KeyValue('foo', 'equals', 'bar');
self::assertFalse($rule->validate(['bar' => 42]));
}
/**
* @test
*/
public function shouldNotValidateWhenBaseKeyDoesNotExist(): void
{
$rule = new KeyValue('foo', 'equals', 'bar');
self::assertFalse($rule->validate(['foo' => true]));
}
/**
* @test
*/
public function shouldNotValidateRuleIsNotValid(): void
{
$rule = new KeyValue('foo', 'probably_not_a_rule', 'bar');
self::assertFalse($rule->validate(['foo' => true, 'bar' => false]));
}
/**
* @test
*/
public function shouldValidateWhenDefinedValuesMatch(): void
{
$rule = new KeyValue('foo', 'equals', 'bar');
self::assertTrue($rule->validate(['foo' => 42, 'bar' => 42]));
}
/**
* @test
*/
public function shouldValidateWhenDefinedValuesDoesNotMatch(): void
{
$rule = new KeyValue('foo', 'equals', 'bar');
self::assertFalse($rule->validate(['foo' => 43, 'bar' => 42]));
}
/**
* @doesNotPerformAssertions
*
* @test
*/
public function shouldAssertWhenDefinedValuesMatch(): void
{
$rule = new KeyValue('foo', 'equals', 'bar');
$rule->assert(['foo' => 42, 'bar' => 42]);
}
/**
* @expectedException \Respect\Validation\Exceptions\AllOfException
* @expectedExceptionMessage All of the required rules must pass for foo
*
* @test
*/
public function shouldAssertWhenDefinedValuesDoesNotMatch(): void
{
$rule = new KeyValue('foo', 'equals', 'bar');
$rule->assert(['foo' => 43, 'bar' => 42]);
}
/**
* @expectedException \Respect\Validation\Exceptions\KeyValueException
* @expectedExceptionMessage "bar" must be valid to validate "foo"
*
* @test
*/
public function shouldNotAssertWhenRuleIsNotValid(): void
{
$rule = new KeyValue('foo', 'probably_not_a_rule', 'bar');
$rule->assert(['foo' => 43, 'bar' => 42]);
}
/**
* @doesNotPerformAssertions
*
* @test
*/
public function shouldCheckWhenDefinedValuesMatch(): void
{
$rule = new KeyValue('foo', 'equals', 'bar');
$rule->check(['foo' => 42, 'bar' => 42]);
}
/**
* @expectedException \Respect\Validation\Exceptions\EqualsException
* @expectedExceptionMessage foo must equal "bar"
*
* @test
*/
public function shouldCheckWhenDefinedValuesDoesNotMatch(): void
{
$rule = new KeyValue('foo', 'equals', 'bar');
$rule->check(['foo' => 43, 'bar' => 42]);
return [
'Different values' => [$keyValue, ['foo' => 43, 'bar' => 42]],
'Comparison key does not exist' => [$keyValue, ['bar' => 42]],
'Base key does not exist' => [$keyValue, ['foo' => true]],
'Rule is not valid' => [new KeyValue('foo', 'probably_not_a_rule', 'bar'), ['foo' => true, 'bar' => false]],
];
}
}