-
Notifications
You must be signed in to change notification settings - Fork 0
Feat: Contains validator #9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
3e0e0c5
Add contains validator
Meldiron 95a3d29
Update src/Validator/Contains.php
Meldiron 15012b5
Improve description
Meldiron 01adf80
Fix empty patterm array behaviour
Meldiron de406ca
Improve metadata test assertions
Meldiron 0c88055
Merge branch 'feat-contains-validator' of https://github.com/utopia-p…
Meldiron File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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,114 @@ | ||
| <?php | ||
|
|
||
| namespace Utopia\Validator; | ||
|
|
||
| use Utopia\Validator; | ||
|
|
||
| /** | ||
| * Contains | ||
| * | ||
| * Validate that a string contains at least one of the predefined substrings. | ||
| */ | ||
| class Contains extends Validator | ||
| { | ||
| /** | ||
| * @var array | ||
| */ | ||
| protected array $patterns; | ||
|
|
||
| /** | ||
| * @var bool | ||
| */ | ||
| protected bool $strict; | ||
|
|
||
| /** | ||
| * Constructor | ||
| * | ||
| * Sets a list of substrings to search for and strict mode. | ||
| * | ||
| * @param array $patterns | ||
| * @param bool $strict enable case-sensitive matching | ||
| */ | ||
| public function __construct(array $patterns, bool $strict = false) | ||
| { | ||
| if (empty($patterns)) { | ||
| throw new \InvalidArgumentException('Patterns array cannot be empty'); | ||
| } | ||
|
|
||
| $this->patterns = $patterns; | ||
| $this->strict = $strict; | ||
| } | ||
|
|
||
| /** | ||
| * Get Description | ||
| * | ||
| * Returns validator description | ||
| * | ||
| * @return string | ||
| */ | ||
| public function getDescription(): string | ||
| { | ||
| $message = 'Value must contain one of ('.\implode(', ', $this->patterns).')'; | ||
|
|
||
| if ($this->strict) { | ||
| $message .= ' (case-sensitive)'; | ||
| } else { | ||
| $message .= ' (case-insensitive)'; | ||
| } | ||
|
|
||
| return $message; | ||
| } | ||
|
|
||
| /** | ||
| * Is valid | ||
| * | ||
| * Validation will pass when $value contains at least one of the patterns. | ||
| * | ||
| * @param mixed $value | ||
| * @return bool | ||
| */ | ||
| public function isValid($value): bool | ||
| { | ||
| if (!\is_string($value)) { | ||
| return false; | ||
| } | ||
|
|
||
| if (!$this->strict) { | ||
| $value = \mb_strtolower($value, 'UTF-8'); | ||
| } | ||
|
|
||
| foreach ($this->patterns as $pattern) { | ||
| $pattern = $this->strict ? $pattern : \mb_strtolower($pattern, 'UTF-8'); | ||
|
|
||
| if (\str_contains($value, $pattern)) { | ||
| return true; | ||
| } | ||
| } | ||
|
|
||
| return false; | ||
| } | ||
|
|
||
| /** | ||
| * Is array | ||
| * | ||
| * Function will return true if object is array. | ||
| * | ||
| * @return bool | ||
| */ | ||
| public function isArray(): bool | ||
| { | ||
| return false; | ||
| } | ||
|
|
||
| /** | ||
| * Get Type | ||
| * | ||
| * Returns validator type. | ||
| * | ||
| * @return string | ||
| */ | ||
| public function getType(): string | ||
| { | ||
| return self::TYPE_STRING; | ||
| } | ||
| } | ||
This file contains hidden or 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,129 @@ | ||
| <?php | ||
|
|
||
| namespace Utopia\Validator; | ||
|
|
||
| use PHPUnit\Framework\TestCase; | ||
| use stdClass; | ||
|
|
||
| class ContainsTest extends TestCase | ||
| { | ||
| public function testCanValidateWithSinglePattern(): void | ||
| { | ||
| $validator = new Contains(['[skip ci]']); | ||
|
|
||
| $this->assertTrue($validator->isValid('[skip ci] update changelog')); | ||
| $this->assertTrue($validator->isValid('docs: update readme [skip ci]')); | ||
| $this->assertTrue($validator->isValid('prefix[skip ci]suffix')); | ||
|
|
||
| $this->assertFalse($validator->isValid('fix: real bug fix')); | ||
| $this->assertFalse($validator->isValid('skip deploy without brackets')); | ||
| $this->assertFalse($validator->isValid('')); | ||
| } | ||
|
|
||
| public function testCanValidateWithMultiplePatterns(): void | ||
| { | ||
| $validator = new Contains(['[skip ci]', '[no ci]', '[ci skip]']); | ||
|
|
||
| $this->assertTrue($validator->isValid('[skip ci]')); | ||
| $this->assertTrue($validator->isValid('[no ci]')); | ||
| $this->assertTrue($validator->isValid('[ci skip]')); | ||
| $this->assertFalse($validator->isValid('[skip deploy]')); | ||
| } | ||
|
|
||
| public function testCanValidateLoosely(): void | ||
| { | ||
| $validator = new Contains(['[skip ci]']); | ||
|
|
||
| $this->assertTrue($validator->isValid('[skip ci]')); | ||
| $this->assertTrue($validator->isValid('[SKIP CI]')); | ||
| $this->assertTrue($validator->isValid('[Skip Ci]')); | ||
| $this->assertTrue($validator->isValid('Docs update [SKIP CI]')); | ||
| } | ||
|
|
||
| public function testCanValidateStrictly(): void | ||
| { | ||
| $validator = new Contains(['[skip ci]'], true); | ||
|
|
||
| $this->assertTrue($validator->isValid('[skip ci]')); | ||
| $this->assertTrue($validator->isValid('prefix[skip ci]suffix')); | ||
|
|
||
| $this->assertFalse($validator->isValid('[SKIP CI]')); | ||
| $this->assertFalse($validator->isValid('[Skip Ci]')); | ||
| } | ||
|
|
||
| public function testCanValidateMultilineStrings(): void | ||
| { | ||
| $validator = new Contains(['[skip ci]']); | ||
|
|
||
| $message = "feat: add new stuff\n\nMore detail here.\n\n[skip ci]"; | ||
| $this->assertTrue($validator->isValid($message)); | ||
| } | ||
|
|
||
| public function testThrowsExceptionForEmptyPatternsArray(): void | ||
| { | ||
| $this->expectException(\InvalidArgumentException::class); | ||
| $this->expectExceptionMessage('Patterns array cannot be empty'); | ||
|
|
||
| new Contains([]); | ||
| } | ||
|
|
||
| public function testCanValidateWithEmptyPatternString(): void | ||
| { | ||
| $validator = new Contains(['']); | ||
|
|
||
| $this->assertTrue($validator->isValid('any string')); | ||
| $this->assertTrue($validator->isValid('')); | ||
| } | ||
|
|
||
| public function testCanValidateWithNonStringValues(): void | ||
| { | ||
| $validator = new Contains(['[skip ci]']); | ||
|
|
||
| $this->assertFalse($validator->isValid(null)); | ||
| $this->assertFalse($validator->isValid([])); | ||
| $this->assertFalse($validator->isValid(123)); | ||
| $this->assertFalse($validator->isValid(12.34)); | ||
| $this->assertFalse($validator->isValid(true)); | ||
| $this->assertFalse($validator->isValid(false)); | ||
| $this->assertFalse($validator->isValid(new stdClass())); | ||
| } | ||
|
|
||
| public function testCanValidatePartialMatches(): void | ||
| { | ||
| $validator = new Contains(['skip']); | ||
|
|
||
| $this->assertTrue($validator->isValid('skip')); | ||
| $this->assertTrue($validator->isValid('skip ci')); | ||
| $this->assertTrue($validator->isValid('please skip this')); | ||
| $this->assertTrue($validator->isValid('skipping')); | ||
|
|
||
| $this->assertFalse($validator->isValid('ski')); | ||
| $this->assertFalse($validator->isValid('')); | ||
| } | ||
|
|
||
| public function testCanValidateWithUnicodeCharacters(): void | ||
| { | ||
| $validator = new Contains(['café', 'naïve']); | ||
|
|
||
| $this->assertTrue($validator->isValid('I love café')); | ||
| $this->assertTrue($validator->isValid('Naïve approach')); | ||
| $this->assertTrue($validator->isValid('CAFÉ')); | ||
|
|
||
| $this->assertFalse($validator->isValid('I love coffee')); | ||
| } | ||
|
|
||
| public function testReturnsCorrectMetadata(): void | ||
| { | ||
| $validator = new Contains(['foo', 'bar']); | ||
|
|
||
| $this->assertFalse($validator->isArray()); | ||
| $this->assertSame(\Utopia\Validator::TYPE_STRING, $validator->getType()); | ||
| $this->assertStringContainsString('foo', $validator->getDescription()); | ||
| $this->assertStringContainsString('bar', $validator->getDescription()); | ||
| $this->assertStringContainsString('case-insensitive', $validator->getDescription()); | ||
|
|
||
| $validatorStrict = new Contains(['foo', 'bar'], true); | ||
|
|
||
| $this->assertStringContainsString('case-sensitive', $validatorStrict->getDescription()); | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.