Files
tez-utils-validate/tests/SchemaTest.php
T

149 lines
4.1 KiB
PHP

<?php
declare(strict_types=1);
namespace Tez\Utils\Tests\Validate;
use PHPUnit\Framework\TestCase;
use Tez\Utils\Validate\Guard;
use Tez\Utils\Validate\Schema;
final class SchemaTest extends TestCase
{
public function testValidDataPassesWithoutException(): void
{
$this->expectNotToPerformAssertions();
Schema::validate([
'name' => 'Alice',
'age' => 28,
'active' => true,
], [
'name' => 'string',
'age' => 'int',
'active' => 'bool',
]);
}
public function testThrowsWhenRequiredKeyIsMissing(): void
{
$this->expectException(\UnexpectedValueException::class);
$this->expectExceptionMessageMatches('/name.*required/');
Schema::validate([], ['name' => 'string']);
}
public function testThrowsOnWrongType(): void
{
$this->expectException(\UnexpectedValueException::class);
$this->expectExceptionMessageMatches('/age.*expected int.*got string/');
Schema::validate(['age' => 'not-an-int'], ['age' => 'int']);
}
public function testOptionalKeyCanBeAbsent(): void
{
$this->expectNotToPerformAssertions();
Schema::validate(['name' => 'Alice'], ['name' => 'string', 'email' => '?string']);
}
public function testOptionalKeyCanBeNull(): void
{
$this->expectNotToPerformAssertions();
Schema::validate(['name' => 'Alice', 'email' => null], ['name' => 'string', 'email' => '?string']);
}
public function testOptionalKeyWithWrongTypeThrows(): void
{
$this->expectException(\UnexpectedValueException::class);
Schema::validate(['email' => 42], ['email' => '?string']);
}
public function testNestedSchemaIsValidated(): void
{
$this->expectNotToPerformAssertions();
Schema::validate([
'user' => ['name' => 'Alice', 'age' => 28],
], [
'user' => ['name' => 'string', 'age' => 'int'],
]);
}
public function testNestedSchemaFailsWithDotNotationPath(): void
{
$this->expectException(\UnexpectedValueException::class);
$this->expectExceptionMessageMatches('/address\.zip/');
Schema::validate([
'address' => ['city' => 'Berlin', 'zip' => 12345],
], [
'address' => ['city' => 'string', 'zip' => 'string'],
]);
}
public function testCallableRuleIsApplied(): void
{
$this->expectNotToPerformAssertions();
Schema::validate(['score' => 75], [
'score' => fn($v) => Guard::inRange($v, 0, 100),
]);
}
public function testCallableRuleFailureIncludesPath(): void
{
$this->expectException(\UnexpectedValueException::class);
$this->expectExceptionMessageMatches('/score:/');
Schema::validate(['score' => 150], [
'score' => fn($v) => Guard::inRange($v, 0, 100),
]);
}
public function testMixedTypeAcceptsAnything(): void
{
$this->expectNotToPerformAssertions();
Schema::validate(
['data' => ['anything', 42, true, null]],
['data' => 'mixed'],
);
}
public function testNestedOptionalField(): void
{
$this->expectNotToPerformAssertions();
Schema::validate([
'address' => ['city' => 'Berlin'],
], [
'address' => ['city' => 'string', 'country' => '?string'],
]);
}
public function testPathIsReportedCorrectlyForDeepNesting(): void
{
$this->expectException(\UnexpectedValueException::class);
$this->expectExceptionMessageMatches('/user\.profile\.displayName/');
Schema::validate([
'user' => [
'profile' => ['displayName' => 123],
],
], [
'user' => [
'profile' => ['displayName' => 'string'],
],
]);
}
public function testUnknownTypeStringThrows(): void
{
$this->expectException(\InvalidArgumentException::class);
Schema::validate(['x' => 'value'], ['x' => 'uuid']);
}
}