From 42271172bd154a4cc06f12d947a468138ec1aa6a Mon Sep 17 00:00:00 2001 From: JakeQZ Date: Thu, 19 Sep 2024 08:05:48 +0100 Subject: [PATCH] [TASK] Add `Preg::match` to wrap `preg_match` with error handling (#1319) This will allow code using `preg_match` to be written more cleanly. --- src/Utilities/Preg.php | 25 +++++++ tests/Unit/Utilities/PregTest.php | 113 ++++++++++++++++++++++++++++++ 2 files changed, 138 insertions(+) diff --git a/src/Utilities/Preg.php b/src/Utilities/Preg.php index 49dc653c..82939d45 100644 --- a/src/Utilities/Preg.php +++ b/src/Utilities/Preg.php @@ -114,6 +114,31 @@ public function split(string $pattern, string $subject, int $limit = -1, int $fl return $result; } + /** + * Wraps `preg_match`. + * If an error occurs, and exceptions are not being thrown, + * zero (`0`) is returned, and if the `$matches` parameter is provided, it is set to an empty array. + * This method does not currently support the `$flags` or `$offset` parameters. + * + * @param non-empty-string $pattern + * @param array $matches + * + * @return 0|1 + * + * @throws \RuntimeException + */ + public function match(string $pattern, string $subject, ?array &$matches = null): int + { + $result = \preg_match($pattern, $subject, $matches); + + if ($result === false) { + $this->logOrThrowPregLastError(); + $result = 0; + $matches = []; + } + + return $result; + } /** * Obtains the name of the error constant for `preg_last_error` diff --git a/tests/Unit/Utilities/PregTest.php b/tests/Unit/Utilities/PregTest.php index a75ef263..bd62c0b6 100644 --- a/tests/Unit/Utilities/PregTest.php +++ b/tests/Unit/Utilities/PregTest.php @@ -66,6 +66,11 @@ static function (Preg $testSubject): void { $testSubject->split('/', ''); }, ], + 'match' => [ + static function (Preg $testSubject): void { + $testSubject->match('/', ''); + }, + ], ]; } @@ -293,6 +298,90 @@ public function splitSplits(string $pattern, string $subject, int $limit, int $f self::assertSame($expectedResult, $result); } + /** + * @return array + */ + public function providePregMatchArgumentsAndExpectedMatchCount(): array + { + return [ + 'no match' => [ + 'pattern' => '/fab/', + 'subject' => 'abba', + 'expect' => 0, + ], + 'with match' => [ + 'pattern' => '/a/', + 'subject' => 'abba', + 'expect' => 1, + ], + ]; + } + + /** + * @test + * + * @param non-empty-string $pattern + * + * @dataProvider providePregMatchArgumentsAndExpectedMatchCount + */ + public function matchReturnsMatchCount(string $pattern, string $subject, int $expectedMatchCount): void + { + $testSubject = new Preg(); + + $result = $testSubject->match($pattern, $subject); + + self::assertSame($expectedMatchCount, $result); + } + + /** + * @return array, + * }> + */ + public function providePregMatchArgumentsAndExpectedMatches(): array + { + return [ + 'no match' => [ + 'pattern' => '/fab/', + 'subject' => 'abba', + 'expect' => [], + ], + 'with match' => [ + 'pattern' => '/a/', + 'subject' => 'abba', + 'expect' => ['a'], + ], + 'with subpattern match' => [ + 'pattern' => '/a(b)/', + 'subject' => 'abba', + 'expect' => ['ab', 'b'], + ], + ]; + } + + /** + * @test + * + * @param non-empty-string $pattern + * @param array $expectedMatches + * + * @dataProvider providePregMatchArgumentsAndExpectedMatches + */ + public function matchSetsMatches(string $pattern, string $subject, array $expectedMatches): void + { + $testSubject = new Preg(); + + $testSubject->match($pattern, $subject, $matches); + + self::assertSame($expectedMatches, $matches); + } + /** * @test */ @@ -348,6 +437,30 @@ public function splitWithOffsetCaptureIsNotSupported(): void $result = $subject->split('/a/', 'abba', -1, PREG_SPLIT_OFFSET_CAPTURE); } + /** + * @test + */ + public function matchReturnsZeroOnError(): void + { + $subject = new Preg(); + + $result = @$subject->match('/', 'abba'); + + self::assertSame(0, $result); + } + + /** + * @test + */ + public function matchSetsMatchesToEmptyArrayOnError(): void + { + $subject = new Preg(); + + @$subject->match('/', 'abba', $matches); + + self::assertSame([], $matches); + } + /** * @param array $matches */