diff --git a/src/Expectation.php b/src/Expectation.php index 476cee1d..148e44b1 100644 --- a/src/Expectation.php +++ b/src/Expectation.php @@ -740,4 +740,26 @@ final class Expectation FileLineFinder::where(fn (string $line): bool => str_contains($line, 'class')) ); } + + /** + * Asserts that the given expectation is iterable and contains snake_case keys. + * + * @return self + */ + public function toHaveSnakeCaseKeys(string $message = ''): self + { + if (! is_iterable($this->value)) { + InvalidExpectationValue::expected('iterable'); + } + + foreach ($this->value as $k => $item) { + $this->and($k)->toBeSnakeCase($message); + + if (is_array($item)) { + $this->and($item)->toHaveSnakeCaseKeys($message); + } + } + + return $this; + } } diff --git a/tests/Features/Expect/toHaveSnakeCaseKeys.php b/tests/Features/Expect/toHaveSnakeCaseKeys.php new file mode 100644 index 00000000..584a4b65 --- /dev/null +++ b/tests/Features/Expect/toHaveSnakeCaseKeys.php @@ -0,0 +1,31 @@ + true, + 'snake_case' => [ + 'snake' => true, + 'snake_case' => [ + 'snake' => true, + 'snake_case' => true, + ], + ], +]; + +test('pass', function () use ($array) { + expect($array)->toHaveSnakeCaseKeys(); +}); + +test('failures', function () { + expect('not-an-array')->toHaveSnakeCaseKeys(); +})->throws(InvalidExpectationValue::class); + +test('failures with message', function () use ($array) { + expect($array)->not->toHaveSnakeCaseKeys('oh no!'); +})->throws(ExpectationFailedException::class, 'oh no!'); + +test('not failures', function () use ($array) { + expect($array)->not->toHaveSnakeCaseKeys(); +})->throws(ExpectationFailedException::class);