mirror of
https://github.com/Respect/Validation.git
synced 2024-06-08 00:32:16 +02:00
Split "Key" rules
Currently, the Key rule has a third parameter that allows the validation of the wrapped rule to be optional, meaning that the validation will only happen if the key exists. That parameter makes the rule harder to understand at times. I'm splitting the Key rule into Key, KeyExists, and KeyOptional. That way, it becomes apparent when someone wants only to validate whether a key exists or if they're going to validate the value of the key only when it exists. I deliberately didn't create an abstract class because those rules are different enough not to have an abstraction. In fact, I can see myself deleting the "AbstractRelated" in the upcoming changes. With these changes, the KeySet rule will not accept validating if the key exists or validating the value only if the key exists. I should refactor that soon, and I will likely need to create a common interface for Key, KeyExists, and KeyOptional. Signed-off-by: Henrique Moody <henriquemoody@gmail.com>
This commit is contained in:
parent
c946f16f60
commit
a647a4737b
|
@ -10,7 +10,9 @@
|
|||
- [EndsWith](rules/EndsWith.md)
|
||||
- [In](rules/In.md)
|
||||
- [Key](rules/Key.md)
|
||||
- [KeyExists](rules/KeyExists.md)
|
||||
- [KeyNested](rules/KeyNested.md)
|
||||
- [KeyOptional](rules/KeyOptional.md)
|
||||
- [KeySet](rules/KeySet.md)
|
||||
- [Sorted](rules/Sorted.md)
|
||||
- [StartsWith](rules/StartsWith.md)
|
||||
|
@ -242,7 +244,9 @@
|
|||
## Structures
|
||||
|
||||
- [Key](rules/Key.md)
|
||||
- [KeyExists](rules/KeyExists.md)
|
||||
- [KeyNested](rules/KeyNested.md)
|
||||
- [KeyOptional](rules/KeyOptional.md)
|
||||
- [KeySet](rules/KeySet.md)
|
||||
- [Property](rules/Property.md)
|
||||
|
||||
|
@ -349,7 +353,9 @@
|
|||
- [IterableVal](rules/IterableVal.md)
|
||||
- [Json](rules/Json.md)
|
||||
- [Key](rules/Key.md)
|
||||
- [KeyExists](rules/KeyExists.md)
|
||||
- [KeyNested](rules/KeyNested.md)
|
||||
- [KeyOptional](rules/KeyOptional.md)
|
||||
- [KeySet](rules/KeySet.md)
|
||||
- [LanguageCode](rules/LanguageCode.md)
|
||||
- [LazyConsecutive](rules/LazyConsecutive.md)
|
||||
|
|
|
@ -32,6 +32,8 @@ See also:
|
|||
- [IntType](IntType.md)
|
||||
- [IterableType](IterableType.md)
|
||||
- [IterableVal](IterableVal.md)
|
||||
- [KeyExists](KeyExists.md)
|
||||
- [KeyOptional](KeyOptional.md)
|
||||
- [NullType](NullType.md)
|
||||
- [ObjectType](ObjectType.md)
|
||||
- [ResourceType](ResourceType.md)
|
||||
|
|
|
@ -35,6 +35,8 @@ See also:
|
|||
- [IterableType](IterableType.md)
|
||||
- [IterableVal](IterableVal.md)
|
||||
- [Key](Key.md)
|
||||
- [KeyExists](KeyExists.md)
|
||||
- [KeyOptional](KeyOptional.md)
|
||||
- [KeySet](KeySet.md)
|
||||
- [ScalarVal](ScalarVal.md)
|
||||
- [Sorted](Sorted.md)
|
||||
|
|
|
@ -33,7 +33,8 @@ Using `v::call()` you can do this in a single chain:
|
|||
```php
|
||||
v::call(
|
||||
'parse_url',
|
||||
v::arrayVal()->key('scheme', v::startsWith('http'))
|
||||
v::arrayVal()
|
||||
->key('scheme', v::startsWith('http'))
|
||||
->key('host', v::domain())
|
||||
->key('path', v::stringType())
|
||||
->key('query', v::notEmpty())
|
||||
|
|
|
@ -47,6 +47,8 @@ See also:
|
|||
- [IterableType](IterableType.md)
|
||||
- [IterableVal](IterableVal.md)
|
||||
- [Key](Key.md)
|
||||
- [KeyExists](KeyExists.md)
|
||||
- [KeyOptional](KeyOptional.md)
|
||||
- [Min](Min.md)
|
||||
- [NotEmpty](NotEmpty.md)
|
||||
- [Unique](Unique.md)
|
||||
|
|
|
@ -1,33 +1,32 @@
|
|||
# Key
|
||||
|
||||
- `Key(mixed $key)`
|
||||
- `Key(mixed $key, Validatable $rule)`
|
||||
- `Key(mixed $key, Validatable $rule, bool $mandatory)`
|
||||
- `Key(int|string $key, Validatable $rule)`
|
||||
|
||||
Validates an array key.
|
||||
Validates the value of an array against a given rule.
|
||||
|
||||
```php
|
||||
$dict = [
|
||||
'foo' => 'bar'
|
||||
];
|
||||
v::key('name', v::stringType())->validate(['name' => 'The Respect Panda']); // true
|
||||
|
||||
v::key('foo')->validate($dict); // true
|
||||
```
|
||||
v::key('email', v::email())->validate(['email' => 'therespectpanda@gmail.com']); // true
|
||||
|
||||
You can also validate the key value itself:
|
||||
|
||||
```php
|
||||
v::key('foo', v::equals('bar'))->validate($dict); // true
|
||||
```
|
||||
|
||||
Third parameter makes the key presence optional:
|
||||
|
||||
```php
|
||||
v::key('lorem', v::stringType(), false)->validate($dict); // true
|
||||
v::key('age', v::intVal())->validate([]); // false
|
||||
```
|
||||
|
||||
The name of this validator is automatically set to the key name.
|
||||
|
||||
```php
|
||||
v::key('email', v::email())->assert([]);
|
||||
// message: email must be present
|
||||
|
||||
v::key('email', v::email())->assert(['email' => 'not email']);
|
||||
// message: email must be valid email
|
||||
```
|
||||
|
||||
## Note
|
||||
|
||||
* To validate if a key exists, use [KeyExists](KeyExists.md) instead.
|
||||
* To validate an array against a given rule if the key exists, use [KeyOptional](KeyOptional.md) instead.
|
||||
|
||||
## Categorization
|
||||
|
||||
- Arrays
|
||||
|
@ -36,15 +35,18 @@ The name of this validator is automatically set to the key name.
|
|||
|
||||
## Changelog
|
||||
|
||||
Version | Description
|
||||
--------|-------------
|
||||
0.3.9 | Created
|
||||
| Version | Description |
|
||||
|--------:|----------------------------------------------------------------------|
|
||||
| 3.0.0 | Split by [KeyExists](KeyExists.md) and [KeyOptional](KeyOptional.md) |
|
||||
| 0.3.9 | Created |
|
||||
|
||||
***
|
||||
See also:
|
||||
|
||||
- [ArrayVal](ArrayVal.md)
|
||||
- [Each](Each.md)
|
||||
- [KeyExists](KeyExists.md)
|
||||
- [KeyNested](KeyNested.md)
|
||||
- [KeyOptional](KeyOptional.md)
|
||||
- [KeySet](KeySet.md)
|
||||
- [Property](Property.md)
|
||||
|
|
43
docs/rules/KeyExists.md
Normal file
43
docs/rules/KeyExists.md
Normal file
|
@ -0,0 +1,43 @@
|
|||
# KeyExists
|
||||
|
||||
- `KeyExists(int|string $key)`
|
||||
|
||||
Validates if the given key exists in an array.
|
||||
|
||||
```php
|
||||
v::keyExists('name')->validate(['name' => 'The Respect Panda']); // true
|
||||
v::keyExists('name')->validate(['email' => 'therespectpanda@gmail.com']); // false
|
||||
|
||||
v::keyExists(0)->validate(['a', 'b', 'c']); // true
|
||||
v::keyExists(4)->validate(['a', 'b', 'c']); // false
|
||||
|
||||
v::keyExists('username')->validate(new ArrayObject(['username' => 'therespectpanda'])); // true
|
||||
v::keyExists(5)->validate(new ArrayObject(['a', 'b', 'c'])); // false
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
* To validate an array against a given rule if the key exists, use [KeyOptional](KeyOptional.md) instead.
|
||||
* To validate an array against a given rule requiring the key to exist, use [Key](Key.md) instead.
|
||||
|
||||
## Categorization
|
||||
|
||||
- Arrays
|
||||
- Structures
|
||||
|
||||
## Changelog
|
||||
|
||||
| Version | Description |
|
||||
| ------: |----------------------------|
|
||||
| 3.0.0 | Created from [Key](Key.md) |
|
||||
|
||||
***
|
||||
See also:
|
||||
|
||||
- [ArrayType](ArrayType.md)
|
||||
- [ArrayVal](ArrayVal.md)
|
||||
- [Each](Each.md)
|
||||
- [Key](Key.md)
|
||||
- [KeyOptional](KeyOptional.md)
|
||||
- [Property](Property.md)
|
||||
|
60
docs/rules/KeyOptional.md
Normal file
60
docs/rules/KeyOptional.md
Normal file
|
@ -0,0 +1,60 @@
|
|||
# KeyOptional
|
||||
|
||||
- `KeyOptional(int|string $key, Validatable $rule)`
|
||||
|
||||
Validates the value of an array against a given rule when the key exists.
|
||||
|
||||
```php
|
||||
v::keyOptional('name', v::stringType())->validate([]); // true
|
||||
v::keyOptional('name', v::stringType())->validate(['name' => 'The Respect Panda']); // true
|
||||
|
||||
v::keyOptional('email', v::email())->validate([]); // true
|
||||
v::keyOptional('email', v::email())->validate(['email' => 'therespectpanda@gmail.com']); // true
|
||||
|
||||
v::keyOptional('age', v::intVal())->validate(['age' => 'Twenty-Five']); // false
|
||||
```
|
||||
|
||||
The name of this validator is automatically set to the key name.
|
||||
|
||||
```php
|
||||
v::keyOptional('age', v::intVal())->assert(['age' => 'Twenty-Five']);
|
||||
// message: age must be an integer number
|
||||
```
|
||||
|
||||
## Note
|
||||
|
||||
This rule will pass for anything that is not an array because it will always pass when it doesn't find a key. If you
|
||||
want to ensure the input is an array, use [ArrayType](ArrayType.md) with it.
|
||||
|
||||
```php
|
||||
v::arrayType()->keyOptional('phone', v::phone())->assert('This is not an array');
|
||||
// message: "This is not an array" must be of type array
|
||||
```
|
||||
|
||||
Below are some other rules that are tightly related to `KeyOptional`:
|
||||
|
||||
* To validate if a key exists, use [KeyExists](KeyExists.md) instead.
|
||||
* To validate an array against a given rule requiring the key to exist, use [Key](Key.md) instead.
|
||||
|
||||
## Categorization
|
||||
|
||||
- Arrays
|
||||
- Structures
|
||||
|
||||
## Changelog
|
||||
|
||||
| Version | Description |
|
||||
| ------: |----------------------------|
|
||||
| 3.0.0 | Created from [Key](Key.md) |
|
||||
***
|
||||
See also:
|
||||
|
||||
- [ArrayType](ArrayType.md)
|
||||
- [ArrayVal](ArrayVal.md)
|
||||
- [Each](Each.md)
|
||||
- [Key](Key.md)
|
||||
- [KeyExists](KeyExists.md)
|
||||
- [Property](Property.md)
|
||||
|
||||
[array]: https://www.php.net/array
|
||||
[ArrayAccess]: https://www.php.net/arrayaccess
|
|
@ -44,5 +44,7 @@ Version | Description
|
|||
See also:
|
||||
|
||||
- [Key](Key.md)
|
||||
- [KeyExists](KeyExists.md)
|
||||
- [KeyNested](KeyNested.md)
|
||||
- [KeyOptional](KeyOptional.md)
|
||||
- [ObjectType](ObjectType.md)
|
||||
|
|
|
@ -164,11 +164,11 @@ interface ChainedValidator extends Validatable
|
|||
|
||||
public function json(): ChainedValidator;
|
||||
|
||||
public function key(
|
||||
string $reference,
|
||||
?Validatable $referenceValidator = null,
|
||||
bool $mandatory = true
|
||||
): ChainedValidator;
|
||||
public function key(int|string $key, Validatable $rule): ChainedValidator;
|
||||
|
||||
public function keyExists(int|string $key): ChainedValidator;
|
||||
|
||||
public function keyOptional(int|string $key, Validatable $rule): ChainedValidator;
|
||||
|
||||
public function keyNested(
|
||||
string $reference,
|
||||
|
|
|
@ -166,11 +166,11 @@ interface StaticValidator
|
|||
|
||||
public static function json(): ChainedValidator;
|
||||
|
||||
public static function key(
|
||||
string $reference,
|
||||
?Validatable $referenceValidator = null,
|
||||
bool $mandatory = true
|
||||
): ChainedValidator;
|
||||
public static function key(int|string $key, Validatable $rule): ChainedValidator;
|
||||
|
||||
public static function keyExists(int|string $key): ChainedValidator;
|
||||
|
||||
public static function keyOptional(int|string $key, Validatable $rule): ChainedValidator;
|
||||
|
||||
public static function keyNested(
|
||||
string $reference,
|
||||
|
|
|
@ -9,45 +9,39 @@ declare(strict_types=1);
|
|||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use Respect\Validation\Attributes\ExceptionClass;
|
||||
use Respect\Validation\Exceptions\ComponentException;
|
||||
use Respect\Validation\Exceptions\NonOmissibleValidationException;
|
||||
use Respect\Validation\Message\Template;
|
||||
use Respect\Validation\Helpers\CanBindEvaluateRule;
|
||||
use Respect\Validation\Result;
|
||||
use Respect\Validation\Rules\Core\Wrapper;
|
||||
use Respect\Validation\Validatable;
|
||||
|
||||
use function array_key_exists;
|
||||
use function is_array;
|
||||
use function is_scalar;
|
||||
|
||||
#[ExceptionClass(NonOmissibleValidationException::class)]
|
||||
#[Template(
|
||||
'{{name}} must be present',
|
||||
'{{name}} must not be present',
|
||||
self::TEMPLATE_NOT_PRESENT,
|
||||
)]
|
||||
#[Template(
|
||||
'{{name}} must be valid',
|
||||
'{{name}} must not be valid',
|
||||
self::TEMPLATE_INVALID,
|
||||
)]
|
||||
final class Key extends AbstractRelated
|
||||
final class Key extends Wrapper
|
||||
{
|
||||
public function __construct(mixed $reference, ?Validatable $rule = null, bool $mandatory = true)
|
||||
use CanBindEvaluateRule;
|
||||
|
||||
public function __construct(
|
||||
private readonly int|string $key,
|
||||
Validatable $rule,
|
||||
) {
|
||||
$rule->setName($rule->getName() ?? (string) $key);
|
||||
parent::__construct($rule);
|
||||
}
|
||||
|
||||
public function getKey(): int|string
|
||||
{
|
||||
if (!is_scalar($reference) || $reference === '') {
|
||||
throw new ComponentException('Invalid array key name');
|
||||
return $this->key;
|
||||
}
|
||||
|
||||
public function evaluate(mixed $input): Result
|
||||
{
|
||||
$keyExistsResult = $this->bindEvaluate(new KeyExists($this->key), $this, $input);
|
||||
if (!$keyExistsResult->isValid) {
|
||||
return $keyExistsResult;
|
||||
}
|
||||
|
||||
parent::__construct($reference, $rule, $mandatory);
|
||||
}
|
||||
$child = $this->rule->evaluate($input[$this->key]);
|
||||
|
||||
public function getReferenceValue(mixed $input): mixed
|
||||
{
|
||||
return $input[$this->getReference()];
|
||||
}
|
||||
|
||||
public function hasReference(mixed $input): bool
|
||||
{
|
||||
return is_array($input) && array_key_exists($this->getReference(), $input);
|
||||
return (new Result($child->isValid, $input, $this))
|
||||
->withChildren($child)
|
||||
->withNameIfMissing($this->rule->getName() ?? (string) $this->key);
|
||||
}
|
||||
}
|
||||
|
|
39
library/Rules/KeyExists.php
Normal file
39
library/Rules/KeyExists.php
Normal file
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use Respect\Validation\Message\Template;
|
||||
use Respect\Validation\Result;
|
||||
use Respect\Validation\Rules\Core\Standard;
|
||||
|
||||
use function array_key_exists;
|
||||
use function is_array;
|
||||
|
||||
#[Template(
|
||||
'{{name}} must be present',
|
||||
'{{name}} must not be present',
|
||||
)]
|
||||
final class KeyExists extends Standard
|
||||
{
|
||||
public function __construct(
|
||||
private readonly int|string $key
|
||||
) {
|
||||
}
|
||||
|
||||
public function evaluate(mixed $input): Result
|
||||
{
|
||||
return new Result($this->hasKey($input), $input, $this, name: (string) $this->key);
|
||||
}
|
||||
|
||||
private function hasKey(mixed $input): bool
|
||||
{
|
||||
return is_array($input) && array_key_exists($this->key, $input);
|
||||
}
|
||||
}
|
42
library/Rules/KeyOptional.php
Normal file
42
library/Rules/KeyOptional.php
Normal file
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use Respect\Validation\Helpers\CanBindEvaluateRule;
|
||||
use Respect\Validation\Result;
|
||||
use Respect\Validation\Rules\Core\Wrapper;
|
||||
use Respect\Validation\Validatable;
|
||||
|
||||
final class KeyOptional extends Wrapper
|
||||
{
|
||||
use CanBindEvaluateRule;
|
||||
|
||||
public function __construct(
|
||||
private readonly int|string $key,
|
||||
Validatable $rule,
|
||||
) {
|
||||
$rule->setName($rule->getName() ?? (string) $key);
|
||||
parent::__construct($rule);
|
||||
}
|
||||
|
||||
public function evaluate(mixed $input): Result
|
||||
{
|
||||
$keyExistsResult = $this->bindEvaluate(new KeyExists($this->key), $this, $input);
|
||||
if (!$keyExistsResult->isValid) {
|
||||
return $keyExistsResult->withInvertedMode();
|
||||
}
|
||||
|
||||
$child = $this->rule->evaluate($input[$this->key]);
|
||||
|
||||
return (new Result($child->isValid, $input, $this))
|
||||
->withChildren($child)
|
||||
->withNameIfMissing($this->rule->getName() ?? (string) $this->key);
|
||||
}
|
||||
}
|
|
@ -49,7 +49,7 @@ final class KeySet extends Wrapper
|
|||
/** @var array<Key> $keyRules */
|
||||
$keyRules = $this->extractMany(array_merge([$rule], $rules), Key::class);
|
||||
|
||||
$this->keys = array_map(static fn(Key $keyRule) => $keyRule->getReference(), $keyRules);
|
||||
$this->keys = array_map(static fn(Key $keyRule) => $keyRule->getKey(), $keyRules);
|
||||
|
||||
parent::__construct(count($keyRules) === 1 ? $keyRules[0] : new AllOf(...$keyRules));
|
||||
}
|
||||
|
|
|
@ -12,20 +12,18 @@ exceptionFullMessage(static function (): void {
|
|||
->key(
|
||||
'mysql',
|
||||
v::create()
|
||||
->key('host', v::stringType(), true)
|
||||
->key('user', v::stringType(), true)
|
||||
->key('password', v::stringType(), true)
|
||||
->key('schema', v::stringType(), true),
|
||||
true
|
||||
->key('host', v::stringType())
|
||||
->key('user', v::stringType())
|
||||
->key('password', v::stringType())
|
||||
->key('schema', v::stringType())
|
||||
)
|
||||
->key(
|
||||
'postgresql',
|
||||
v::create()
|
||||
->key('host', v::stringType(), true)
|
||||
->key('user', v::stringType(), true)
|
||||
->key('password', v::stringType(), true)
|
||||
->key('schema', v::stringType(), true),
|
||||
true
|
||||
->key('host', v::stringType())
|
||||
->key('user', v::stringType())
|
||||
->key('password', v::stringType())
|
||||
->key('schema', v::stringType())
|
||||
)
|
||||
->setName('the given data')
|
||||
->assert([
|
||||
|
|
|
@ -12,20 +12,18 @@ exceptionMessages(static function (): void {
|
|||
->key(
|
||||
'mysql',
|
||||
v::create()
|
||||
->key('host', v::stringType(), true)
|
||||
->key('user', v::stringType(), true)
|
||||
->key('password', v::stringType(), true)
|
||||
->key('schema', v::stringType(), true),
|
||||
true
|
||||
->key('host', v::stringType())
|
||||
->key('user', v::stringType())
|
||||
->key('password', v::stringType())
|
||||
->key('schema', v::stringType())
|
||||
)
|
||||
->key(
|
||||
'postgresql',
|
||||
v::create()
|
||||
->key('host', v::stringType(), true)
|
||||
->key('user', v::stringType(), true)
|
||||
->key('password', v::stringType(), true)
|
||||
->key('schema', v::stringType(), true),
|
||||
true
|
||||
->key('host', v::stringType())
|
||||
->key('user', v::stringType())
|
||||
->key('password', v::stringType())
|
||||
->key('schema', v::stringType())
|
||||
)
|
||||
->assert([
|
||||
'mysql' => [
|
||||
|
|
|
@ -13,20 +13,18 @@ exceptionMessages(
|
|||
->key(
|
||||
'mysql',
|
||||
v::create()
|
||||
->key('host', v::stringType(), true)
|
||||
->key('user', v::stringType(), true)
|
||||
->key('password', v::stringType(), true)
|
||||
->key('schema', v::stringType(), true),
|
||||
true
|
||||
->key('host', v::stringType())
|
||||
->key('user', v::stringType())
|
||||
->key('password', v::stringType())
|
||||
->key('schema', v::stringType())
|
||||
)
|
||||
->key(
|
||||
'postgresql',
|
||||
v::create()
|
||||
->key('host', v::stringType(), true)
|
||||
->key('user', v::stringType(), true)
|
||||
->key('password', v::stringType(), true)
|
||||
->key('schema', v::stringType(), true),
|
||||
true
|
||||
->key('host', v::stringType())
|
||||
->key('user', v::stringType())
|
||||
->key('password', v::stringType())
|
||||
->key('schema', v::stringType())
|
||||
)
|
||||
->setTemplates([
|
||||
'mysql' => [
|
||||
|
|
|
@ -12,20 +12,18 @@ exceptionFullMessage(static function (): void {
|
|||
->key(
|
||||
'mysql',
|
||||
v::create()
|
||||
->key('host', v::stringType(), true)
|
||||
->key('user', v::stringType(), true)
|
||||
->key('password', v::stringType(), true)
|
||||
->key('schema', v::stringType(), true),
|
||||
true
|
||||
->key('host', v::stringType())
|
||||
->key('user', v::stringType())
|
||||
->key('password', v::stringType())
|
||||
->key('schema', v::stringType())
|
||||
)
|
||||
->key(
|
||||
'postgresql',
|
||||
v::create()
|
||||
->key('host', v::stringType(), true)
|
||||
->key('user', v::stringType(), true)
|
||||
->key('password', v::stringType(), true)
|
||||
->key('schema', v::stringType(), true),
|
||||
true
|
||||
->key('host', v::stringType())
|
||||
->key('user', v::stringType())
|
||||
->key('password', v::stringType())
|
||||
->key('schema', v::stringType())
|
||||
)
|
||||
->setName('the given data')
|
||||
->assert([
|
||||
|
|
159
tests/integration/rules/key.phpt
Normal file
159
tests/integration/rules/key.phpt
Normal file
|
@ -0,0 +1,159 @@
|
|||
--FILE--
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
require 'vendor/autoload.php';
|
||||
|
||||
use Respect\Validation\Validator as v;
|
||||
|
||||
run([
|
||||
// Simple
|
||||
'Missing key' => [v::key('foo', v::intType()), []],
|
||||
'Default' => [v::key('foo', v::intType()), ['foo' => 'string']],
|
||||
'Negative' => [v::not(v::key('foo', v::intType())), ['foo' => 12]],
|
||||
'Double-negative with missing key' => [
|
||||
v::not(v::not(v::key('foo', v::intType()))),
|
||||
[],
|
||||
],
|
||||
|
||||
// With custom name
|
||||
'With wrapped name, missing key' => [
|
||||
v::key('foo', v::intType()->setName('Wrapped'))->setName('Wrapper'),
|
||||
[],
|
||||
],
|
||||
'With wrapped name, default' => [
|
||||
v::key('foo', v::intType()->setName('Wrapped'))->setName('Wrapper'),
|
||||
['foo' => 'string'],
|
||||
],
|
||||
'With wrapped name, negative' => [
|
||||
v::not(v::key('foo', v::intType()->setName('Wrapped'))->setName('Wrapper'))->setName('Not'),
|
||||
['foo' => 12],
|
||||
],
|
||||
'With wrapper name, default' => [
|
||||
v::key('foo', v::intType())->setName('Wrapper'),
|
||||
['foo' => 'string'],
|
||||
],
|
||||
'With wrapper name, missing key' => [
|
||||
v::key('foo', v::intType())->setName('Wrapper'),
|
||||
[],
|
||||
],
|
||||
'With wrapper name, negative' => [
|
||||
v::not(v::key('foo', v::intType())->setName('Wrapper'))->setName('Not'),
|
||||
['foo' => 12],
|
||||
],
|
||||
'With "Not" name, negative' => [
|
||||
v::not(v::key('foo', v::intType()))->setName('Not'),
|
||||
['foo' => 12],
|
||||
],
|
||||
|
||||
// With custom template
|
||||
'With template, default' => [v::key('foo', v::intType()), ['foo' => 'string'], 'That key is off-key'],
|
||||
'With template, negative' => [v::not(v::key('foo', v::intType())), ['foo' => 12], 'No off-key key'],
|
||||
]);
|
||||
?>
|
||||
--EXPECT--
|
||||
Missing key
|
||||
⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺
|
||||
foo must be present
|
||||
- foo must be present
|
||||
[
|
||||
'foo' => 'foo must be present',
|
||||
]
|
||||
|
||||
Default
|
||||
⎺⎺⎺⎺⎺⎺⎺
|
||||
foo must be of type integer
|
||||
- foo must be of type integer
|
||||
[
|
||||
'foo' => 'foo must be of type integer',
|
||||
]
|
||||
|
||||
Negative
|
||||
⎺⎺⎺⎺⎺⎺⎺⎺
|
||||
foo must not be of type integer
|
||||
- foo must not be of type integer
|
||||
[
|
||||
'foo' => 'foo must not be of type integer',
|
||||
]
|
||||
|
||||
Double-negative with missing key
|
||||
⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺
|
||||
foo must be present
|
||||
- foo must be present
|
||||
[
|
||||
'foo' => 'foo must be present',
|
||||
]
|
||||
|
||||
With wrapped name, missing key
|
||||
⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺
|
||||
Wrapped must be present
|
||||
- Wrapped must be present
|
||||
[
|
||||
'Wrapped' => 'Wrapped must be present',
|
||||
]
|
||||
|
||||
With wrapped name, default
|
||||
⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺
|
||||
Wrapped must be of type integer
|
||||
- Wrapped must be of type integer
|
||||
[
|
||||
'Wrapped' => 'Wrapped must be of type integer',
|
||||
]
|
||||
|
||||
With wrapped name, negative
|
||||
⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺
|
||||
Wrapped must not be of type integer
|
||||
- Wrapped must not be of type integer
|
||||
[
|
||||
'Wrapped' => 'Wrapped must not be of type integer',
|
||||
]
|
||||
|
||||
With wrapper name, default
|
||||
⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺
|
||||
foo must be of type integer
|
||||
- foo must be of type integer
|
||||
[
|
||||
'foo' => 'foo must be of type integer',
|
||||
]
|
||||
|
||||
With wrapper name, missing key
|
||||
⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺
|
||||
foo must be present
|
||||
- foo must be present
|
||||
[
|
||||
'foo' => 'foo must be present',
|
||||
]
|
||||
|
||||
With wrapper name, negative
|
||||
⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺
|
||||
foo must not be of type integer
|
||||
- foo must not be of type integer
|
||||
[
|
||||
'foo' => 'foo must not be of type integer',
|
||||
]
|
||||
|
||||
With "Not" name, negative
|
||||
⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺
|
||||
foo must not be of type integer
|
||||
- foo must not be of type integer
|
||||
[
|
||||
'foo' => 'foo must not be of type integer',
|
||||
]
|
||||
|
||||
With template, default
|
||||
⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺
|
||||
That key is off-key
|
||||
- That key is off-key
|
||||
[
|
||||
'foo' => 'That key is off-key',
|
||||
]
|
||||
|
||||
With template, negative
|
||||
⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺
|
||||
No off-key key
|
||||
- No off-key key
|
||||
[
|
||||
'foo' => 'No off-key key',
|
||||
]
|
||||
|
49
tests/integration/rules/keyExists.phpt
Normal file
49
tests/integration/rules/keyExists.phpt
Normal file
|
@ -0,0 +1,49 @@
|
|||
--FILE--
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
require 'vendor/autoload.php';
|
||||
|
||||
use Respect\Validation\Validator as v;
|
||||
|
||||
run([
|
||||
'Default mode' => [v::keyExists('foo'), ['bar' => 'baz']],
|
||||
'Negative mode' => [v::not(v::keyExists('foo')), ['foo' => 'baz']],
|
||||
'Custom name' => [v::keyExists('foo')->setName('Custom name'), ['bar' => 'baz']],
|
||||
'Custom template' => [v::keyExists('foo'), ['bar' => 'baz'], 'Custom template for `{{name}}`'],
|
||||
]);
|
||||
?>
|
||||
--EXPECT--
|
||||
Default mode
|
||||
⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺
|
||||
foo must be present
|
||||
- foo must be present
|
||||
[
|
||||
'foo' => 'foo must be present',
|
||||
]
|
||||
|
||||
Negative mode
|
||||
⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺
|
||||
foo must not be present
|
||||
- foo must not be present
|
||||
[
|
||||
'foo' => 'foo must not be present',
|
||||
]
|
||||
|
||||
Custom name
|
||||
⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺
|
||||
Custom name must be present
|
||||
- Custom name must be present
|
||||
[
|
||||
'Custom name' => 'Custom name must be present',
|
||||
]
|
||||
|
||||
Custom template
|
||||
⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺
|
||||
Custom template for `foo`
|
||||
- Custom template for `foo`
|
||||
[
|
||||
'foo' => 'Custom template for `foo`',
|
||||
]
|
||||
|
126
tests/integration/rules/keyOptional.phpt
Normal file
126
tests/integration/rules/keyOptional.phpt
Normal file
|
@ -0,0 +1,126 @@
|
|||
--FILE--
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
require 'vendor/autoload.php';
|
||||
|
||||
use Respect\Validation\Validator as v;
|
||||
|
||||
run([
|
||||
// Simple
|
||||
'Default' => [v::keyOptional('foo', v::intType()), ['foo' => 'string']],
|
||||
'Negative' => [v::not(v::keyOptional('foo', v::intType())), ['foo' => 12]],
|
||||
'Negative with missing key' => [
|
||||
v::not(v::keyOptional('foo', v::intType())),
|
||||
[],
|
||||
],
|
||||
|
||||
// With custom name
|
||||
'With wrapped name, default' => [
|
||||
v::keyOptional('foo', v::intType()->setName('Wrapped'))->setName('Wrapper'),
|
||||
['foo' => 'string'],
|
||||
],
|
||||
'With wrapped name, negative' => [
|
||||
v::not(v::keyOptional('foo', v::intType()->setName('Wrapped'))->setName('Wrapper'))->setName('Not'),
|
||||
['foo' => 12],
|
||||
],
|
||||
'With wrapper name, default' => [
|
||||
v::keyOptional('foo', v::intType())->setName('Wrapper'),
|
||||
['foo' => 'string'],
|
||||
],
|
||||
'With wrapper name, negative' => [
|
||||
v::not(v::keyOptional('foo', v::intType())->setName('Wrapper'))->setName('Not'),
|
||||
['foo' => 12],
|
||||
],
|
||||
'With "Not" name, negative' => [
|
||||
v::not(v::keyOptional('foo', v::intType()))->setName('Not'),
|
||||
['foo' => 12],
|
||||
],
|
||||
|
||||
// With custom template
|
||||
'With template, default' => [v::keyOptional('foo', v::intType()), ['foo' => 'string'], 'That key is off-key'],
|
||||
'With template, negative' => [v::not(v::keyOptional('foo', v::intType())), ['foo' => 12], 'No off-key key'],
|
||||
]);
|
||||
?>
|
||||
--EXPECT--
|
||||
Default
|
||||
⎺⎺⎺⎺⎺⎺⎺
|
||||
foo must be of type integer
|
||||
- foo must be of type integer
|
||||
[
|
||||
'foo' => 'foo must be of type integer',
|
||||
]
|
||||
|
||||
Negative
|
||||
⎺⎺⎺⎺⎺⎺⎺⎺
|
||||
foo must not be of type integer
|
||||
- foo must not be of type integer
|
||||
[
|
||||
'foo' => 'foo must not be of type integer',
|
||||
]
|
||||
|
||||
Negative with missing key
|
||||
⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺
|
||||
foo must be present
|
||||
- foo must be present
|
||||
[
|
||||
'foo' => 'foo must be present',
|
||||
]
|
||||
|
||||
With wrapped name, default
|
||||
⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺
|
||||
Wrapped must be of type integer
|
||||
- Wrapped must be of type integer
|
||||
[
|
||||
'Wrapped' => 'Wrapped must be of type integer',
|
||||
]
|
||||
|
||||
With wrapped name, negative
|
||||
⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺
|
||||
Wrapped must not be of type integer
|
||||
- Wrapped must not be of type integer
|
||||
[
|
||||
'Wrapped' => 'Wrapped must not be of type integer',
|
||||
]
|
||||
|
||||
With wrapper name, default
|
||||
⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺
|
||||
foo must be of type integer
|
||||
- foo must be of type integer
|
||||
[
|
||||
'foo' => 'foo must be of type integer',
|
||||
]
|
||||
|
||||
With wrapper name, negative
|
||||
⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺
|
||||
foo must not be of type integer
|
||||
- foo must not be of type integer
|
||||
[
|
||||
'foo' => 'foo must not be of type integer',
|
||||
]
|
||||
|
||||
With "Not" name, negative
|
||||
⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺
|
||||
foo must not be of type integer
|
||||
- foo must not be of type integer
|
||||
[
|
||||
'foo' => 'foo must not be of type integer',
|
||||
]
|
||||
|
||||
With template, default
|
||||
⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺
|
||||
That key is off-key
|
||||
- That key is off-key
|
||||
[
|
||||
'foo' => 'That key is off-key',
|
||||
]
|
||||
|
||||
With template, negative
|
||||
⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺
|
||||
No off-key key
|
||||
- No off-key key
|
||||
[
|
||||
'foo' => 'No off-key key',
|
||||
]
|
||||
|
|
@ -218,4 +218,45 @@ abstract class TestCase extends PHPUnitTestCase
|
|||
'positive float' => [32.890],
|
||||
];
|
||||
}
|
||||
|
||||
/** @return array<array{mixed}> */
|
||||
public static function providerForNonArrayValues(): array
|
||||
{
|
||||
$scalarValues = self::providerForNonScalarValues();
|
||||
unset($scalarValues['array']);
|
||||
|
||||
return array_merge(
|
||||
self::providerForIntegerValues(),
|
||||
self::providerForBooleanValues(),
|
||||
self::providerForFloatValues(),
|
||||
self::providerForStringValues(),
|
||||
$scalarValues,
|
||||
);
|
||||
}
|
||||
|
||||
/** @return array<string, array{string|int, array<mixed>}> */
|
||||
public static function providerForArrayWithMissingKeys(): array
|
||||
{
|
||||
return [
|
||||
'integer key, non-empty input' => [0, [1 => true, 2 => true]],
|
||||
'string key, non-empty input' => ['foo', ['bar' => true, 'baz' => true]],
|
||||
'integer key, empty input' => [0, []],
|
||||
'string key, empty input' => ['foo', []],
|
||||
];
|
||||
}
|
||||
|
||||
/** @return array<string, array{string|int, array<mixed>}> */
|
||||
public static function providerForArrayWithExistingKeys(): array
|
||||
{
|
||||
return [
|
||||
'integer key with a single value array' => [1, [1 => true]],
|
||||
'integer key with a multiple value array' => [2, [1 => true, 2 => true]],
|
||||
'string key with a single value array' => ['foo', ['foo' => true, 'bar' => true]],
|
||||
'string key with a multiple value array' => ['bar', ['foo' => true, 'bar' => true]],
|
||||
'integer key with null for a value' => [0, [null]],
|
||||
'string key with null for a value' => ['foo', ['foo' => null]],
|
||||
'integer key with false for a value' => [0, [false]],
|
||||
'string key with false for a value' => ['foo', ['foo' => false]],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
48
tests/unit/Rules/KeyExistsTest.php
Normal file
48
tests/unit/Rules/KeyExistsTest.php
Normal file
|
@ -0,0 +1,48 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use PHPUnit\Framework\Attributes\CoversClass;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use PHPUnit\Framework\Attributes\Test;
|
||||
use Respect\Validation\Test\TestCase;
|
||||
|
||||
#[CoversClass(KeyExists::class)]
|
||||
final class KeyExistsTest extends TestCase
|
||||
{
|
||||
#[Test]
|
||||
#[DataProvider('providerForNonArrayValues')]
|
||||
public function itShouldAlwaysInvalidateNonArrayValues(mixed $input): void
|
||||
{
|
||||
$rule = new KeyExists(0);
|
||||
|
||||
self::assertInvalidInput($rule, $input);
|
||||
}
|
||||
|
||||
/** @param array<mixed> $input */
|
||||
#[Test]
|
||||
#[DataProvider('providerForArrayWithMissingKeys')]
|
||||
public function itShouldInvalidateMissingKeys(int|string $key, array $input): void
|
||||
{
|
||||
$rule = new KeyExists($key);
|
||||
|
||||
self::assertInvalidInput($rule, $input);
|
||||
}
|
||||
|
||||
/** @param array<mixed> $input */
|
||||
#[Test]
|
||||
#[DataProvider('providerForArrayWithExistingKeys')]
|
||||
public function itShouldValidateExistingKeys(int|string $key, array $input): void
|
||||
{
|
||||
$rule = new KeyExists($key);
|
||||
|
||||
self::assertValidInput($rule, $input);
|
||||
}
|
||||
}
|
78
tests/unit/Rules/KeyOptionalTest.php
Normal file
78
tests/unit/Rules/KeyOptionalTest.php
Normal file
|
@ -0,0 +1,78 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use PHPUnit\Framework\Attributes\CoversClass;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use PHPUnit\Framework\Attributes\Group;
|
||||
use PHPUnit\Framework\Attributes\Test;
|
||||
use Respect\Validation\Test\Rules\Stub;
|
||||
use Respect\Validation\Test\TestCase;
|
||||
|
||||
#[Group('rule')]
|
||||
#[CoversClass(KeyOptional::class)]
|
||||
final class KeyOptionalTest extends TestCase
|
||||
{
|
||||
#[Test]
|
||||
#[DataProvider('providerForNonArrayValues')]
|
||||
public function itShouldAlwaysValidateNonArrayValues(mixed $input): void
|
||||
{
|
||||
$rule = new KeyOptional(0, Stub::daze());
|
||||
|
||||
self::assertValidInput($rule, $input);
|
||||
}
|
||||
|
||||
/** @param array<mixed> $input */
|
||||
#[Test]
|
||||
#[DataProvider('providerForArrayWithMissingKeys')]
|
||||
public function itShouldAlwaysValidateMissingKeys(int|string $key, array $input): void
|
||||
{
|
||||
$rule = new KeyOptional($key, Stub::daze());
|
||||
|
||||
self::assertValidInput($rule, $input);
|
||||
}
|
||||
|
||||
/** @param array<mixed> $input */
|
||||
#[Test]
|
||||
#[DataProvider('providerForArrayWithExistingKeys')]
|
||||
public function itShouldValidateExistingKeysWithWrappedRule(int|string $key, array $input): void
|
||||
{
|
||||
$wrapped = Stub::pass(1);
|
||||
|
||||
$rule = new KeyOptional($key, $wrapped);
|
||||
$rule->evaluate($input);
|
||||
|
||||
self::assertEquals($wrapped->inputs, [$input[$key]]);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function itShouldUpdateWrappedNameWithTheGivenKeyWhenItIsString(): void
|
||||
{
|
||||
$key = 'toodaloo';
|
||||
|
||||
$wrapped = Stub::daze();
|
||||
|
||||
new KeyOptional($key, $wrapped);
|
||||
|
||||
self::assertEquals($key, $wrapped->getName());
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function itShouldUpdateWrappedNameWithTheGivenKeyWhenItIsInteger(): void
|
||||
{
|
||||
$key = 123;
|
||||
|
||||
$wrapped = Stub::daze();
|
||||
|
||||
new KeyOptional($key, $wrapped);
|
||||
|
||||
self::assertEquals($key, $wrapped->getName());
|
||||
}
|
||||
}
|
|
@ -21,16 +21,15 @@ final class KeySetTest extends RuleTestCase
|
|||
/** @return iterable<string, array{KeySet, mixed}> */
|
||||
public static function providerForValidInput(): iterable
|
||||
{
|
||||
yield 'correct keys, without rule' => [new KeySet(new Key('foo')), ['foo' => 'bar']];
|
||||
yield 'correct keys, with passing rule' => [new KeySet(new Key('foo', Stub::pass(1))), ['foo' => 'bar']];
|
||||
}
|
||||
|
||||
/** @return iterable<string, array{KeySet, mixed}> */
|
||||
public static function providerForInvalidInput(): iterable
|
||||
{
|
||||
yield 'not array' => [new KeySet(new Key('foo')), null];
|
||||
yield 'missing keys' => [new KeySet(new Key('foo')), []];
|
||||
yield 'extra keys' => [new KeySet(new Key('foo')), ['foo' => 'bar', 'baz' => 'qux']];
|
||||
yield 'not array' => [new KeySet(new Key('foo', Stub::daze())), null];
|
||||
yield 'missing keys' => [new KeySet(new Key('foo', Stub::daze())), []];
|
||||
yield 'extra keys' => [new KeySet(new Key('foo', Stub::daze())), ['foo' => 'bar', 'baz' => 'qux']];
|
||||
yield 'correct keys, with failing rule' => [new KeySet(new Key('foo', Stub::fail(1))), ['foo' => 'bar']];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,145 +10,78 @@ declare(strict_types=1);
|
|||
namespace Respect\Validation\Rules;
|
||||
|
||||
use PHPUnit\Framework\Attributes\CoversClass;
|
||||
use PHPUnit\Framework\Attributes\DoesNotPerformAssertions;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use PHPUnit\Framework\Attributes\Group;
|
||||
use PHPUnit\Framework\Attributes\Test;
|
||||
use Respect\Validation\Exceptions\ComponentException;
|
||||
use Respect\Validation\Exceptions\ValidationException;
|
||||
use Respect\Validation\Test\Rules\Stub;
|
||||
use Respect\Validation\Test\TestCase;
|
||||
use Throwable;
|
||||
|
||||
#[Group('rule')]
|
||||
#[CoversClass(AbstractRelated::class)]
|
||||
#[CoversClass(Key::class)]
|
||||
final class KeyTest extends TestCase
|
||||
{
|
||||
#[Test]
|
||||
public function arrayWithPresentKeyShouldReturnTrue(): void
|
||||
#[DataProvider('providerForNonArrayValues')]
|
||||
public function itShouldAlwaysInvalidateNonArrayValues(mixed $input): void
|
||||
{
|
||||
$validator = new Key('bar');
|
||||
$someArray = [];
|
||||
$someArray['bar'] = 'foo';
|
||||
self::assertTrue($validator->validate($someArray));
|
||||
$rule = new Key(0, Stub::daze());
|
||||
|
||||
self::assertInvalidInput($rule, $input);
|
||||
}
|
||||
|
||||
/** @param array<mixed> $input */
|
||||
#[Test]
|
||||
#[DataProvider('providerForArrayWithMissingKeys')]
|
||||
public function itShouldInvalidateMissingKeys(int|string $key, array $input): void
|
||||
{
|
||||
$rule = new Key($key, Stub::daze());
|
||||
|
||||
self::assertInvalidInput($rule, $input);
|
||||
}
|
||||
|
||||
/** @param array<mixed> $input */
|
||||
#[Test]
|
||||
#[DataProvider('providerForArrayWithExistingKeys')]
|
||||
public function itShouldValidateExistingKeysWithWrappedRule(int|string $key, array $input): void
|
||||
{
|
||||
$wrapped = Stub::pass(1);
|
||||
|
||||
$rule = new Key($key, $wrapped);
|
||||
$rule->evaluate($input);
|
||||
|
||||
self::assertEquals($wrapped->inputs, [$input[$key]]);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function arrayWithNumericKeyShouldReturnTrue(): void
|
||||
public function itShouldReturnDefinedKey(): void
|
||||
{
|
||||
$validator = new Key(0);
|
||||
$someArray = [];
|
||||
$someArray[0] = 'foo';
|
||||
self::assertTrue($validator->validate($someArray));
|
||||
$key = 'toodaloo';
|
||||
$rule = new Key($key, Stub::daze());
|
||||
|
||||
self::assertSame($key, $rule->getKey());
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function emptyInputMustReturnFalse(): void
|
||||
public function itShouldUpdateWrappedNameWithTheGivenKeyWhenItIsString(): void
|
||||
{
|
||||
$validator = new Key('someEmptyKey');
|
||||
$input = '';
|
||||
$key = 'toodaloo';
|
||||
|
||||
self::assertFalse($validator->validate($input));
|
||||
$wrapped = Stub::daze();
|
||||
|
||||
new Key($key, $wrapped);
|
||||
|
||||
self::assertEquals($key, $wrapped->getName());
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function emptyInputMustNotAssert(): void
|
||||
public function itShouldUpdateWrappedNameWithTheGivenKeyWhenItIsInteger(): void
|
||||
{
|
||||
$validator = new Key('someEmptyKey');
|
||||
$key = 123;
|
||||
|
||||
$this->expectException(ValidationException::class);
|
||||
$wrapped = Stub::daze();
|
||||
|
||||
$validator->assert('');
|
||||
}
|
||||
new Key($key, $wrapped);
|
||||
|
||||
#[Test]
|
||||
public function emptyInputMustNotCheck(): void
|
||||
{
|
||||
$validator = new Key('someEmptyKey');
|
||||
|
||||
$this->expectException(ValidationException::class);
|
||||
|
||||
$validator->check('');
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function arrayWithEmptyKeyShouldReturnTrue(): void
|
||||
{
|
||||
$validator = new Key('someEmptyKey');
|
||||
$input = [];
|
||||
$input['someEmptyKey'] = '';
|
||||
|
||||
self::assertTrue($validator->validate($input));
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function shouldHaveTheSameReturnValueForAllValidators(): void
|
||||
{
|
||||
$rule = new Key('key', new NotEmpty());
|
||||
$input = ['key' => ''];
|
||||
|
||||
try {
|
||||
$rule->assert($input);
|
||||
self::fail('`assert()` must throws exception');
|
||||
} catch (Throwable $e) {
|
||||
}
|
||||
|
||||
try {
|
||||
$rule->check($input);
|
||||
self::fail('`check()` must throws exception');
|
||||
} catch (Throwable $e) {
|
||||
}
|
||||
|
||||
self::assertFalse($rule->validate($input));
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function arrayWithAbsentKeyShouldThrowValidationException(): void
|
||||
{
|
||||
$validator = new Key('bar');
|
||||
$someArray = [];
|
||||
$someArray['baraaaaaa'] = 'foo';
|
||||
|
||||
$this->expectException(ValidationException::class);
|
||||
|
||||
$validator->assert($someArray);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function notArrayShouldThrowValidationException(): void
|
||||
{
|
||||
$validator = new Key('bar');
|
||||
$someArray = 123;
|
||||
|
||||
$this->expectException(ValidationException::class);
|
||||
|
||||
$validator->assert($someArray);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function invalidConstructorParametersShouldThrowComponentExceptionUponInstantiation(): void
|
||||
{
|
||||
$this->expectException(ComponentException::class);
|
||||
|
||||
new Key(['invalid']);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
#[DoesNotPerformAssertions]
|
||||
public function extraValidatorShouldValidateKey(): void
|
||||
{
|
||||
$subValidator = new Length(1, 3);
|
||||
$validator = new Key('bar', $subValidator);
|
||||
$someArray = [];
|
||||
$someArray['bar'] = 'foo';
|
||||
$validator->assert($someArray);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function notMandatoryExtraValidatorShouldPassWithAbsentKey(): void
|
||||
{
|
||||
$subValidator = new Length(1, 3);
|
||||
$validator = new Key('bar', $subValidator, false);
|
||||
$someArray = [];
|
||||
self::assertTrue($validator->validate($someArray));
|
||||
self::assertEquals($key, $wrapped->getName());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue