mirror of
https://github.com/Respect/Validation.git
synced 2026-03-17 07:45:45 +01:00
When nested-structural validation fails, it's challenging to identify which rule failed from the main exception message. A great example is the `Issue796Test.php` file. The exception message says: host must be a string But you're left unsure whether it's the `host` key from the `mysql` key or the `postgresql` key. This commit changes that behaviour by introducing the concept of "Path." The `path` represents the path that a rule has taken, and we can use it in structural rules to identify the path of an array or object. Here's what it looks like before and after: ```diff -host must be a string +`.mysql.host` must be a string ``` Because paths are a specific concept, I added a dot (`.`) at the beginning of all paths when displaying them. I was inspired by the `jq` syntax. I also added backticks around paths to distinguish them from any other value. I didn't manage to fix a test, and I skipped it instead of fixing it because I want to make changes in how we display error messages as arrays, and it will be easier to fix it then.
215 lines
7.1 KiB
PHP
215 lines
7.1 KiB
PHP
<?php
|
|
|
|
/*
|
|
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
|
|
* SPDX-License-Identifier: MIT
|
|
*/
|
|
|
|
declare(strict_types=1);
|
|
|
|
test('one rule / one failed', expectAll(
|
|
fn() => v::keySet(v::key('foo', v::intType()))->assert(['foo' => 'string']),
|
|
'`.foo` must be an integer',
|
|
'- `.foo` must be an integer',
|
|
['foo' => '`.foo` must be an integer'],
|
|
));
|
|
|
|
test('one rule / one missing key', expectAll(
|
|
fn() => v::keySet(v::keyExists('foo'))->assert([]),
|
|
'`.foo` must be present',
|
|
'- `.foo` must be present',
|
|
['foo' => '`.foo` must be present'],
|
|
));
|
|
|
|
test('one rule / one extra key', expectAll(
|
|
fn() => v::keySet(v::keyExists('foo'))->assert(['foo' => 42, 'bar' => 'string']),
|
|
'`.bar` must not be present',
|
|
'- `.bar` must not be present',
|
|
['bar' => '`.bar` must not be present'],
|
|
));
|
|
|
|
test('one rule / one extra key / one missing key', expectAll(
|
|
fn() => v::keySet(v::keyExists('foo'))->assert(['bar' => true]),
|
|
'`.foo` must be present',
|
|
<<<'FULL_MESSAGE'
|
|
- `["bar": true]` contains both missing and extra keys
|
|
- `.foo` must be present
|
|
- `.bar` must not be present
|
|
FULL_MESSAGE,
|
|
[
|
|
'__root__' => '`["bar": true]` contains both missing and extra keys',
|
|
'foo' => '`.foo` must be present',
|
|
'bar' => '`.bar` must not be present',
|
|
],
|
|
));
|
|
|
|
test('one rule / two extra keys', expectAll(
|
|
fn() => v::keySet(v::keyExists('foo'))->assert(['foo' => 42, 'bar' => 'string', 'baz' => true]),
|
|
'`.bar` must not be present',
|
|
<<<'FULL_MESSAGE'
|
|
- `["foo": 42, "bar": "string", "baz": true]` contains extra keys
|
|
- `.bar` must not be present
|
|
- `.baz` must not be present
|
|
FULL_MESSAGE,
|
|
[
|
|
'__root__' => '`["foo": 42, "bar": "string", "baz": true]` contains extra keys',
|
|
'bar' => '`.bar` must not be present',
|
|
'baz' => '`.baz` must not be present',
|
|
],
|
|
));
|
|
|
|
test('one rule / more than ten extra keys', expectAll(
|
|
fn() => v::keySet(v::keyExists('foo'))
|
|
->assert([
|
|
'foo' => 42,
|
|
'bar' => 'string',
|
|
'baz' => true,
|
|
'qux' => false,
|
|
'quux' => 42,
|
|
'corge' => 'string',
|
|
'grault' => true,
|
|
'garply' => false,
|
|
'waldo' => 42,
|
|
'fred' => 'string',
|
|
'plugh' => true,
|
|
'xyzzy' => false,
|
|
'thud' => 42,
|
|
]),
|
|
'`.bar` must not be present',
|
|
<<<'FULL_MESSAGE'
|
|
- `["foo": 42, "bar": "string", "baz": true, "qux": false, "quux": 42, ...]` contains extra keys
|
|
- `.bar` must not be present
|
|
- `.baz` must not be present
|
|
- `.qux` must not be present
|
|
- `.quux` must not be present
|
|
- `.corge` must not be present
|
|
- `.grault` must not be present
|
|
- `.garply` must not be present
|
|
- `.waldo` must not be present
|
|
- `.fred` must not be present
|
|
- `.plugh` must not be present
|
|
FULL_MESSAGE,
|
|
[
|
|
'__root__' => '`["foo": 42, "bar": "string", "baz": true, "qux": false, "quux": 42, ...]` contains extra keys',
|
|
'bar' => '`.bar` must not be present',
|
|
'baz' => '`.baz` must not be present',
|
|
'qux' => '`.qux` must not be present',
|
|
'quux' => '`.quux` must not be present',
|
|
'corge' => '`.corge` must not be present',
|
|
'grault' => '`.grault` must not be present',
|
|
'garply' => '`.garply` must not be present',
|
|
'waldo' => '`.waldo` must not be present',
|
|
'fred' => '`.fred` must not be present',
|
|
'plugh' => '`.plugh` must not be present',
|
|
],
|
|
));
|
|
|
|
test('multiple rules / one failed', expectAll(
|
|
fn() => v::keySet(v::keyExists('foo'), v::keyExists('bar'))->assert(['foo' => 42]),
|
|
'`.bar` must be present',
|
|
'- `.bar` must be present',
|
|
['bar' => '`.bar` must be present'],
|
|
));
|
|
|
|
test('multiple rules / all failed', expectAll(
|
|
fn() => v::keySet(v::keyExists('foo'), v::keyExists('bar'))->assert([]),
|
|
'`.foo` must be present',
|
|
<<<'FULL_MESSAGE'
|
|
- `[]` contains missing keys
|
|
- `.foo` must be present
|
|
- `.bar` must be present
|
|
FULL_MESSAGE,
|
|
[
|
|
'__root__' => '`[]` contains missing keys',
|
|
'foo' => '`.foo` must be present',
|
|
'bar' => '`.bar` must be present',
|
|
],
|
|
));
|
|
|
|
test('multiple rules / one extra key', expectAll(
|
|
fn() => v::keySet(
|
|
v::keyExists('foo'),
|
|
v::keyExists('bar'),
|
|
)->assert(['foo' => 42, 'bar' => 'string', 'baz' => true]),
|
|
'`.baz` must not be present',
|
|
'- `.baz` must not be present',
|
|
['baz' => '`.baz` must not be present'],
|
|
));
|
|
|
|
test('multiple rules / one extra key / one missing', expectAll(
|
|
fn() => v::keySet(
|
|
v::keyExists('foo'),
|
|
v::keyExists('bar'),
|
|
)->assert(['bar' => 'string', 'baz' => true]),
|
|
'`.foo` must be present',
|
|
<<<'FULL_MESSAGE'
|
|
- `["bar": "string", "baz": true]` contains both missing and extra keys
|
|
- `.foo` must be present
|
|
- `.baz` must not be present
|
|
FULL_MESSAGE,
|
|
[
|
|
'__root__' => '`["bar": "string", "baz": true]` contains both missing and extra keys',
|
|
'foo' => '`.foo` must be present',
|
|
'baz' => '`.baz` must not be present',
|
|
],
|
|
));
|
|
|
|
test('multiple rules / two extra keys', expectAll(
|
|
fn() => v::keySet(
|
|
v::keyExists('foo'),
|
|
v::keyExists('bar'),
|
|
v::keyOptional('qux', v::intType()),
|
|
)->assert(['foo' => 42, 'bar' => 'string', 'baz' => true, 'qux' => false]),
|
|
'`.qux` must be an integer',
|
|
<<<'FULL_MESSAGE'
|
|
- `["foo": 42, "bar": "string", "baz": true, "qux": false]` contains extra keys
|
|
- `.qux` must be an integer
|
|
- `.baz` must not be present
|
|
FULL_MESSAGE,
|
|
[
|
|
'__root__' => '`["foo": 42, "bar": "string", "baz": true, "qux": false]` contains extra keys',
|
|
'qux' => '`.qux` must be an integer',
|
|
'baz' => '`.baz` must not be present',
|
|
],
|
|
));
|
|
|
|
test('multiple rules / all failed validation', expectAll(
|
|
fn() => v::keySet(
|
|
v::key('foo', v::intType()),
|
|
v::key('bar', v::intType()),
|
|
v::key('baz', v::intType()),
|
|
)
|
|
->assert(['foo' => 42, 'bar' => 'string', 'baz' => true]),
|
|
'`.bar` must be an integer',
|
|
<<<'FULL_MESSAGE'
|
|
- `["foo": 42, "bar": "string", "baz": true]` validation failed
|
|
- `.bar` must be an integer
|
|
- `.baz` must be an integer
|
|
FULL_MESSAGE,
|
|
[
|
|
'__root__' => '`["foo": 42, "bar": "string", "baz": true]` validation failed',
|
|
'bar' => '`.bar` must be an integer',
|
|
'baz' => '`.baz` must be an integer',
|
|
],
|
|
));
|
|
|
|
test('multiple rules / single missing key / single failed validation', expectAll(
|
|
fn() => v::keySet(
|
|
v::create()
|
|
->key('foo', v::intType())
|
|
->key('bar', v::intType())
|
|
->key('baz', v::intType()),
|
|
)
|
|
->assert(['foo' => 42, 'bar' => 'string']),
|
|
'`.bar` must be an integer',
|
|
<<<'FULL_MESSAGE'
|
|
- `["foo": 42, "bar": "string"]` contains missing keys
|
|
- `.bar` must be an integer
|
|
- `.baz` must be present
|
|
FULL_MESSAGE,
|
|
[
|
|
'__root__' => '`["foo": 42, "bar": "string"]` contains missing keys',
|
|
'bar' => '`.bar` must be an integer',
|
|
'baz' => '`.baz` must be present',
|
|
],
|
|
));
|