From 774a34040029078a0a2bab1828b4d9104dec6aec Mon Sep 17 00:00:00 2001 From: Sonali dudhia <45190968+sonalidudhia@users.noreply.github.com> Date: Thu, 11 Jun 2026 14:44:00 +0530 Subject: [PATCH] feat: add toBeUlid assertion and isUlid validation method (#1726) --- src/Mixins/Expectation.php | 16 ++++++++++++++++ src/Support/Str.php | 8 ++++++++ tests/Features/Expect/toBeUlid.php | 26 ++++++++++++++++++++++++++ 3 files changed, 50 insertions(+) create mode 100644 tests/Features/Expect/toBeUlid.php diff --git a/src/Mixins/Expectation.php b/src/Mixins/Expectation.php index 926200a8..4522155e 100644 --- a/src/Mixins/Expectation.php +++ b/src/Mixins/Expectation.php @@ -1142,6 +1142,22 @@ final class Expectation return $this; } + /** + * Asserts that the value is a ULID. + * + * @return self + */ + public function toBeUlid(string $message = ''): self + { + if (! is_string($this->value)) { + InvalidExpectationValue::expected('string'); + } + + Assert::assertTrue(Str::isUlid($this->value), $message); + + return $this; + } + /** * Asserts that the value is between 2 specified values * diff --git a/src/Support/Str.php b/src/Support/Str.php index 04f4b1fd..85ba4115 100644 --- a/src/Support/Str.php +++ b/src/Support/Str.php @@ -98,6 +98,14 @@ final class Str return preg_match('/^[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}$/iD', $value) > 0; } + /** + * Determine if a given value is a valid ULID. + */ + public static function isUlid(string $value): bool + { + return preg_match('/^[0-9A-HJKMNP-TV-Z]{26}$/', $value) > 0; + } + /** * Creates a describe block as `$describeDescription` → `$testDescription` format. * diff --git a/tests/Features/Expect/toBeUlid.php b/tests/Features/Expect/toBeUlid.php new file mode 100644 index 00000000..0f4a0e67 --- /dev/null +++ b/tests/Features/Expect/toBeUlid.php @@ -0,0 +1,26 @@ +toBeUlid(); +})->throws(InvalidExpectationValue::class, 'Invalid expectation value type. Expected [string].'); + +test('pass', function () { + expect('01ARZ3NDEKTSV4RRFFQ69G5FAV')->toBeUlid(); + expect('01BX5ZZKBKACTAV9WEVGEMMVRE')->toBeUlid(); + expect('7ZZZZZZZZZ0000000000000000')->toBeUlid(); +}); + +test('failures', function () { + expect('foo')->toBeUlid(); +})->throws(ExpectationFailedException::class); + +test('failures with message', function () { + expect('bar')->toBeUlid('oh no!'); +})->throws(ExpectationFailedException::class, 'oh no!'); + +test('not failures', function () { + expect('foo')->not->toBeUlid(); +});