diff --git a/CHANGELOG.md b/CHANGELOG.md index cbdda20..9fa0ac1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ Changelog - All assertion methods now return the checked value. - Added `notInArray` and `notOneOf`. - Added `isInitialized`, to check if a class property is initialized. +- Added `notNegativeInteger` and `negativeInteger` ### Fixed diff --git a/README.md b/README.md index e81d088..bbfac0a 100644 --- a/README.md +++ b/README.md @@ -89,6 +89,8 @@ Method | Description `integer($value, $message = '')` | Check that a value is an integer `integerish($value, $message = '')` | Check that a value casts to an integer `positiveInteger($value, $message = '')` | Check that a value is a positive (non-zero) integer +`negativeInteger($value, $message = '')` | Check that a value is a negative integer +`notNegativeInteger($value, $message = '')` | Check that a value is a non-negative integer `float($value, $message = '')` | Check that a value is a float `numeric($value, $message = '')` | Check that a value is numeric `natural($value, $message = '')` | Check that a value is a non-negative integer diff --git a/src/Assert.php b/src/Assert.php index 5a46c9b..d585aa4 100644 --- a/src/Assert.php +++ b/src/Assert.php @@ -117,7 +117,9 @@ public static function integerish(mixed $value, string $message = ''): int|float */ public static function positiveInteger(mixed $value, string $message = ''): int { - if (!(\is_int($value) && $value > 0)) { + self::integer($value); + + if ($value < 1) { static::reportInvalidArgument(\sprintf( $message ?: 'Expected a positive integer. Got: %s', static::valueToString($value) @@ -127,6 +129,50 @@ public static function positiveInteger(mixed $value, string $message = ''): int return $value; } + /** + * @psalm-pure + * @psalm-assert non-negative-int $value + * + * @psalm-return non-negative-int + * + * @throws InvalidArgumentException + */ + public static function notNegativeInteger(mixed $value, string $message = ''): int + { + self::integer($value); + + if ($value < 0) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected a non negative integer. Got: %s', + static::valueToString($value) + )); + } + + return $value; + } + + /** + * @psalm-pure + * @psalm-assert negative-int $value + * + * @psalm-return negative-int + * + * @throws InvalidArgumentException + */ + public static function negativeInteger(mixed $value, string $message = ''): int + { + self::integer($value); + + if ($value >= 0) { + static::reportInvalidArgument(\sprintf( + $message ?: 'Expected a negative integer. Got: %s', + static::valueToString($value) + )); + } + + return $value; + } + /** * @psalm-pure * @@ -1741,7 +1787,7 @@ public static function propertyNotExists(mixed $classOrObject, mixed $property, )); } - return $value; + return $classOrObject; } /** diff --git a/src/Mixin.php b/src/Mixin.php index 8b44e6e..c076c4e 100644 --- a/src/Mixin.php +++ b/src/Mixin.php @@ -293,6 +293,118 @@ public static function allNullOrPositiveInteger(?iterable $value, string $messag return $value; } + /** + * @psalm-pure + * + * @psalm-assert non-negative-int|null $value + * + * @return non-negative-int|null + * + * @throws InvalidArgumentException + */ + public static function nullOrNotNegativeInteger(mixed $value, string $message = ''): mixed + { + null === $value || static::notNegativeInteger($value, $message); + + return $value; + } + + /** + * @psalm-pure + * + * @psalm-assert iterable $value + * + * @return iterable + * + * @throws InvalidArgumentException + */ + public static function allNotNegativeInteger(iterable $value, string $message = ''): iterable + { + static::isIterable($value); + + foreach ($value as $entry) { + static::notNegativeInteger($entry, $message); + } + + return $value; + } + + /** + * @psalm-pure + * + * @psalm-assert iterable $value + * + * @return iterable + * + * @throws InvalidArgumentException + */ + public static function allNullOrNotNegativeInteger(?iterable $value, string $message = ''): ?iterable + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::notNegativeInteger($entry, $message); + } + + return $value; + } + + /** + * @psalm-pure + * + * @psalm-assert negative-int|null $value + * + * @return negative-int|null + * + * @throws InvalidArgumentException + */ + public static function nullOrNegativeInteger(mixed $value, string $message = ''): mixed + { + null === $value || static::negativeInteger($value, $message); + + return $value; + } + + /** + * @psalm-pure + * + * @psalm-assert iterable $value + * + * @return iterable + * + * @throws InvalidArgumentException + */ + public static function allNegativeInteger(iterable $value, string $message = ''): iterable + { + static::isIterable($value); + + foreach ($value as $entry) { + static::negativeInteger($entry, $message); + } + + return $value; + } + + /** + * @psalm-pure + * + * @psalm-assert iterable $value + * + * @return iterable + * + * @throws InvalidArgumentException + */ + public static function allNullOrNegativeInteger(?iterable $value, string $message = ''): ?iterable + { + static::isIterable($value); + + foreach ($value as $entry) { + null === $entry || static::negativeInteger($entry, $message); + } + + return $value; + } + /** * @psalm-pure * diff --git a/tests/AssertTest.php b/tests/AssertTest.php index 4b0e9eb..4e801eb 100644 --- a/tests/AssertTest.php +++ b/tests/AssertTest.php @@ -79,6 +79,26 @@ public static function getTests(): array ['positiveInteger', ['0'], false], ['positiveInteger', [1.0], false], ['positiveInteger', [1.23], false], + ['notNegativeInteger', [123], true], + ['notNegativeInteger', [1], true], + ['notNegativeInteger', [-123], false], + ['notNegativeInteger', [0], true], + ['notNegativeInteger', [0.0], false], + ['notNegativeInteger', ['123'], false], + ['notNegativeInteger', ['-123'], false], + ['notNegativeInteger', ['0'], false], + ['notNegativeInteger', [1.0], false], + ['notNegativeInteger', [1.23], false], + ['negativeInteger', [123], false], + ['negativeInteger', [1], false], + ['negativeInteger', [-123], true], + ['negativeInteger', [0], false], + ['negativeInteger', [0.0], false], + ['negativeInteger', ['123'], false], + ['negativeInteger', ['-123'], false], + ['negativeInteger', ['0'], false], + ['negativeInteger', [1.0], false], + ['negativeInteger', [1.23], false], ['float', [1.0], true], ['float', [1.23], true], ['float', [123], false], diff --git a/tests/static-analysis/assert-negativeInteger.php b/tests/static-analysis/assert-negativeInteger.php new file mode 100644 index 0000000..dc1ab5c --- /dev/null +++ b/tests/static-analysis/assert-negativeInteger.php @@ -0,0 +1,63 @@ + + */ +function allNegativeInteger(mixed $value): iterable +{ + Assert::allNegativeInteger($value); + + return $value; +} + +/** + * @psalm-pure + * + * @param mixed $value + * + * @return iterable + */ +function allNullOrNegativeInteger(mixed $value): iterable +{ + Assert::allNullOrNegativeInteger($value); + + return $value; +} diff --git a/tests/static-analysis/assert-notNegativeInteger.php b/tests/static-analysis/assert-notNegativeInteger.php new file mode 100644 index 0000000..01874bd --- /dev/null +++ b/tests/static-analysis/assert-notNegativeInteger.php @@ -0,0 +1,65 @@ + + */ +function allNonNegativeInteger(mixed $value): iterable +{ + Assert::allNotNegativeInteger($value); + + return $value; +} + +/** + * @psalm-pure + * + * @param mixed $value + * + * @return iterable + */ +function allNullOrNonNegativeInteger(mixed $value): iterable +{ + Assert::allNullOrPositiveInteger($value); + + return $value; +}