Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add validator for LexString values
- Loading branch information
Showing
3 changed files
with
164 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace SocialWeb\Atproto\Lexicon\Validators; | ||
|
||
use SocialWeb\Atproto\Lexicon\Nsid\NsidValidator; | ||
use SocialWeb\Atproto\Lexicon\Types\LexString; | ||
use SocialWeb\Atproto\Lexicon\Types\LexStringFormat; | ||
use SocialWeb\Atproto\Lexicon\Validators\Formats\AtIdentifierValidator; | ||
use SocialWeb\Atproto\Lexicon\Validators\Formats\AtUriValidator; | ||
use SocialWeb\Atproto\Lexicon\Validators\Formats\DatetimeValidator; | ||
use SocialWeb\Atproto\Lexicon\Validators\Formats\DidValidator; | ||
use SocialWeb\Atproto\Lexicon\Validators\Formats\HandleValidator; | ||
use SocialWeb\Atproto\Lexicon\Validators\Formats\UriValidator; | ||
|
||
use function grapheme_strlen; | ||
use function implode; | ||
use function in_array; | ||
use function is_string; | ||
use function strlen; | ||
|
||
class LexStringValidator implements Validator | ||
{ | ||
public function __construct(private readonly LexString $type) | ||
{ | ||
} | ||
|
||
public function validate(mixed $value, ?string $path = null): string | ||
{ | ||
if ($value === null) { | ||
$value = $this->type->default; | ||
} | ||
|
||
$path = $path ?? 'Value'; | ||
|
||
if (!is_string($value)) { | ||
throw new InvalidValue("$path must be a string"); | ||
} | ||
|
||
if ($this->type->const !== null && $value !== $this->type->const) { | ||
throw new InvalidValue("$path must be {$this->type->const}"); | ||
} | ||
|
||
if ($this->type->enum !== null && !in_array($value, $this->type->enum)) { | ||
throw new InvalidValue("$path must be one of (" . implode('|', $this->type->enum) . ')'); | ||
} | ||
|
||
if ($this->type->maxLength !== null && strlen($value) > $this->type->maxLength) { | ||
throw new InvalidValue("$path must not be longer than {$this->type->maxLength} characters"); | ||
} | ||
|
||
if ($this->type->minLength !== null && strlen($value) < $this->type->minLength) { | ||
throw new InvalidValue("$path must not be shorter than {$this->type->minLength} characters"); | ||
} | ||
|
||
if ($this->type->maxGraphemes !== null && grapheme_strlen($value) > $this->type->maxGraphemes) { | ||
throw new InvalidValue("$path must not be longer than {$this->type->maxGraphemes} graphemes"); | ||
} | ||
|
||
if ($this->type->minGraphemes !== null && grapheme_strlen($value) < $this->type->minGraphemes) { | ||
throw new InvalidValue("$path must not be shorter than {$this->type->minGraphemes} graphemes"); | ||
} | ||
|
||
return match ($this->type->format) { | ||
LexStringFormat::AtIdentifier => (new AtIdentifierValidator())->validate($value, $path), | ||
LexStringFormat::AtUri => (new AtUriValidator())->validate($value, $path), | ||
//LexStringFormat::Cid => ???, | ||
LexStringFormat::DateTime => (new DatetimeValidator())->validate($value, $path), | ||
LexStringFormat::Did => (new DidValidator())->validate($value, $path), | ||
LexStringFormat::Handle => (new HandleValidator())->validate($value, $path), | ||
LexStringFormat::Nsid => (new NsidValidator())->validate($value, $path), | ||
LexStringFormat::Uri => (new UriValidator())->validate($value, $path), | ||
default => $value, | ||
}; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace SocialWeb\Test\Atproto\Lexicon\Validators; | ||
|
||
use SocialWeb\Atproto\Lexicon\Types\LexEntity; | ||
use SocialWeb\Atproto\Lexicon\Types\LexString; | ||
use SocialWeb\Atproto\Lexicon\Types\LexStringFormat; | ||
use SocialWeb\Atproto\Lexicon\Validators\LexStringValidator; | ||
use SocialWeb\Atproto\Lexicon\Validators\Validator; | ||
|
||
use function assert; | ||
|
||
class LexStringValidatorTest extends ValidatorTestCase | ||
{ | ||
protected function getValidator(LexEntity $type): Validator | ||
{ | ||
assert($type instanceof LexString); | ||
|
||
return new LexStringValidator($type); | ||
} | ||
|
||
/** | ||
* @return array<array{0: LexString, 1: mixed}> | ||
*/ | ||
public static function validTestProvider(): array | ||
{ | ||
return [ | ||
[new LexString(), 'foo'], | ||
[new LexString(default: 'bar'), null], | ||
[new LexString(default: 'baz'), 'qux'], | ||
[new LexString(const: 'qux'), 'qux'], | ||
[new LexString(enum: ['a', 'b', 'c']), 'b'], | ||
[new LexString(maxLength: 6), 'foobar'], | ||
[new LexString(minLength: 3), 'baz'], | ||
[new LexString(maxGraphemes: 5), '1234👨👩👧👦'], | ||
[new LexString(minGraphemes: 2), '👨👩👧👦👩👩👧👦'], | ||
[new LexString(format: LexStringFormat::AtIdentifier), 'did:plc:12345678abcdefghijklmnop'], | ||
[new LexString(format: LexStringFormat::AtUri), 'at://user.bsky.social'], | ||
[new LexString(format: LexStringFormat::DateTime), '2019-07-09T15:03:36.000+00:00'], | ||
[new LexString(format: LexStringFormat::Did), 'did:plc:7iza6de2dwap2sbkpav7c6c6'], | ||
[new LexString(format: LexStringFormat::Handle), 'john.test.bsky.app'], | ||
[new LexString(format: LexStringFormat::Nsid), 'com.example.foo'], | ||
[new LexString(format: LexStringFormat::Uri), 'foo://bar'], | ||
]; | ||
} | ||
|
||
/** | ||
* @return array<array{0: LexString, 1: mixed, 2: string}> | ||
*/ | ||
public static function invalidTestProvider(): array | ||
{ | ||
return [ | ||
[new LexString(), 1234, 'Value must be a string'], | ||
[new LexString(), 12.34, 'Value must be a string'], | ||
[new LexString(), true, 'Value must be a string'], | ||
[new LexString(), null, 'Value must be a string'], | ||
[new LexString(), [], 'Value must be a string'], | ||
[new LexString(), (object) [], 'Value must be a string'], | ||
[new LexString(default: 'bar'), 1234, 'Value must be a string'], | ||
[new LexString(default: 'bar'), 12.34, 'Value must be a string'], | ||
[new LexString(default: 'bar'), true, 'Value must be a string'], | ||
[new LexString(default: 'bar'), [], 'Value must be a string'], | ||
[new LexString(default: 'bar'), (object) [], 'Value must be a string'], | ||
[new LexString(const: 'foo'), 'qux', 'Value must be foo'], | ||
[new LexString(enum: ['a', 'b', 'c']), 'd', 'Value must be one of (a|b|c)'], | ||
[new LexString(maxLength: 8), 'foobarbaz', 'Value must not be longer than 8 characters'], | ||
[new LexString(minLength: 4), 'qux', 'Value must not be shorter than 4 characters'], | ||
[new LexString(maxGraphemes: 4), '1234👨👩👧👦', 'Value must not be longer than 4 graphemes'], | ||
[new LexString(minGraphemes: 2), '👨👩👧👦', 'Value must not be shorter than 2 graphemes'], | ||
[new LexString(format: LexStringFormat::AtIdentifier), 'bad id', 'Value must be a valid handle or DID'], | ||
[new LexString(format: LexStringFormat::AtUri), 'http://did:plc:asdf123', 'AT URI must use "at://" scheme'], | ||
[ | ||
new LexString(format: LexStringFormat::DateTime), | ||
'2020-12-04', | ||
'Value must be an ISO 8601 formatted datetime string', | ||
], | ||
[new LexString(format: LexStringFormat::Did), 'method:did:val', 'DID requires "did:" prefix'], | ||
[new LexString(format: LexStringFormat::Handle), 'did:thing.test', 'Invalid characters found in handle'], | ||
[new LexString(format: LexStringFormat::Nsid), 'example.com', 'NSID needs at least three parts'], | ||
[new LexString(format: LexStringFormat::Uri), 'foobar', 'Value must be a URI'], | ||
]; | ||
} | ||
} |