Refactor case sensitiveness support

This is a mid-size refactor that affects several validators.

Most prominently, the ones that had an `$identical` parameter
to deal with case sensitiveness.

This parameter was confusing, effectively making validators such
as `Contains` behave very differently for arrays versus strings.

In arrays, `$identical` meant "the same type", while it in strings
it meant "case sensitive".

That parameter was removed, and the default behavior is now to
always compare **case sensitive** and strict typing.

A document explaining how to combine other validators in order
to achieve case _insensitive_ comparisons was added.

Additionally, the `Call` validator was refactored back to be
suitable to take on the task of being a fast, quick composable
validator.

With the introduction of `Circuit`, we can shift the responsibility
of dealing with possible mismatches to the user. This kind of type
handling is demonstrated in how I refactored `Tld` to account for
the type mismatch without setting error handlers.
This commit is contained in:
Alexandre Gomes Gaigalas 2026-01-29 20:35:35 -03:00
commit ec16b3d2df
50 changed files with 282 additions and 363 deletions

View file

@ -0,0 +1,35 @@
<!--
SPDX-FileCopyrightText: (c) Respect Project Contributors
SPDX-License-Identifier: MIT
-->
# Case Insensitive Validation
For most simple cases, you can use `v::call` wrappers to perform
case normalization before comparison.
For strings:
```php
v::call(strtolower(...), v::contains('cde'))->assert('ABCDEF');
// Validation passes successfully
v::call(strtolower(...), v::contains('xxx'))->assert('ABCDEF');
// → "abcdef" must contain "xxx"
```
For arrays:
```php
v::call(
static fn ($i) => array_map(strtolower(...), $i),
v::contains('abc')
)->assert(['ABC', 'DEF']);
// Validation passes successfully
v::call(
static fn ($i) => array_map(strtolower(...), $i),
v::contains('xxx')
)->assert(['ABC', 'DEF']);
// → `["abc", "def"]` must contain "xxx"
```

View file

@ -296,6 +296,42 @@ v::each(v::alwaysValid())->isValid([]); // false (empty)
+ v::intType()->assert($input);
```
##### Call does not handle errors anymore
`Call` now does not handle PHP errors inside the callback you provided.
```php
v::call('strtolower', v::equals('foo'))->assert(123); // Error bubbles out
```
You can use anonymous functions to handle errors or perform type conversions
instead:
```php
v::call(static fn ($i) => strtolower((string) $i), v::equals('123'));
```
##### `Contains`, `ContainsAny`, `In`, `EndsWith` and `StartsWith` strict by default.
The parameter `$identical`, which controlled case-insensitivy and strict typing was
removed. Now these validators will always compare _case-sensitive_ and use
_strict typing_.
```diff
- v::contains('needle', identical: true);
- v::containsAny(['needle1', 'needle2'], identical: true);
- v::in(['hay', 'stack'], compareIdentical: true);
- v::startsWith('needle', identical: true);
- v::endsWith('needle', identical: true);
+ v::contains('needle'); // always strict case and type
+ v::containsAny(['needle1', 'needle2']); // always strict case and type
+ v::in(['hay', 'stack']); // always strict case and type
+ v::startsWith('needle'); // always strict case and type
+ v::endsWith('needle'); // always strict case and type
```
For more information, refer to [case-sensitiveness.md](case-sensitiveness.md)
##### New package dependencies
Some validators now require additional packages:

View file

@ -52,22 +52,20 @@ v::call(
// Validation passes successfully
```
## Templates
Call does not handle possible errors (type mismatches). If you need to
ensure that your callback is of a certain type, use [Circuit](Circuit.md) or
handle it using a closure:
### `Call::TEMPLATE_STANDARD`
```php
v::call('strtolower', v::equals('ABC'))->assert(123);
// 𝙭 strtolower(): Argument #1 ($string) must be of type string, int given
| Mode | Template |
| ---------: | :--------------------------------------------------------- |
| `default` | {{input}} must be a suitable argument for {{callable}} |
| `inverted` | {{input}} must not be a suitable argument for {{callable}} |
v::circuit(v::stringType(), v::call('strtolower', v::equals('abc')))->assert(123);
// → 123 must be a string
## Template placeholders
| Placeholder | Description |
| ----------- | ---------------------------------------------------------------- |
| `callable` | |
| `input` | |
| `subject` | The validated input or the custom validator name (if specified). |
v::circuit(v::stringType(), v::call('strtolower', v::equals('abc')))->assert('ABC');
// Validation passes successfully
```
## Categorization
@ -77,9 +75,10 @@ v::call(
## Changelog
| Version | Description |
| ------: | :---------- |
| 0.3.9 | Created |
| Version | Description |
| ------: | :---------------------------- |
| 3.0.0 | No longer sets error handlers |
| 0.3.9 | Created |
## See Also

View file

@ -6,7 +6,6 @@ SPDX-License-Identifier: MIT
# Contains
- `Contains(mixed $containsValue)`
- `Contains(mixed $containsValue, bool $identical)`
Validates if the input contains some value.
@ -24,9 +23,6 @@ v::contains('ipsum')->assert(['ipsum', 'lorem']);
// Validation passes successfully
```
A second parameter may be passed for identical comparison instead
of equal comparison.
Message template for this validator includes `{{containsValue}}`.
## Templates
@ -52,9 +48,10 @@ Message template for this validator includes `{{containsValue}}`.
## Changelog
| Version | Description |
| ------: | :---------- |
| 0.3.9 | Created |
| Version | Description |
| ------: | :---------------------------------- |
| 3.0.0 | Case-insensitive comparison removed |
| 0.3.9 | Created |
## See Also

View file

@ -6,27 +6,23 @@ SPDX-License-Identifier: MIT
# ContainsAny
- `ContainsAny(non-empty-array<mixed> $needles)`
- `ContainsAny(non-empty-array<mixed> $needles, bool $identical)`
Validates if the input contains at least one of defined values
For strings (comparing is case insensitive):
For strings:
```php
v::containsAny(['lorem', 'dolor'])->assert('lorem ipsum');
// Validation passes successfully
```
For arrays (comparing is case sensitive to respect "contains" behavior):
For arrays:
```php
v::containsAny(['lorem', 'dolor'])->assert(['ipsum', 'lorem']);
// Validation passes successfully
```
A second parameter may be passed for identical comparison instead
of equal comparison for arrays.
Message template for this validator includes `{{needles}}`.
## Templates
@ -52,9 +48,10 @@ Message template for this validator includes `{{needles}}`.
## Changelog
| Version | Description |
| ------: | :---------- |
| 2.0.0 | Created |
| Version | Description |
| ------: | :---------------------------------- |
| 3.0.0 | Case-insensitive comparison removed |
| 2.0.0 | Created |
## See Also

View file

@ -6,7 +6,6 @@ SPDX-License-Identifier: MIT
# ContainsCount
- `ContainsCount(mixed $containsValue, int $count)`
- `ContainsCount(mixed $containsValue, int $count, bool $identical)`
Validates if the input contains a value a specific number of times.
@ -24,16 +23,6 @@ v::containsCount('ipsum', 2)->assert(['ipsum', 'lorem', 'ipsum']);
// Validation passes successfully
```
A third parameter may be passed for identical comparison instead of equal comparison.
```php
v::containsCount(1, 1, true)->assert([1, 2, 3]);
// Validation passes successfully
v::containsCount('1', 1, true)->assert([1, 2, 3]);
// → `[1, 2, 3]` must contain "1" only once
```
## Templates
### `ContainsCount::TEMPLATE_TIMES`

View file

@ -6,7 +6,6 @@ SPDX-License-Identifier: MIT
# EndsWith
- `EndsWith(mixed $endValue)`
- `EndsWith(mixed $endValue, bool $identical)`
This validator is similar to `Contains()`, but validates
only if the value is at the end of the input.
@ -25,9 +24,6 @@ v::endsWith('ipsum')->assert(['lorem', 'ipsum']);
// Validation passes successfully
```
A second parameter may be passed for identical comparison instead
of equal comparison.
Message template for this validator includes `{{endValue}}`.
## Templates
@ -53,9 +49,10 @@ Message template for this validator includes `{{endValue}}`.
## Changelog
| Version | Description |
| ------: | :---------- |
| 0.3.9 | Created |
| Version | Description |
| ------: | :---------------------------------- |
| 3.0.0 | Case-insensitive comparison removed |
| 0.3.9 | Created |
## See Also

View file

@ -6,7 +6,6 @@ SPDX-License-Identifier: MIT
# In
- `In(mixed $haystack)`
- `In(mixed $haystack, bool $compareIdentical)`
Validates if the input is contained in a specific haystack.
@ -24,9 +23,6 @@ v::in(['lorem', 'ipsum'])->assert('lorem');
// Validation passes successfully
```
A second parameter may be passed for identical comparison instead
of equal comparison.
Message template for this validator includes `{{haystack}}`.
## Templates
@ -53,9 +49,10 @@ Message template for this validator includes `{{haystack}}`.
## Changelog
| Version | Description |
| ------: | :---------- |
| 0.3.9 | Created |
| Version | Description |
| ------: | :---------------------------------- |
| 3.0.0 | Case-insensitive comparison removed |
| 0.3.9 | Created |
## See Also

View file

@ -6,7 +6,6 @@ SPDX-License-Identifier: MIT
# StartsWith
- `StartsWith(mixed $startValue)`
- `StartsWith(mixed $startValue, bool $identical)`
Validates whether the input starts with a given value.
@ -27,9 +26,6 @@ v::startsWith('lorem')->assert(['lorem', 'ipsum']);
// Validation passes successfully
```
`true` may be passed as a parameter to indicate identical comparison
instead of equal.
Message template for this validator includes `{{startValue}}`.
## Templates
@ -55,9 +51,10 @@ Message template for this validator includes `{{startValue}}`.
## Changelog
| Version | Description |
| ------: | :---------- |
| 0.3.9 | Created |
| Version | Description |
| ------: | :---------------------------------- |
| 3.0.0 | Case-insensitive comparison removed |
| 0.3.9 | Created |
## See Also

View file

@ -64,12 +64,12 @@ interface AllBuilder
public static function allConsonant(string ...$additionalChars): Chain;
public static function allContains(mixed $containsValue, bool $identical = false): Chain;
public static function allContains(mixed $containsValue): Chain;
/** @param non-empty-array<mixed> $needles */
public static function allContainsAny(array $needles, bool $identical = false): Chain;
public static function allContainsAny(array $needles): Chain;
public static function allContainsCount(mixed $containsValue, int $count, bool $identical = false): Chain;
public static function allContainsCount(mixed $containsValue, int $count): Chain;
public static function allControl(string ...$additionalChars): Chain;
@ -106,7 +106,7 @@ interface AllBuilder
public static function allEmoji(): Chain;
public static function allEndsWith(mixed $endValue, bool $identical = false): Chain;
public static function allEndsWith(mixed $endValue): Chain;
public static function allEquals(mixed $compareTo): Chain;
@ -150,7 +150,7 @@ interface AllBuilder
public static function allImei(): Chain;
public static function allIn(mixed $haystack, bool $compareIdentical = false): Chain;
public static function allIn(mixed $haystack): Chain;
public static function allInfinite(): Chain;
@ -266,7 +266,7 @@ interface AllBuilder
public static function allSpaced(): Chain;
public static function allStartsWith(mixed $startValue, bool $identical = false): Chain;
public static function allStartsWith(mixed $startValue): Chain;
public static function allStringType(): Chain;

View file

@ -64,12 +64,12 @@ interface AllChain
public function allConsonant(string ...$additionalChars): Chain;
public function allContains(mixed $containsValue, bool $identical = false): Chain;
public function allContains(mixed $containsValue): Chain;
/** @param non-empty-array<mixed> $needles */
public function allContainsAny(array $needles, bool $identical = false): Chain;
public function allContainsAny(array $needles): Chain;
public function allContainsCount(mixed $containsValue, int $count, bool $identical = false): Chain;
public function allContainsCount(mixed $containsValue, int $count): Chain;
public function allControl(string ...$additionalChars): Chain;
@ -106,7 +106,7 @@ interface AllChain
public function allEmoji(): Chain;
public function allEndsWith(mixed $endValue, bool $identical = false): Chain;
public function allEndsWith(mixed $endValue): Chain;
public function allEquals(mixed $compareTo): Chain;
@ -150,7 +150,7 @@ interface AllChain
public function allImei(): Chain;
public function allIn(mixed $haystack, bool $compareIdentical = false): Chain;
public function allIn(mixed $haystack): Chain;
public function allInfinite(): Chain;
@ -266,7 +266,7 @@ interface AllChain
public function allSpaced(): Chain;
public function allStartsWith(mixed $startValue, bool $identical = false): Chain;
public function allStartsWith(mixed $startValue): Chain;
public function allStringType(): Chain;

View file

@ -69,12 +69,12 @@ interface Builder extends AllBuilder, KeyBuilder, LengthBuilder, MaxBuilder, Min
public static function consonant(string ...$additionalChars): Chain;
public static function contains(mixed $containsValue, bool $identical = false): Chain;
public static function contains(mixed $containsValue): Chain;
/** @param non-empty-array<mixed> $needles */
public static function containsAny(array $needles, bool $identical = false): Chain;
public static function containsAny(array $needles): Chain;
public static function containsCount(mixed $containsValue, int $count, bool $identical = false): Chain;
public static function containsCount(mixed $containsValue, int $count): Chain;
public static function control(string ...$additionalChars): Chain;
@ -111,7 +111,7 @@ interface Builder extends AllBuilder, KeyBuilder, LengthBuilder, MaxBuilder, Min
public static function emoji(): Chain;
public static function endsWith(mixed $endValue, bool $identical = false): Chain;
public static function endsWith(mixed $endValue): Chain;
public static function equals(mixed $compareTo): Chain;
@ -157,7 +157,7 @@ interface Builder extends AllBuilder, KeyBuilder, LengthBuilder, MaxBuilder, Min
public static function imei(): Chain;
public static function in(mixed $haystack, bool $compareIdentical = false): Chain;
public static function in(mixed $haystack): Chain;
public static function infinite(): Chain;
@ -291,7 +291,7 @@ interface Builder extends AllBuilder, KeyBuilder, LengthBuilder, MaxBuilder, Min
public static function spaced(): Chain;
public static function startsWith(mixed $startValue, bool $identical = false): Chain;
public static function startsWith(mixed $startValue): Chain;
public static function stringType(): Chain;

View file

@ -71,12 +71,12 @@ interface Chain extends Validator, AllChain, KeyChain, LengthChain, MaxChain, Mi
public function consonant(string ...$additionalChars): Chain;
public function contains(mixed $containsValue, bool $identical = false): Chain;
public function contains(mixed $containsValue): Chain;
/** @param non-empty-array<mixed> $needles */
public function containsAny(array $needles, bool $identical = false): Chain;
public function containsAny(array $needles): Chain;
public function containsCount(mixed $containsValue, int $count, bool $identical = false): Chain;
public function containsCount(mixed $containsValue, int $count): Chain;
public function control(string ...$additionalChars): Chain;
@ -113,7 +113,7 @@ interface Chain extends Validator, AllChain, KeyChain, LengthChain, MaxChain, Mi
public function emoji(): Chain;
public function endsWith(mixed $endValue, bool $identical = false): Chain;
public function endsWith(mixed $endValue): Chain;
public function equals(mixed $compareTo): Chain;
@ -159,7 +159,7 @@ interface Chain extends Validator, AllChain, KeyChain, LengthChain, MaxChain, Mi
public function imei(): Chain;
public function in(mixed $haystack, bool $compareIdentical = false): Chain;
public function in(mixed $haystack): Chain;
public function infinite(): Chain;
@ -293,7 +293,7 @@ interface Chain extends Validator, AllChain, KeyChain, LengthChain, MaxChain, Mi
public function spaced(): Chain;
public function startsWith(mixed $startValue, bool $identical = false): Chain;
public function startsWith(mixed $startValue): Chain;
public function stringType(): Chain;

View file

@ -66,12 +66,12 @@ interface KeyBuilder
public static function keyConsonant(int|string $key, string ...$additionalChars): Chain;
public static function keyContains(int|string $key, mixed $containsValue, bool $identical = false): Chain;
public static function keyContains(int|string $key, mixed $containsValue): Chain;
/** @param non-empty-array<mixed> $needles */
public static function keyContainsAny(int|string $key, array $needles, bool $identical = false): Chain;
public static function keyContainsAny(int|string $key, array $needles): Chain;
public static function keyContainsCount(int|string $key, mixed $containsValue, int $count, bool $identical = false): Chain;
public static function keyContainsCount(int|string $key, mixed $containsValue, int $count): Chain;
public static function keyControl(int|string $key, string ...$additionalChars): Chain;
@ -108,7 +108,7 @@ interface KeyBuilder
public static function keyEmoji(int|string $key): Chain;
public static function keyEndsWith(int|string $key, mixed $endValue, bool $identical = false): Chain;
public static function keyEndsWith(int|string $key, mixed $endValue): Chain;
public static function keyEquals(int|string $key, mixed $compareTo): Chain;
@ -152,7 +152,7 @@ interface KeyBuilder
public static function keyImei(int|string $key): Chain;
public static function keyIn(int|string $key, mixed $haystack, bool $compareIdentical = false): Chain;
public static function keyIn(int|string $key, mixed $haystack): Chain;
public static function keyInfinite(int|string $key): Chain;
@ -268,7 +268,7 @@ interface KeyBuilder
public static function keySpaced(int|string $key): Chain;
public static function keyStartsWith(int|string $key, mixed $startValue, bool $identical = false): Chain;
public static function keyStartsWith(int|string $key, mixed $startValue): Chain;
public static function keyStringType(int|string $key): Chain;

View file

@ -66,12 +66,12 @@ interface KeyChain
public function keyConsonant(int|string $key, string ...$additionalChars): Chain;
public function keyContains(int|string $key, mixed $containsValue, bool $identical = false): Chain;
public function keyContains(int|string $key, mixed $containsValue): Chain;
/** @param non-empty-array<mixed> $needles */
public function keyContainsAny(int|string $key, array $needles, bool $identical = false): Chain;
public function keyContainsAny(int|string $key, array $needles): Chain;
public function keyContainsCount(int|string $key, mixed $containsValue, int $count, bool $identical = false): Chain;
public function keyContainsCount(int|string $key, mixed $containsValue, int $count): Chain;
public function keyControl(int|string $key, string ...$additionalChars): Chain;
@ -108,7 +108,7 @@ interface KeyChain
public function keyEmoji(int|string $key): Chain;
public function keyEndsWith(int|string $key, mixed $endValue, bool $identical = false): Chain;
public function keyEndsWith(int|string $key, mixed $endValue): Chain;
public function keyEquals(int|string $key, mixed $compareTo): Chain;
@ -152,7 +152,7 @@ interface KeyChain
public function keyImei(int|string $key): Chain;
public function keyIn(int|string $key, mixed $haystack, bool $compareIdentical = false): Chain;
public function keyIn(int|string $key, mixed $haystack): Chain;
public function keyInfinite(int|string $key): Chain;
@ -268,7 +268,7 @@ interface KeyChain
public function keySpaced(int|string $key): Chain;
public function keyStartsWith(int|string $key, mixed $startValue, bool $identical = false): Chain;
public function keyStartsWith(int|string $key, mixed $startValue): Chain;
public function keyStringType(int|string $key): Chain;

View file

@ -32,7 +32,7 @@ interface LengthBuilder
public static function lengthIdentical(mixed $compareTo): Chain;
public static function lengthIn(mixed $haystack, bool $compareIdentical = false): Chain;
public static function lengthIn(mixed $haystack): Chain;
public static function lengthInfinite(): Chain;

View file

@ -32,7 +32,7 @@ interface LengthChain
public function lengthIdentical(mixed $compareTo): Chain;
public function lengthIn(mixed $haystack, bool $compareIdentical = false): Chain;
public function lengthIn(mixed $haystack): Chain;
public function lengthInfinite(): Chain;

View file

@ -32,7 +32,7 @@ interface MaxBuilder
public static function maxIdentical(mixed $compareTo): Chain;
public static function maxIn(mixed $haystack, bool $compareIdentical = false): Chain;
public static function maxIn(mixed $haystack): Chain;
public static function maxInfinite(): Chain;

View file

@ -32,7 +32,7 @@ interface MaxChain
public function maxIdentical(mixed $compareTo): Chain;
public function maxIn(mixed $haystack, bool $compareIdentical = false): Chain;
public function maxIn(mixed $haystack): Chain;
public function maxInfinite(): Chain;

View file

@ -32,7 +32,7 @@ interface MinBuilder
public static function minIdentical(mixed $compareTo): Chain;
public static function minIn(mixed $haystack, bool $compareIdentical = false): Chain;
public static function minIn(mixed $haystack): Chain;
public static function minInfinite(): Chain;

View file

@ -32,7 +32,7 @@ interface MinChain
public function minIdentical(mixed $compareTo): Chain;
public function minIn(mixed $haystack, bool $compareIdentical = false): Chain;
public function minIn(mixed $haystack): Chain;
public function minInfinite(): Chain;

View file

@ -66,12 +66,12 @@ interface NotBuilder
public static function notConsonant(string ...$additionalChars): Chain;
public static function notContains(mixed $containsValue, bool $identical = false): Chain;
public static function notContains(mixed $containsValue): Chain;
/** @param non-empty-array<mixed> $needles */
public static function notContainsAny(array $needles, bool $identical = false): Chain;
public static function notContainsAny(array $needles): Chain;
public static function notContainsCount(mixed $containsValue, int $count, bool $identical = false): Chain;
public static function notContainsCount(mixed $containsValue, int $count): Chain;
public static function notControl(string ...$additionalChars): Chain;
@ -108,7 +108,7 @@ interface NotBuilder
public static function notEmoji(): Chain;
public static function notEndsWith(mixed $endValue, bool $identical = false): Chain;
public static function notEndsWith(mixed $endValue): Chain;
public static function notEquals(mixed $compareTo): Chain;
@ -154,7 +154,7 @@ interface NotBuilder
public static function notImei(): Chain;
public static function notIn(mixed $haystack, bool $compareIdentical = false): Chain;
public static function notIn(mixed $haystack): Chain;
public static function notInfinite(): Chain;
@ -282,7 +282,7 @@ interface NotBuilder
public static function notSpaced(): Chain;
public static function notStartsWith(mixed $startValue, bool $identical = false): Chain;
public static function notStartsWith(mixed $startValue): Chain;
public static function notStringType(): Chain;

View file

@ -66,12 +66,12 @@ interface NotChain
public function notConsonant(string ...$additionalChars): Chain;
public function notContains(mixed $containsValue, bool $identical = false): Chain;
public function notContains(mixed $containsValue): Chain;
/** @param non-empty-array<mixed> $needles */
public function notContainsAny(array $needles, bool $identical = false): Chain;
public function notContainsAny(array $needles): Chain;
public function notContainsCount(mixed $containsValue, int $count, bool $identical = false): Chain;
public function notContainsCount(mixed $containsValue, int $count): Chain;
public function notControl(string ...$additionalChars): Chain;
@ -108,7 +108,7 @@ interface NotChain
public function notEmoji(): Chain;
public function notEndsWith(mixed $endValue, bool $identical = false): Chain;
public function notEndsWith(mixed $endValue): Chain;
public function notEquals(mixed $compareTo): Chain;
@ -154,7 +154,7 @@ interface NotChain
public function notImei(): Chain;
public function notIn(mixed $haystack, bool $compareIdentical = false): Chain;
public function notIn(mixed $haystack): Chain;
public function notInfinite(): Chain;
@ -282,7 +282,7 @@ interface NotChain
public function notSpaced(): Chain;
public function notStartsWith(mixed $startValue, bool $identical = false): Chain;
public function notStartsWith(mixed $startValue): Chain;
public function notStringType(): Chain;

View file

@ -66,12 +66,12 @@ interface NullOrBuilder
public static function nullOrConsonant(string ...$additionalChars): Chain;
public static function nullOrContains(mixed $containsValue, bool $identical = false): Chain;
public static function nullOrContains(mixed $containsValue): Chain;
/** @param non-empty-array<mixed> $needles */
public static function nullOrContainsAny(array $needles, bool $identical = false): Chain;
public static function nullOrContainsAny(array $needles): Chain;
public static function nullOrContainsCount(mixed $containsValue, int $count, bool $identical = false): Chain;
public static function nullOrContainsCount(mixed $containsValue, int $count): Chain;
public static function nullOrControl(string ...$additionalChars): Chain;
@ -108,7 +108,7 @@ interface NullOrBuilder
public static function nullOrEmoji(): Chain;
public static function nullOrEndsWith(mixed $endValue, bool $identical = false): Chain;
public static function nullOrEndsWith(mixed $endValue): Chain;
public static function nullOrEquals(mixed $compareTo): Chain;
@ -154,7 +154,7 @@ interface NullOrBuilder
public static function nullOrImei(): Chain;
public static function nullOrIn(mixed $haystack, bool $compareIdentical = false): Chain;
public static function nullOrIn(mixed $haystack): Chain;
public static function nullOrInfinite(): Chain;
@ -284,7 +284,7 @@ interface NullOrBuilder
public static function nullOrSpaced(): Chain;
public static function nullOrStartsWith(mixed $startValue, bool $identical = false): Chain;
public static function nullOrStartsWith(mixed $startValue): Chain;
public static function nullOrStringType(): Chain;

View file

@ -66,12 +66,12 @@ interface NullOrChain
public function nullOrConsonant(string ...$additionalChars): Chain;
public function nullOrContains(mixed $containsValue, bool $identical = false): Chain;
public function nullOrContains(mixed $containsValue): Chain;
/** @param non-empty-array<mixed> $needles */
public function nullOrContainsAny(array $needles, bool $identical = false): Chain;
public function nullOrContainsAny(array $needles): Chain;
public function nullOrContainsCount(mixed $containsValue, int $count, bool $identical = false): Chain;
public function nullOrContainsCount(mixed $containsValue, int $count): Chain;
public function nullOrControl(string ...$additionalChars): Chain;
@ -108,7 +108,7 @@ interface NullOrChain
public function nullOrEmoji(): Chain;
public function nullOrEndsWith(mixed $endValue, bool $identical = false): Chain;
public function nullOrEndsWith(mixed $endValue): Chain;
public function nullOrEquals(mixed $compareTo): Chain;
@ -154,7 +154,7 @@ interface NullOrChain
public function nullOrImei(): Chain;
public function nullOrIn(mixed $haystack, bool $compareIdentical = false): Chain;
public function nullOrIn(mixed $haystack): Chain;
public function nullOrInfinite(): Chain;
@ -284,7 +284,7 @@ interface NullOrChain
public function nullOrSpaced(): Chain;
public function nullOrStartsWith(mixed $startValue, bool $identical = false): Chain;
public function nullOrStartsWith(mixed $startValue): Chain;
public function nullOrStringType(): Chain;

View file

@ -66,12 +66,12 @@ interface PropertyBuilder
public static function propertyConsonant(string $propertyName, string ...$additionalChars): Chain;
public static function propertyContains(string $propertyName, mixed $containsValue, bool $identical = false): Chain;
public static function propertyContains(string $propertyName, mixed $containsValue): Chain;
/** @param non-empty-array<mixed> $needles */
public static function propertyContainsAny(string $propertyName, array $needles, bool $identical = false): Chain;
public static function propertyContainsAny(string $propertyName, array $needles): Chain;
public static function propertyContainsCount(string $propertyName, mixed $containsValue, int $count, bool $identical = false): Chain;
public static function propertyContainsCount(string $propertyName, mixed $containsValue, int $count): Chain;
public static function propertyControl(string $propertyName, string ...$additionalChars): Chain;
@ -108,7 +108,7 @@ interface PropertyBuilder
public static function propertyEmoji(string $propertyName): Chain;
public static function propertyEndsWith(string $propertyName, mixed $endValue, bool $identical = false): Chain;
public static function propertyEndsWith(string $propertyName, mixed $endValue): Chain;
public static function propertyEquals(string $propertyName, mixed $compareTo): Chain;
@ -152,7 +152,7 @@ interface PropertyBuilder
public static function propertyImei(string $propertyName): Chain;
public static function propertyIn(string $propertyName, mixed $haystack, bool $compareIdentical = false): Chain;
public static function propertyIn(string $propertyName, mixed $haystack): Chain;
public static function propertyInfinite(string $propertyName): Chain;
@ -268,7 +268,7 @@ interface PropertyBuilder
public static function propertySpaced(string $propertyName): Chain;
public static function propertyStartsWith(string $propertyName, mixed $startValue, bool $identical = false): Chain;
public static function propertyStartsWith(string $propertyName, mixed $startValue): Chain;
public static function propertyStringType(string $propertyName): Chain;

View file

@ -66,12 +66,12 @@ interface PropertyChain
public function propertyConsonant(string $propertyName, string ...$additionalChars): Chain;
public function propertyContains(string $propertyName, mixed $containsValue, bool $identical = false): Chain;
public function propertyContains(string $propertyName, mixed $containsValue): Chain;
/** @param non-empty-array<mixed> $needles */
public function propertyContainsAny(string $propertyName, array $needles, bool $identical = false): Chain;
public function propertyContainsAny(string $propertyName, array $needles): Chain;
public function propertyContainsCount(string $propertyName, mixed $containsValue, int $count, bool $identical = false): Chain;
public function propertyContainsCount(string $propertyName, mixed $containsValue, int $count): Chain;
public function propertyControl(string $propertyName, string ...$additionalChars): Chain;
@ -108,7 +108,7 @@ interface PropertyChain
public function propertyEmoji(string $propertyName): Chain;
public function propertyEndsWith(string $propertyName, mixed $endValue, bool $identical = false): Chain;
public function propertyEndsWith(string $propertyName, mixed $endValue): Chain;
public function propertyEquals(string $propertyName, mixed $compareTo): Chain;
@ -152,7 +152,7 @@ interface PropertyChain
public function propertyImei(string $propertyName): Chain;
public function propertyIn(string $propertyName, mixed $haystack, bool $compareIdentical = false): Chain;
public function propertyIn(string $propertyName, mixed $haystack): Chain;
public function propertyInfinite(string $propertyName): Chain;
@ -268,7 +268,7 @@ interface PropertyChain
public function propertySpaced(string $propertyName): Chain;
public function propertyStartsWith(string $propertyName, mixed $startValue, bool $identical = false): Chain;
public function propertyStartsWith(string $propertyName, mixed $startValue): Chain;
public function propertyStringType(string $propertyName): Chain;

View file

@ -64,12 +64,12 @@ interface UndefOrBuilder
public static function undefOrConsonant(string ...$additionalChars): Chain;
public static function undefOrContains(mixed $containsValue, bool $identical = false): Chain;
public static function undefOrContains(mixed $containsValue): Chain;
/** @param non-empty-array<mixed> $needles */
public static function undefOrContainsAny(array $needles, bool $identical = false): Chain;
public static function undefOrContainsAny(array $needles): Chain;
public static function undefOrContainsCount(mixed $containsValue, int $count, bool $identical = false): Chain;
public static function undefOrContainsCount(mixed $containsValue, int $count): Chain;
public static function undefOrControl(string ...$additionalChars): Chain;
@ -106,7 +106,7 @@ interface UndefOrBuilder
public static function undefOrEmoji(): Chain;
public static function undefOrEndsWith(mixed $endValue, bool $identical = false): Chain;
public static function undefOrEndsWith(mixed $endValue): Chain;
public static function undefOrEquals(mixed $compareTo): Chain;
@ -152,7 +152,7 @@ interface UndefOrBuilder
public static function undefOrImei(): Chain;
public static function undefOrIn(mixed $haystack, bool $compareIdentical = false): Chain;
public static function undefOrIn(mixed $haystack): Chain;
public static function undefOrInfinite(): Chain;
@ -282,7 +282,7 @@ interface UndefOrBuilder
public static function undefOrSpaced(): Chain;
public static function undefOrStartsWith(mixed $startValue, bool $identical = false): Chain;
public static function undefOrStartsWith(mixed $startValue): Chain;
public static function undefOrStringType(): Chain;

View file

@ -64,12 +64,12 @@ interface UndefOrChain
public function undefOrConsonant(string ...$additionalChars): Chain;
public function undefOrContains(mixed $containsValue, bool $identical = false): Chain;
public function undefOrContains(mixed $containsValue): Chain;
/** @param non-empty-array<mixed> $needles */
public function undefOrContainsAny(array $needles, bool $identical = false): Chain;
public function undefOrContainsAny(array $needles): Chain;
public function undefOrContainsCount(mixed $containsValue, int $count, bool $identical = false): Chain;
public function undefOrContainsCount(mixed $containsValue, int $count): Chain;
public function undefOrControl(string ...$additionalChars): Chain;
@ -106,7 +106,7 @@ interface UndefOrChain
public function undefOrEmoji(): Chain;
public function undefOrEndsWith(mixed $endValue, bool $identical = false): Chain;
public function undefOrEndsWith(mixed $endValue): Chain;
public function undefOrEquals(mixed $compareTo): Chain;
@ -152,7 +152,7 @@ interface UndefOrChain
public function undefOrImei(): Chain;
public function undefOrIn(mixed $haystack, bool $compareIdentical = false): Chain;
public function undefOrIn(mixed $haystack): Chain;
public function undefOrInfinite(): Chain;
@ -282,7 +282,7 @@ interface UndefOrChain
public function undefOrSpaced(): Chain;
public function undefOrStartsWith(mixed $startValue, bool $identical = false): Chain;
public function undefOrStartsWith(mixed $startValue): Chain;
public function undefOrStringType(): Chain;

View file

@ -17,21 +17,12 @@ declare(strict_types=1);
namespace Respect\Validation\Validators;
use Attribute;
use ErrorException;
use Respect\Validation\Message\Template;
use Respect\Validation\Result;
use Respect\Validation\Validator;
use Throwable;
use function call_user_func;
use function restore_error_handler;
use function set_error_handler;
#[Attribute(Attribute::TARGET_PROPERTY | Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)]
#[Template(
'{{input}} must be a suitable argument for {{callable}}',
'{{input}} must not be a suitable argument for {{callable}}',
)]
final class Call implements Validator
{
/** @var callable */
@ -46,18 +37,6 @@ final class Call implements Validator
public function evaluate(mixed $input): Result
{
set_error_handler(static function (int $severity, string $message, string|null $filename, int $line): void {
throw new ErrorException($message, 0, $severity, $filename, $line);
});
try {
$result = $this->validator->evaluate(call_user_func($this->callable, $input));
} catch (Throwable) {
$result = Result::failed($input, $this, ['callable' => $this->callable]);
}
restore_error_handler();
return $result;
return $this->validator->evaluate(call_user_func($this->callable, $input));
}
}

View file

@ -23,7 +23,6 @@ use Respect\Validation\Validator;
use function in_array;
use function is_array;
use function is_scalar;
use function mb_stripos;
use function mb_strpos;
#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)]
@ -33,17 +32,15 @@ use function mb_strpos;
)]
final readonly class Contains implements Validator
{
public function __construct(
private mixed $containsValue,
private bool $identical = false,
) {
public function __construct(private mixed $containsValue)
{
}
public function evaluate(mixed $input): Result
{
$parameters = ['containsValue' => $this->containsValue];
if (is_array($input)) {
return Result::of(in_array($this->containsValue, $input, $this->identical), $input, $this, $parameters);
return Result::of(in_array($this->containsValue, $input, strict: true), $input, $this, $parameters);
}
if (!is_scalar($input) || !is_scalar($this->containsValue)) {
@ -64,10 +61,6 @@ final readonly class Contains implements Validator
return false;
}
if ($this->identical) {
return mb_strpos($haystack, $needle) !== false;
}
return mb_stripos($haystack, $needle) !== false;
return mb_strpos($haystack, $needle) !== false;
}
}

View file

@ -28,13 +28,13 @@ use function count;
final class ContainsAny extends Envelope
{
/** @param non-empty-array<mixed> $needles */
public function __construct(array $needles, bool $identical = false)
public function __construct(array $needles)
{
if (empty($needles)) {
throw new InvalidValidatorException('At least one value must be provided');
}
$validators = $this->getValidators($needles, $identical);
$validators = $this->getValidators($needles);
parent::__construct(
count($validators) === 1 ? $validators[0] : new AnyOf(...$validators),
@ -47,12 +47,10 @@ final class ContainsAny extends Envelope
*
* @return Contains[]
*/
private function getValidators(array $needles, bool $identical): array
private function getValidators(array $needles): array
{
return array_map(
static function ($needle) use ($identical): Contains {
return new Contains($needle, $identical);
},
static fn($needle): Contains => new Contains($needle),
$needles,
);
}

View file

@ -18,7 +18,6 @@ use Respect\Validation\Validator;
use function array_reduce;
use function is_array;
use function is_scalar;
use function mb_strtolower;
use function mb_substr_count;
#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)]
@ -40,7 +39,6 @@ final readonly class ContainsCount implements Validator
public function __construct(
private mixed $containsValue,
private int $count,
private bool $identical = false,
) {
}
@ -74,7 +72,7 @@ final readonly class ContainsCount implements Validator
}
return Result::of(
$this->countStringOccurrences((string) $input, $needle) === $this->count,
mb_substr_count((string) $input, $needle) === $this->count,
$input,
$this,
$parameters,
@ -87,21 +85,10 @@ final readonly class ContainsCount implements Validator
{
return array_reduce(
$input,
$this->identical ? function (int $carry, mixed $item): int {
function (int $carry, mixed $item): int {
return $carry + ($item === $this->containsValue ? 1 : 0);
} : function (int $carry, mixed $item): int {
return $carry + ($item == $this->containsValue ? 1 : 0);
},
0,
);
}
private function countStringOccurrences(string $haystack, string $needle): int
{
if ($this->identical) {
return mb_substr_count($haystack, $needle);
}
return mb_substr_count(mb_strtolower($haystack), mb_strtolower($needle));
}
}

View file

@ -23,7 +23,6 @@ use Respect\Validation\Validator;
use function end;
use function is_array;
use function mb_strlen;
use function mb_strripos;
use function mb_strrpos;
#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)]
@ -35,27 +34,14 @@ final readonly class EndsWith implements Validator
{
public function __construct(
private mixed $endValue,
private bool $identical = false,
) {
}
public function evaluate(mixed $input): Result
{
$parameters = ['endValue' => $this->endValue];
if ($this->identical) {
return Result::of($this->validateIdentical($input), $input, $this, $parameters);
}
return Result::of($this->validateEquals($input), $input, $this, $parameters);
}
private function validateEquals(mixed $input): bool
{
if (is_array($input)) {
return end($input) == $this->endValue;
}
return mb_strripos($input, $this->endValue) === mb_strlen($input) - mb_strlen($this->endValue);
return Result::of($this->validateIdentical($input), $input, $this, $parameters);
}
private function validateIdentical(mixed $input): bool

View file

@ -22,7 +22,6 @@ use Respect\Validation\Validator;
use function in_array;
use function is_array;
use function mb_stripos;
use function mb_strpos;
#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)]
@ -34,37 +33,20 @@ final readonly class In implements Validator
{
public function __construct(
private mixed $haystack,
private bool $compareIdentical = false,
) {
}
public function evaluate(mixed $input): Result
{
$parameters = ['haystack' => $this->haystack];
if ($this->compareIdentical) {
return Result::of($this->validateIdentical($input), $input, $this, $parameters);
}
return Result::of($this->validateEquals($input), $input, $this, $parameters);
return Result::of($this->validate($input), $input, $this, $parameters);
}
private function validateEquals(mixed $input): bool
private function validate(mixed $input): bool
{
if (is_array($this->haystack)) {
return in_array($input, $this->haystack);
}
if ($input === null || $input === '') {
return $input == $this->haystack;
}
return mb_stripos($this->haystack, (string) $input) !== false;
}
private function validateIdentical(mixed $input): bool
{
if (is_array($this->haystack)) {
return in_array($input, $this->haystack, true);
return in_array($input, $this->haystack, strict: true);
}
if ($input === null || $input === '') {

View file

@ -22,7 +22,6 @@ use Respect\Validation\Validator;
use function is_array;
use function is_string;
use function mb_stripos;
use function mb_strpos;
use function reset;
@ -35,31 +34,14 @@ final readonly class StartsWith implements Validator
{
public function __construct(
private mixed $startValue,
private bool $identical = false,
) {
}
public function evaluate(mixed $input): Result
{
$parameters = ['startValue' => $this->startValue];
if ($this->identical) {
return Result::of($this->validateIdentical($input), $input, $this, $parameters);
}
return Result::of($this->validateEquals($input), $input, $this, $parameters);
}
protected function validateEquals(mixed $input): bool
{
if (is_array($input)) {
return reset($input) == $this->startValue;
}
if (is_string($input) && is_string($this->startValue)) {
return mb_stripos($input, $this->startValue) === 0;
}
return false;
return Result::of($this->validateIdentical($input), $input, $this, $parameters);
}
protected function validateIdentical(mixed $input): bool

View file

@ -23,6 +23,9 @@ final class Tld extends Envelope
{
public function __construct()
{
parent::__construct(new Call('mb_strtoupper', new In(DataLoader::load('domain/tld.php'))));
parent::__construct(new Circuit(
new StringType(),
new Call('mb_strtoupper', new In(DataLoader::load('domain/tld.php'))),
));
}
}

View file

@ -18,22 +18,12 @@ test('Scenario #2', catchMessage(
fn(string $message) => expect($message)->toBe('" something " must not be a string'),
));
test('Scenario #3', catchMessage(
fn() => v::call('stripslashes', v::alwaysValid())->assert([]),
fn(string $message) => expect($message)->toBe('`[]` must be a suitable argument for "stripslashes"'),
));
test('Scenario #4', catchFullMessage(
test('Scenario #3', catchFullMessage(
fn() => v::call('strval', v::intType())->assert(1234),
fn(string $fullMessage) => expect($fullMessage)->toBe('- "1234" must be an integer'),
));
test('Scenario #5', catchFullMessage(
test('Scenario #4', catchFullMessage(
fn() => v::not(v::call('is_float', v::boolType()))->assert(1.2),
fn(string $fullMessage) => expect($fullMessage)->toBe('- `true` must not be a boolean'),
));
test('Scenario #6', catchFullMessage(
fn() => v::call('array_shift', v::alwaysValid())->assert(INF),
fn(string $fullMessage) => expect($fullMessage)->toBe('- `INF` must be a suitable argument for "array_shift"'),
));

View file

@ -24,6 +24,6 @@ test('Scenario #3', catchFullMessage(
));
test('Scenario #4', catchFullMessage(
fn() => v::not(v::containsAny(['foo', 'bar'], true))->assert(['bar', 'foo']),
fn() => v::not(v::containsAny(['foo', 'bar']))->assert(['bar', 'foo']),
fn(string $fullMessage) => expect($fullMessage)->toBe('- `["bar", "foo"]` must not contain any value from `["foo", "bar"]`'),
));

View file

@ -24,11 +24,11 @@ test('Scenario #3', catchFullMessage(
));
test('Scenario #4', catchFullMessage(
fn() => v::not(v::containsCount('foo', 1, true))->assert(['foo', 'bar']),
fn() => v::not(v::containsCount('foo', 1))->assert(['foo', 'bar']),
fn(string $fullMessage) => expect($fullMessage)->toBe('- `["foo", "bar"]` must not contain "foo" only once'),
));
test('Scenario #5', catchFullMessage(
fn() => v::containsCount('foo', 1, true)->assert(['foo', 'foo']),
fn() => v::containsCount('foo', 1)->assert(['foo', 'foo']),
fn(string $fullMessage) => expect($fullMessage)->toBe('- `["foo", "foo"]` must contain "foo" only once'),
));

View file

@ -24,6 +24,6 @@ test('Scenario #3', catchFullMessage(
));
test('Scenario #4', catchFullMessage(
fn() => v::not(v::contains('foo', true))->assert(['bar', 'foo']),
fn() => v::not(v::contains('foo'))->assert(['bar', 'foo']),
fn(string $fullMessage) => expect($fullMessage)->toBe('- `["bar", "foo"]` must not contain "foo"'),
));

View file

@ -19,11 +19,11 @@ test('Scenario #2', catchMessage(
));
test('Scenario #3', catchFullMessage(
fn() => v::in([2, '1', 3], true)->assert('2'),
fn() => v::in([2, '1', 3])->assert('2'),
fn(string $fullMessage) => expect($fullMessage)->toBe('- "2" must be in `[2, "1", 3]`'),
));
test('Scenario #4', catchFullMessage(
fn() => v::not(v::in([2, '1', 3], true))->assert('1'),
fn() => v::not(v::in([2, '1', 3]))->assert('1'),
fn(string $fullMessage) => expect($fullMessage)->toBe('- "1" must not be in `[2, "1", 3]`'),
));

View file

@ -19,7 +19,7 @@ test('Scenario #2', catchMessage(
));
test('Scenario #3', catchFullMessage(
fn() => v::startsWith('3.3', true)->assert([3.3, 4.4]),
fn() => v::startsWith('3.3')->assert([3.3, 4.4]),
fn(string $fullMessage) => expect($fullMessage)->toBe('- `[3.3, 4.4]` must start with "3.3"'),
));

View file

@ -14,11 +14,11 @@ declare(strict_types=1);
namespace Respect\Validation\Validators;
use Exception;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\Group;
use PHPUnit\Framework\Attributes\Test;
use Respect\Validation\Test\RuleTestCase;
use Respect\Validation\Test\Validators\Stub;
use TypeError;
#[Group('validator')]
#[CoversClass(Call::class)]
@ -28,7 +28,7 @@ final class CallTest extends RuleTestCase
public static function providerForValidInput(): iterable
{
return [
'valid rule and valid callable' => [new Call('trim', Stub::pass(1)), ' input '],
'callback true' => [new Call('strtolower', new Equals('abc')), 'ABC'],
];
}
@ -36,8 +36,16 @@ final class CallTest extends RuleTestCase
public static function providerForInvalidInput(): iterable
{
return [
'PHP error' => [new Call('trim', Stub::pass(1)), []],
'exception' => [new Call(static fn() => throw new Exception(), Stub::pass(1)), []],
'callback false' => [new Call('strtolower', new Equals('abc')), 'DEF'],
];
}
#[Test]
public function shouldLetErrorsEmittedByTheChosenProvidedCallbackToBubbleUp(): void
{
$this->expectException(TypeError::class);
$this->expectExceptionMessage('strtolower(): Argument #1 ($string) must be of type string, int given');
$validator = new Call('strtolower', new Equals('abc'));
$validator->evaluate(123);
}
}

View file

@ -36,14 +36,8 @@ final class ContainsAnyTest extends RuleTestCase
public static function providerForValidInput(): iterable
{
return [
[new ContainsAny(['Something', 'Else']), 'something else'],
[new ContainsAny([true]), [1, 2, 3]],
[new ContainsAny([true], true), [true]],
[new ContainsAny(['1']), [1, 2, 3]],
[new ContainsAny([1], true), [1, 2, 3]],
[new ContainsAny(['word', '@', '/']), 'lorem ipsum @ word'],
[new ContainsAny(['foo', 'qux']), 'foobarbaz'],
[new ContainsAny(['1']), ['foo', 1]],
[new ContainsAny([true]), [true]],
[new ContainsAny([1]), [1, 2, 3]],
[new ContainsAny(['foo', true]), ['foo', 'bar']],
];
}
@ -55,13 +49,8 @@ final class ContainsAnyTest extends RuleTestCase
[new ContainsAny(['foo']), ['bar', 'baz']],
[new ContainsAny(['foo', 'bar']), ['baz', 'qux']],
[new ContainsAny(['foo', 'bar']), ['FOO', 'BAR']],
[new ContainsAny(['foo'], true), ['bar', 'baz']],
[new ContainsAny(['foo', 'bar'], true), ['FOO', 'BAR']],
[new ContainsAny(['whatever']), ''],
[new ContainsAny(['']), 'whatever'],
[new ContainsAny([false]), ''],
[new ContainsAny(['foo', 'qux']), 'barbaz'],
[new ContainsAny([1, 2, 3], true), ['1', '2', '3']],
[new ContainsAny([1, 2, 3]), ['1', '2', '3']],
[new ContainsAny(['word', '@', '/']), 'lorem ipsum'],
];
}

View file

@ -27,16 +27,10 @@ final class ContainsCountTest extends RuleTestCase
[new ContainsCount('foo', 1), 'foo bar'],
[new ContainsCount('foo', 2), 'foo bar foo'],
[new ContainsCount('a', 3), 'banana'],
[new ContainsCount('1', 1, true), ['1', 2, 3]],
[new ContainsCount(1, 1, true), [1, 2, 3]],
[new ContainsCount('A', 3), 'banana'],
[new ContainsCount('foo', 2), 'FOO bar foo'],
[new ContainsCount('A', 0, true), 'banana'],
[new ContainsCount('a', 3, true), 'banana'],
[new ContainsCount('1', 1), ['1', 2, 3]],
[new ContainsCount(1, 1), [1, 2, 3]],
[new ContainsCount('A', 0), 'banana'],
[new ContainsCount('a', 3), 'banana'],
[new ContainsCount('foo', 0), 'bar'],
];
}
@ -48,16 +42,12 @@ final class ContainsCountTest extends RuleTestCase
[new ContainsCount('foo', 2), ['foo', 'bar']],
[new ContainsCount('foo', 2), 'foo bar'],
[new ContainsCount('a', 2), 'banana'],
[new ContainsCount('1', 1, true), [1, 2, 3]],
[new ContainsCount('1', 1), [1, 2, 3]],
[new ContainsCount('A', 2), 'banana'],
[new ContainsCount('A', 3, true), 'banana'],
[new ContainsCount('A', 3), 'banana'],
[new ContainsCount('foo', 2), 'FOO bar foo'],
[new ContainsCount('foo', 1), null],
[new ContainsCount('foo', 1), new stdClass()],
[new ContainsCount('', 1), ''],
];
}

View file

@ -30,15 +30,12 @@ final class ContainsTest extends RuleTestCase
public static function providerForValidInput(): iterable
{
return [
[new Contains('foo', false), ['bar', 'foo']],
[new Contains('foo', false), 'barbazFOO'],
[new Contains('foo', false), 'barbazfoo'],
[new Contains('foo', false), 'foobazfoO'],
[new Contains('1', false), [2, 3, 1]],
[new Contains('1', false), [2, 3, '1']],
[new Contains('foo'), ['bar', 'foo']],
[new Contains('foo'), ['fool', 'foo']],
[new Contains('foo'), 'foobazfoO'],
[new Contains('foo'), 'barbazfoo'],
[new Contains('foo'), 'foobazfoo'],
[new Contains('1'), [2, 3, '1']],
[new Contains('1'), [2, 3, (string) 1]],
[new Contains('1'), [2, 3, '1']],
[new Contains(1), [2, 3, 1]],
@ -49,24 +46,19 @@ final class ContainsTest extends RuleTestCase
public static function providerForInvalidInput(): iterable
{
return [
[new Contains('', false), 'abc'],
[new Contains(null, false), null],
[new Contains(null, false), []],
[new Contains(new stdClass(), false), new stdClass()],
[new Contains('foo', false), ''],
[new Contains('bat', false), ['bar', 'foo']],
[new Contains('foo', false), 'barfaabaz'],
[new Contains('foo', false), 'faabarbaz'],
[new Contains(null, true), null],
[new Contains(null, true), []],
[new Contains(new stdClass(), true), new stdClass()],
[new Contains('foo', true), ''],
[new Contains('bat', true), ['BAT', 'foo']],
[new Contains('bat', true), ['BaT', 'Batata']],
[new Contains('foo', true), 'barfaabaz'],
[new Contains('foo', true), 'barbazFOO'],
[new Contains('foo', true), 'faabarbaz'],
[new Contains(1, true), ['1', 2, 3]],
[new Contains('foo'), 'barbazFOO'],
[new Contains('1'), [2, 3, 1]],
[new Contains(''), 'abc'],
[new Contains(null), null],
[new Contains(null), []],
[new Contains(new stdClass()), new stdClass()],
[new Contains('foo'), ''],
[new Contains('bat'), ['bar', 'foo']],
[new Contains('foo'), 'barfaabaz'],
[new Contains('foo'), 'faabarbaz'],
[new Contains('bat'), ['BAT', 'foo']],
[new Contains('bat'), ['BaT', 'Batata']],
[new Contains(1), ['1', 2, 3]],
];
}
}

View file

@ -28,12 +28,10 @@ final class EndsWithTest extends RuleTestCase
{
return [
[new EndsWith('foo'), ['bar', 'foo']],
[new EndsWith('foo'), 'barbazFOO'],
[new EndsWith('foo'), 'barbazfoo'],
[new EndsWith('foo'), 'foobazfoo'],
[new EndsWith('1'), [2, 3, 1]],
[new EndsWith(1), [2, 3, 1]],
[new EndsWith('1', true), [2, 3, '1']],
[new EndsWith('1'), [2, 3, '1']],
];
}
@ -44,11 +42,12 @@ final class EndsWithTest extends RuleTestCase
[new EndsWith('foo'), ''],
[new EndsWith('bat'), ['bar', 'foo']],
[new EndsWith('foo'), 'barfaabaz'],
[new EndsWith('foo', true), 'barbazFOO'],
[new EndsWith('foo'), 'barbazFOO'],
[new EndsWith('foo'), 'faabarbaz'],
[new EndsWith('foo'), 'baabazfaa'],
[new EndsWith('foo'), 'baafoofaa'],
[new EndsWith('1', true), [1, '1', 3]],
[new EndsWith('1'), [1, '1', 3]],
[new EndsWith('1'), [2, 3, 1]],
];
}
}

View file

@ -36,8 +36,7 @@ final class InTest extends RuleTestCase
[new In('barfoobaz'), 'foo'],
[new In('foobarbaz'), 'foo'],
[new In('barbazfoo'), 'foo'],
[new In([1, 2, 3]), '1'],
[new In(['1', 2, 3], true), '1'],
[new In(['1', 2, 3]), '1'],
];
}
@ -45,11 +44,11 @@ final class InTest extends RuleTestCase
public static function providerForInvalidInput(): iterable
{
return [
[new In('0', true), 'abc'],
[new In('0'), 'abc'],
[new In('0'), null],
[new In(0, true), null],
[new In('', true), null],
[new In([], true), null],
[new In(0), null],
[new In(''), null],
[new In([]), null],
[new In('barfoobaz'), ''],
[new In('barfoobaz'), null],
[new In('barfoobaz'), 0],
@ -58,7 +57,7 @@ final class InTest extends RuleTestCase
[new In('barfaabaz'), 'foo'],
[new In('faabarbaz'), 'foo'],
[new In('baabazfaa'), 'foo'],
[new In([1, 2, 3], true), '1'],
[new In([1, 2, 3]), '1'],
];
}
}

View file

@ -27,11 +27,9 @@ final class StartsWithTest extends RuleTestCase
{
return [
[new StartsWith('foo'), ['foo', 'bar']],
[new StartsWith('foo') ,'FOObarbaz'],
[new StartsWith('foo') , 'foobarbaz'],
[new StartsWith('foo') ,'foobazfoo'],
[new StartsWith('1'), [1, 2, 3]],
[new StartsWith('1', true), ['1', 2, 3]],
[new StartsWith('foo'), 'foobarbaz'],
[new StartsWith('foo'), 'foobazfoo'],
[new StartsWith('1'), ['1', 2, 3]],
];
}
@ -40,15 +38,15 @@ final class StartsWithTest extends RuleTestCase
{
return [
[new StartsWith(123), 123],
[new StartsWith(123, true), 123],
[new StartsWith('foo'), ''],
[new StartsWith('bat'), ['foo', 'bar']],
[new StartsWith('foo'), 'barfaabaz'],
[new StartsWith('foo', true), 'FOObarbaz'],
[new StartsWith('foo'), 'FOObarbaz'],
[new StartsWith('foo'), 'faabarbaz'],
[new StartsWith('foo'), 'baabazfaa'],
[new StartsWith('foo'), 'baafoofaa'],
[new StartsWith('1', true), [1, '1', 3]],
[new StartsWith('1'), [1, '1', 3]],
[new StartsWith('1'), [1, 2, 3]],
];
}
}