From 03b544a07d6b0695c73284d6cf8e6a1a371cb7f5 Mon Sep 17 00:00:00 2001 From: Navarr Barnier Date: Sun, 6 Mar 2022 21:35:05 -0500 Subject: [PATCH 01/21] Test Stringable Infection --- tests/StringLengthTest.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/StringLengthTest.php b/tests/StringLengthTest.php index 75fca03..8f7dc5a 100644 --- a/tests/StringLengthTest.php +++ b/tests/StringLengthTest.php @@ -2,6 +2,7 @@ namespace Navarr\SmartString\Test; +use Navarr\SmartString\SmartString; use Navarr\SmartString\SmartStringFactory; use PHPUnit\Framework\TestCase; @@ -20,7 +21,8 @@ public function getData(): array return [ ['abcdef', 6], ['こんにちは', 5], - ['🏴󠁧󠁢󠁥󠁮󠁧󠁿', 1] + ['🏴󠁧󠁢󠁥󠁮󠁧󠁿', 1], + [SmartString::build('abc'), 3] // Ensure methods properly handle a Stringable ]; } From 62d93764e1d7b355ca2dce598c81126b1d1c58b7 Mon Sep 17 00:00:00 2001 From: Navarr Barnier Date: Sun, 6 Mar 2022 21:35:56 -0500 Subject: [PATCH 02/21] Fix test parameters --- tests/StringLengthTest.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/StringLengthTest.php b/tests/StringLengthTest.php index 8f7dc5a..849b6ac 100644 --- a/tests/StringLengthTest.php +++ b/tests/StringLengthTest.php @@ -5,6 +5,7 @@ use Navarr\SmartString\SmartString; use Navarr\SmartString\SmartStringFactory; use PHPUnit\Framework\TestCase; +use Stringable; class StringLengthTest extends TestCase { @@ -29,7 +30,7 @@ public function getData(): array /** * @dataProvider getData */ - public function testLength(string $string, int $expectedLength) + public function testLength(Stringable|string $string, int $expectedLength) { $testString = $this->factory->create($string); $this->assertEquals($expectedLength, $testString->length()); @@ -38,7 +39,7 @@ public function testLength(string $string, int $expectedLength) /** * @dataProvider getData */ - public function testStrlen(string $string, int $expectedLength) + public function testStrlen(Stringable|string $string, int $expectedLength) { $testString = $this->factory->create($string); $this->assertEquals($expectedLength, $testString->strlen()); From 4142d6440c4d1fce550163b940beec11640c5660 Mon Sep 17 00:00:00 2001 From: Navarr Barnier Date: Sun, 6 Mar 2022 21:36:57 -0500 Subject: [PATCH 03/21] Add strict-type declaration --- src/SmartString.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/SmartString.php b/src/SmartString.php index 2325c82..96fd9d2 100644 --- a/src/SmartString.php +++ b/src/SmartString.php @@ -1,5 +1,7 @@ Date: Sun, 6 Mar 2022 21:38:24 -0500 Subject: [PATCH 04/21] Fix static analysis issue of sending a Stringable to a string parameter --- src/SmartString.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SmartString.php b/src/SmartString.php index 96fd9d2..c6d403a 100644 --- a/src/SmartString.php +++ b/src/SmartString.php @@ -49,7 +49,7 @@ public function __toString(): string } #[Pure] - public function stripos(string $needle, int $offset = 0): int|false + public function stripos(Stringable|string $needle, int $offset = 0): int|false { return match ($this->shouldUseGrapheme) { true => grapheme_stripos($this->value, $needle, $offset), From d25a7839a5ca0863b3e7cfa6e21a9eb3857c97a5 Mon Sep 17 00:00:00 2001 From: Navarr Barnier Date: Mon, 7 Mar 2022 14:49:09 -0500 Subject: [PATCH 05/21] Properly convert needle to string for stripos --- src/SmartString.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/SmartString.php b/src/SmartString.php index c6d403a..b7417e5 100644 --- a/src/SmartString.php +++ b/src/SmartString.php @@ -51,6 +51,7 @@ public function __toString(): string #[Pure] public function stripos(Stringable|string $needle, int $offset = 0): int|false { + $needle = (string)$needle; return match ($this->shouldUseGrapheme) { true => grapheme_stripos($this->value, $needle, $offset), false => stripos($this->value, $needle, $offset) From 51f1891c49b0466962d1f2e679ba21fe68fedebf Mon Sep 17 00:00:00 2001 From: Navarr Barnier Date: Mon, 7 Mar 2022 19:30:01 -0500 Subject: [PATCH 06/21] Add Concatenation Test --- tests/ConcatenateTest.php | 49 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 tests/ConcatenateTest.php diff --git a/tests/ConcatenateTest.php b/tests/ConcatenateTest.php new file mode 100644 index 0000000..afbfba2 --- /dev/null +++ b/tests/ConcatenateTest.php @@ -0,0 +1,49 @@ +factory = new SmartStringFactory(); + parent::setUp(); + } + + public function getData(): array + { + return [ + ['a', 'b', 'ab'], + ['a', SmartString::build('b'), 'ab'] + ]; + } + + /** + * @dataProvider getData + */ + public function testConcat(string $initial, Stringable|string $additional, string $expectedResult): void + { + $object = $this->factory->create($initial); + $result = $object->concat($additional); + $this->assertInstanceOf(SmartString::class, $result); + $this->assertEquals($expectedResult, (string)$result); + } + + /** + * @dataProvider getData + */ + public function testConcatenate(string $initial, Stringable|string $additional, string $expectedResult): void + { + $object = $this->factory->create($initial); + $result = $object->concatenate($additional); + $this->assertInstanceOf(SmartString::class, $result); + $this->assertEquals($expectedResult, (string)$result); + } +} From da843b044fbe652fe53ab503efbcfae208d38bab Mon Sep 17 00:00:00 2001 From: Navarr Barnier Date: Mon, 7 Mar 2022 19:37:30 -0500 Subject: [PATCH 07/21] Add Grapheme-triggering data to Concatenation Tests --- tests/ConcatenateTest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/ConcatenateTest.php b/tests/ConcatenateTest.php index afbfba2..3fdff01 100644 --- a/tests/ConcatenateTest.php +++ b/tests/ConcatenateTest.php @@ -21,7 +21,8 @@ public function getData(): array { return [ ['a', 'b', 'ab'], - ['a', SmartString::build('b'), 'ab'] + ['a', SmartString::build('b'), 'ab'], + ['a', '🏴', 'a🏴'] ]; } From ea16d322bd12e9c24e67c84d29b3879287f0a5f5 Mon Sep 17 00:00:00 2001 From: Navarr Barnier Date: Mon, 7 Mar 2022 19:38:06 -0500 Subject: [PATCH 08/21] Add more Grapheme-triggering data to Concatenation Tests --- tests/ConcatenateTest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/ConcatenateTest.php b/tests/ConcatenateTest.php index 3fdff01..6d8e9b7 100644 --- a/tests/ConcatenateTest.php +++ b/tests/ConcatenateTest.php @@ -22,7 +22,8 @@ public function getData(): array return [ ['a', 'b', 'ab'], ['a', SmartString::build('b'), 'ab'], - ['a', '🏴', 'a🏴'] + ['a', '🏴', 'a🏴'], + ['🏴', 'a', '🏴a'], ]; } From 30859dac1c4e5be2b93f0f872f280614bbaef25c Mon Sep 17 00:00:00 2001 From: Navarr Barnier Date: Mon, 7 Mar 2022 19:56:49 -0500 Subject: [PATCH 09/21] Add Construction Tests --- tests/ConcatenateTest.php | 2 ++ tests/ConstructionTest.php | 60 ++++++++++++++++++++++++++++++++++++++ tests/StringLengthTest.php | 2 ++ 3 files changed, 64 insertions(+) create mode 100644 tests/ConstructionTest.php diff --git a/tests/ConcatenateTest.php b/tests/ConcatenateTest.php index 6d8e9b7..b4fed76 100644 --- a/tests/ConcatenateTest.php +++ b/tests/ConcatenateTest.php @@ -29,6 +29,7 @@ public function getData(): array /** * @dataProvider getData + * @covers SmartString::concat */ public function testConcat(string $initial, Stringable|string $additional, string $expectedResult): void { @@ -40,6 +41,7 @@ public function testConcat(string $initial, Stringable|string $additional, strin /** * @dataProvider getData + * @covers SmartString::concatenate */ public function testConcatenate(string $initial, Stringable|string $additional, string $expectedResult): void { diff --git a/tests/ConstructionTest.php b/tests/ConstructionTest.php new file mode 100644 index 0000000..8ee961d --- /dev/null +++ b/tests/ConstructionTest.php @@ -0,0 +1,60 @@ +factory = new SmartStringFactory(); + } + + public function getData(): array + { + return [ + ['a', 'a', false], + [SmartString::build('a'), 'a', false], + ['🏴', '🏴', true], + [SmartString::build('🏴'), '🏴', true], + ]; + } + + /** + * @dataProvider getData + * @covers SmartString::build + */ + public function testBuild(Stringable|string $suppliedValue, string $expectedValue, bool $expectedUseGraphemeValue): void + { + $object = SmartString::build($suppliedValue); + $this->testObject($object, $expectedValue, $expectedUseGraphemeValue); + } + + /** + * @dataProvider getData + * @covers SmartStringFactory::create + */ + public function testFactory(Stringable|string $suppliedValue, string $expectedValue, bool $expectedUseGraphemeValue): void + { + $object = $this->factory->create($suppliedValue); + $this->testObject($object, $expectedValue, $expectedUseGraphemeValue); + } + + private function testObject(SmartString $object, string $expectedValue, bool $expectedUseGraphemeValue) + { + $reflectionObject = new ReflectionClass($object); + + $valueProp = $reflectionObject->getProperty('value'); + $shouldUseGraphemeProp = $reflectionObject->getProperty('shouldUseGrapheme'); + + $this->assertEquals($expectedValue, $valueProp->getValue($object)); + $this->assertEquals($expectedUseGraphemeValue, $shouldUseGraphemeProp->getValue($object)); + } +} diff --git a/tests/StringLengthTest.php b/tests/StringLengthTest.php index 849b6ac..89f43f4 100644 --- a/tests/StringLengthTest.php +++ b/tests/StringLengthTest.php @@ -29,6 +29,7 @@ public function getData(): array /** * @dataProvider getData + * @covers SmartString::length */ public function testLength(Stringable|string $string, int $expectedLength) { @@ -38,6 +39,7 @@ public function testLength(Stringable|string $string, int $expectedLength) /** * @dataProvider getData + * @covers SmartString::strlen */ public function testStrlen(Stringable|string $string, int $expectedLength) { From 5d156083713169f0e2de4d12f6bee481395192e3 Mon Sep 17 00:00:00 2001 From: Navarr Barnier Date: Tue, 8 Mar 2022 07:18:42 -0500 Subject: [PATCH 10/21] Add Substring From Needle tests --- src/SmartString.php | 16 +++- tests/SubstringFromNeedleTest.php | 125 ++++++++++++++++++++++++++++++ 2 files changed, 138 insertions(+), 3 deletions(-) create mode 100644 tests/SubstringFromNeedleTest.php diff --git a/src/SmartString.php b/src/SmartString.php index b7417e5..b0bc7bd 100644 --- a/src/SmartString.php +++ b/src/SmartString.php @@ -147,13 +147,23 @@ public function strstr(Stringable|string $needle, bool $beforeNeedle = false): S #[Pure] public function substringFromNeedle( Stringable|string $needle, - bool $beforeNeedle = false, int $flags = 0 ): SmartString|false { if (($flags & static::CASE_INSENSITIVE) == static::CASE_INSENSITIVE) { - return $this->stristr($needle, $beforeNeedle); + return $this->stristr($needle); } - return $this->strstr($needle, $beforeNeedle); + return $this->strstr($needle); + } + + #[Pure] + public function substringUntilNeedle( + Stringable|string $needle, + int $flags = 0 + ): SmartString|false { + if (($flags & static::CASE_INSENSITIVE) == static::CASE_INSENSITIVE) { + return $this->stristr($needle, true); + } + return $this->strstr($needle, true); } #[Pure] diff --git a/tests/SubstringFromNeedleTest.php b/tests/SubstringFromNeedleTest.php new file mode 100644 index 0000000..ab9f9e2 --- /dev/null +++ b/tests/SubstringFromNeedleTest.php @@ -0,0 +1,125 @@ +factory = new SmartStringFactory(); + parent::setUp(); + } + + private function getDataCaseInsensitive(): array + { + return [ + ['abcdefg', 'c', 'cdefg'], + ['abcdefg', SmartString::build('c'), 'cdefg'], + ['abcABCdefDEF', 'C', 'cABCdefDEF'], + ['abcABCdefDEF', SmartString::build('C'), 'cABCdefDEF'], + ['abcdefg', 'h', false], + ['abcdefg', SmartString::build('h'), false], + ['abcdefg', '🏴', false], + ['abcdefg', SmartString::build('🏴'), false], + ['ab🏴defg', '🏴', '🏴defg'], + ['ab🏴defg', SmartString::build('🏴'), '🏴defg'], + ]; + } + + private function getDataCaseSensitive(): array + { + return [ + ['abcABCdefDEF', 'C', 'CdefDEF'], + ['abcABCdefDEF', SmartString::build('C'), 'CdefDEF'], + ['abcABCdefDEF', 'c', 'cABCdefDEF'], + ['abcABCdefDEF', SmartString::build('c'), 'cABCdefDEF'], + ['abcABCdefDEF', 'h', false], + ['abcABCdefDEF', SmartString::build('h'), false], + ['abcABCdefDEF', 'H', false], + ['abcABCdefDEF', SmartString::build('H'), false], + ['abcABCdefDEF', '🏴', false], + ['abcABCdefDEF', SmartString::build('🏴'), false], + ['abcABC🏴defDEF', '🏴', '🏴defDEF'], + ['abcABC🏴defDEF', SmartString::build('🏴'), '🏴defDEF'], + ]; + } + + /** + * @dataProvider getDataCaseSensitive + */ + public function testSubstringFromNeedleCaseSensitive( + Stringable|string $initial, + Stringable|string $substring, + string|false $expected + ): void { + $object = $this->factory->create($initial); + $result = $object->substringFromNeedle($substring); + + if (is_string($expected)) { + $this->assertInstanceOf(SmartString::class, $result); + $result = (string)$result; + } + $this->assertEquals($expected, $result); + } + + /** + * @dataProvider getDataCaseSensitive + */ + public function testStrstrWithBeforeNeedleFalse( + Stringable|string $initial, + Stringable|string $substring, + string|false $expected + ): void { + $object = $this->factory->create($initial); + $result = $object->strstr($substring); + + if (is_string($expected)) { + $this->assertInstanceOf(SmartString::class, $result); + $result = (string)$result; + } + $this->assertEquals($expected, $result); + } + + /** + * @dataProvider getDataCaseInsensitive + */ + public function testSubstringFromNeedleCaseInsensitive( + Stringable|string $initial, + Stringable|string $substring, + string|false $expected + ): void { + $object = $this->factory->create($initial); + $result = $object->substringFromNeedle($substring, SmartString::CASE_INSENSITIVE); + + if (is_string($expected)) { + $this->assertInstanceOf(SmartString::class, $result); + $result = (string)$result; + } + $this->assertEquals($expected, $result); + } + + /** + * @dataProvider getDataCaseInsensitive + */ + public function testStristrWithBeforeNeedleFalse( + Stringable|string $initial, + Stringable|string $substring, + string|false $expected + ): void { + $object = $this->factory->create($initial); + $result = $object->stristr($substring); + + if (is_string($expected)) { + $this->assertInstanceOf(SmartString::class, $result); + $result = (string)$result; + } + $this->assertEquals($expected, $result); + } +} From de2369d26397b2402e1a1b0873f77f3c7333fd68 Mon Sep 17 00:00:00 2001 From: Navarr Barnier Date: Tue, 8 Mar 2022 07:19:52 -0500 Subject: [PATCH 11/21] PSR-12 fixes --- tests/ConstructionTest.php | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/tests/ConstructionTest.php b/tests/ConstructionTest.php index 8ee961d..c99424d 100644 --- a/tests/ConstructionTest.php +++ b/tests/ConstructionTest.php @@ -29,20 +29,26 @@ public function getData(): array /** * @dataProvider getData - * @covers SmartString::build + * @covers SmartString::build */ - public function testBuild(Stringable|string $suppliedValue, string $expectedValue, bool $expectedUseGraphemeValue): void - { + public function testBuild( + Stringable|string $suppliedValue, + string $expectedValue, + bool $expectedUseGraphemeValue + ): void { $object = SmartString::build($suppliedValue); $this->testObject($object, $expectedValue, $expectedUseGraphemeValue); } /** * @dataProvider getData - * @covers SmartStringFactory::create + * @covers SmartStringFactory::create */ - public function testFactory(Stringable|string $suppliedValue, string $expectedValue, bool $expectedUseGraphemeValue): void - { + public function testFactory( + Stringable|string $suppliedValue, + string $expectedValue, + bool $expectedUseGraphemeValue + ): void { $object = $this->factory->create($suppliedValue); $this->testObject($object, $expectedValue, $expectedUseGraphemeValue); } From de5d29f31f059e4ce6363fe14827af96cddb204e Mon Sep 17 00:00:00 2001 From: Navarr Barnier Date: Tue, 8 Mar 2022 07:24:15 -0500 Subject: [PATCH 12/21] Remove `@covers` annotations since they're throwing warnings --- tests/ConcatenateTest.php | 2 -- tests/ConstructionTest.php | 2 -- tests/StringLengthTest.php | 2 -- 3 files changed, 6 deletions(-) diff --git a/tests/ConcatenateTest.php b/tests/ConcatenateTest.php index b4fed76..6d8e9b7 100644 --- a/tests/ConcatenateTest.php +++ b/tests/ConcatenateTest.php @@ -29,7 +29,6 @@ public function getData(): array /** * @dataProvider getData - * @covers SmartString::concat */ public function testConcat(string $initial, Stringable|string $additional, string $expectedResult): void { @@ -41,7 +40,6 @@ public function testConcat(string $initial, Stringable|string $additional, strin /** * @dataProvider getData - * @covers SmartString::concatenate */ public function testConcatenate(string $initial, Stringable|string $additional, string $expectedResult): void { diff --git a/tests/ConstructionTest.php b/tests/ConstructionTest.php index c99424d..688fb07 100644 --- a/tests/ConstructionTest.php +++ b/tests/ConstructionTest.php @@ -29,7 +29,6 @@ public function getData(): array /** * @dataProvider getData - * @covers SmartString::build */ public function testBuild( Stringable|string $suppliedValue, @@ -42,7 +41,6 @@ public function testBuild( /** * @dataProvider getData - * @covers SmartStringFactory::create */ public function testFactory( Stringable|string $suppliedValue, diff --git a/tests/StringLengthTest.php b/tests/StringLengthTest.php index 89f43f4..849b6ac 100644 --- a/tests/StringLengthTest.php +++ b/tests/StringLengthTest.php @@ -29,7 +29,6 @@ public function getData(): array /** * @dataProvider getData - * @covers SmartString::length */ public function testLength(Stringable|string $string, int $expectedLength) { @@ -39,7 +38,6 @@ public function testLength(Stringable|string $string, int $expectedLength) /** * @dataProvider getData - * @covers SmartString::strlen */ public function testStrlen(Stringable|string $string, int $expectedLength) { From 7107fea98f9d672dcf12a9ee8d7653918f50095d Mon Sep 17 00:00:00 2001 From: Navarr Barnier Date: Sat, 12 Mar 2022 14:47:52 -0500 Subject: [PATCH 13/21] Add Substring Until Needle tests --- tests/SubstringUntilNeedleTest.php | 124 +++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 tests/SubstringUntilNeedleTest.php diff --git a/tests/SubstringUntilNeedleTest.php b/tests/SubstringUntilNeedleTest.php new file mode 100644 index 0000000..aeeae06 --- /dev/null +++ b/tests/SubstringUntilNeedleTest.php @@ -0,0 +1,124 @@ +factory = new SmartStringFactory(); + } + + /** + * @dataProvider getDataCaseInsensitive + */ + public function testStristrWithBeforeNeedleTrue( + Stringable|string $initial, + Stringable|string $substring, + string|false $expected + ): void { + $object = $this->factory->create($initial); + $result = $object->stristr($substring, true); + + if (is_string($expected)) { + $this->assertInstanceOf(SmartString::class, $result); + $result = (string)$result; + } + $this->assertEquals($expected, $result); + } + + /** + * @dataProvider getDataCaseSensitive + */ + public function testStrstrWithBeforeNeedleTrue( + Stringable|string $initial, + Stringable|string $substring, + string|false $expected + ): void { + $object = $this->factory->create($initial); + $result = $object->strstr($substring, true); + + if (is_string($expected)) { + $this->assertInstanceOf(SmartString::class, $result); + $result = (string)$result; + } + $this->assertEquals($expected, $result); + } + + /** + * @dataProvider getDataCaseInsensitive + */ + public function testSubstringUntilNeedleCaseInsensitive( + Stringable|string $initial, + Stringable|string $substring, + string|false $expected + ): void { + $object = $this->factory->create($initial); + $result = $object->substringUntilNeedle($substring, SmartString::CASE_INSENSITIVE); + + if (is_string($expected)) { + $this->assertInstanceOf(SmartString::class, $result); + $result = (string)$result; + } + $this->assertEquals($expected, $result); + } + + /** + * @dataProvider getDataCaseSensitive + */ + public function testSubstringUntilNeedleCaseSensitive( + Stringable|string $initial, + Stringable|string $substring, + string|false $expected + ): void { + $object = $this->factory->create($initial); + $result = $object->substringUntilNeedle($substring); + + if (is_string($expected)) { + $this->assertInstanceOf(SmartString::class, $result); + $result = (string)$result; + } + $this->assertEquals($expected, $result); + } +} From 51d14fb4d967f96302f156e877aaeb73e538d4d7 Mon Sep 17 00:00:00 2001 From: Navarr Barnier Date: Sat, 12 Mar 2022 15:13:25 -0500 Subject: [PATCH 14/21] Add Find Position Test --- tests/FindPositionTest.php | 91 ++++++++++++++++++++++++++++++ tests/SubstringUntilNeedleTest.php | 1 + 2 files changed, 92 insertions(+) create mode 100644 tests/FindPositionTest.php diff --git a/tests/FindPositionTest.php b/tests/FindPositionTest.php new file mode 100644 index 0000000..81b998d --- /dev/null +++ b/tests/FindPositionTest.php @@ -0,0 +1,91 @@ +factory = new SmartStringFactory(); + parent::setUp(); + } + + private function getDataCaseSensitive(): array + { + return [ + ['abcABCdefDEF', 'c', 2], + ['abcabcdefdef', 'c', 5, 3], + ]; + } + + private function getDataCaseInsensitive(): array + { + return [ + ['abcABCdefDEF', 'C', 2], + ['ABCabcABCabc', 'C', 5, 3] + ]; + } + + /** + * @dataProvider getDataCaseSensitive + */ + public function testFindPositionCaseSensitive( + Stringable|string $initial, + Stringable|string $needle, + int|bool $expected, + int $offset = 0 + ): void { + $object = $this->factory->create($initial); + $result = $object->findPosition($needle, $offset); + $this->assertEquals($expected, $result); + } + + /** + * @dataProvider getDataCaseInsensitive + */ + public function testFindPositionCaseInsensitive( + Stringable|string $initial, + Stringable|string $needle, + int|bool $expected, + int $offset = 0 + ): void { + $object = $this->factory->create($initial); + $result = $object->findPosition($needle, $offset, SmartString::CASE_INSENSITIVE); + $this->assertEquals($expected, $result); + } + + /** + * @dataProvider getDataCaseInsensitive + */ + public function testStripos( + Stringable|string $initial, + Stringable|string $needle, + int|bool $expected, + int $offset = 0 + ): void { + $object = $this->factory->create($initial); + $result = $object->stripos($needle, $offset); + $this->assertEquals($expected, $result); + } + + /** + * @dataProvider getDataCaseSensitive + */ + public function testStrpos( + Stringable|string $initial, + Stringable|string $needle, + int|bool $expected, + int $offset = 0 + ): void { + $object = $this->factory->create($initial); + $result = $object->strpos($needle, $offset); + $this->assertEquals($expected, $result); + } +} diff --git a/tests/SubstringUntilNeedleTest.php b/tests/SubstringUntilNeedleTest.php index aeeae06..7e5a560 100644 --- a/tests/SubstringUntilNeedleTest.php +++ b/tests/SubstringUntilNeedleTest.php @@ -48,6 +48,7 @@ private function getDataCaseSensitive(): array public function setUp(): void { $this->factory = new SmartStringFactory(); + parent::setUp(); } /** From 1fa2064f41a1968b48df2554b96507e9f119c522 Mon Sep 17 00:00:00 2001 From: Navarr Barnier Date: Sun, 3 Apr 2022 11:19:50 -0400 Subject: [PATCH 15/21] Add Composer cache support and separate code coverage reporting from phpunit --- .github/workflows/commit.yml | 60 ++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/.github/workflows/commit.yml b/.github/workflows/commit.yml index 6681ae3..fcee7d8 100644 --- a/.github/workflows/commit.yml +++ b/.github/workflows/commit.yml @@ -23,6 +23,17 @@ jobs: - name: Checkout Repository uses: actions/checkout@v2 + - name: Get Composer Cache Directory + id: composer-cache + run: | + echo "::set-output name=dir::$(composer config cache-files-dir)" + - uses: actions/cache@v3 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-php${{ matrix.php }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: | + ${{ runner.os }}-php${{ matrix.php }}-composer- + - name: Install Dependencies run: composer install if: ${{ matrix.php != '8.2' }} @@ -34,6 +45,22 @@ jobs: - name: Test run: vendor/bin/phpunit tests --testdox --coverage-clover coverage.xml + - name: Upload Coverage Artifact + uses: actions/upload-artifact@v2 + with: + name: codecov + path: coverage.xml + + codecov: + name: Code Coverage Report + runs-on: ubuntu-latest + needs: phpunit + steps: + - name: Download Coverage Artifact + uses: actions/download-artifact@v2 + with: + name: codecov + - name: Upload to CodeCov uses: codecov/codecov-action@v1 with: @@ -57,6 +84,17 @@ jobs: - name: Checkout Repository uses: actions/checkout@v2 + - name: Get Composer Cache Directory + id: composer-cache + run: | + echo "::set-output name=dir::$(composer config cache-files-dir)" + - uses: actions/cache@v3 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-php${{ matrix.php }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: | + ${{ runner.os }}-php${{ matrix.php }}-composer- + - name: Install Dependencies run: composer install if: ${{ matrix.php != '8.2' }} @@ -81,6 +119,17 @@ jobs: - name: Checkout Repository uses: actions/checkout@v2 + - name: Get Composer Cache Directory + id: composer-cache + run: | + echo "::set-output name=dir::$(composer config cache-files-dir)" + - uses: actions/cache@v3 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-php${{ matrix.php }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: | + ${{ runner.os }}-php${{ matrix.php }}-composer- + - name: Install Dependencies run: composer install if: ${{ matrix.php != '8.2' }} @@ -111,6 +160,17 @@ jobs: - name: Checkout Repository uses: actions/checkout@v2 + - name: Get Composer Cache Directory + id: composer-cache + run: | + echo "::set-output name=dir::$(composer config cache-files-dir)" + - uses: actions/cache@v3 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-php${{ matrix.php }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: | + ${{ runner.os }}-php${{ matrix.php }}-composer- + - name: Install Dependencies run: composer install if: ${{ matrix.php != '8.2' }} From 16b40dcdaffa0e17f4a9ee89fd1b0d10084ececd Mon Sep 17 00:00:00 2001 From: Navarr Barnier Date: Sat, 18 Jun 2022 10:03:44 -0400 Subject: [PATCH 16/21] Add grapheme data to FindPosition tests --- tests/FindPositionTest.php | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tests/FindPositionTest.php b/tests/FindPositionTest.php index 81b998d..05724fa 100644 --- a/tests/FindPositionTest.php +++ b/tests/FindPositionTest.php @@ -22,6 +22,10 @@ private function getDataCaseSensitive(): array return [ ['abcABCdefDEF', 'c', 2], ['abcabcdefdef', 'c', 5, 3], + ['abcABCdefDEF', SmartString::build('c'), 2], + ['abcabcdefdef', SmartString::build('c'), 5, 3], + ['ab🏴defg', '🏴', 2], + ['ab🏴defg', SmartString::build('🏴'), 2], ]; } @@ -29,7 +33,11 @@ private function getDataCaseInsensitive(): array { return [ ['abcABCdefDEF', 'C', 2], - ['ABCabcABCabc', 'C', 5, 3] + ['ABCabcABCabc', 'C', 5, 3], + ['abcABCdefDEF', SmartString::build('C'), 2], + ['ABCabcABCabc', SmartString::build('C'), 5, 3], + ['ab🏴defg', '🏴', 2], + ['ab🏴defg', SmartString::build('🏴'), 2], ]; } From 2d23ea12d5729f5f62e2c217d95ee6cda603c200 Mon Sep 17 00:00:00 2001 From: Navarr Date: Mon, 6 Oct 2025 16:28:39 -0400 Subject: [PATCH 17/21] Modernize Library * Test PHP 8.3, 8.4 * Support PHP 8.2+ * Update phpstan and infection * Change phpstan level to MAX --- .github/workflows/commit.yml | 28 ++++------------------------ composer.json | 11 ++++++++--- phpstan.neon | 2 +- src/SmartString.php | 6 +++--- 4 files changed, 16 insertions(+), 31 deletions(-) diff --git a/.github/workflows/commit.yml b/.github/workflows/commit.yml index 6681ae3..830562f 100644 --- a/.github/workflows/commit.yml +++ b/.github/workflows/commit.yml @@ -11,7 +11,7 @@ jobs: strategy: matrix: os: [unbuntu-latest, macos-latest, windows-latest] - php: ['8.1', '8.2'] + php: ['8.2', '8.3', '8.4'] steps: - name: Setup PHP uses: shivammathur/setup-php@v2 @@ -25,11 +25,6 @@ jobs: - name: Install Dependencies run: composer install - if: ${{ matrix.php != '8.2' }} - - - name: Install Dependencies (Ignore Platform Req) - run: composer install --ignore-platform-req=php - if: ${{ matrix.php == '8.2' }} - name: Test run: vendor/bin/phpunit tests --testdox --coverage-clover coverage.xml @@ -46,7 +41,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - php: ['8.1', '8.2'] + php: ['8.2', '8.3', '8.4'] steps: - name: Setup PHP uses: shivammathur/setup-php@v2 @@ -59,11 +54,6 @@ jobs: - name: Install Dependencies run: composer install - if: ${{ matrix.php != '8.2' }} - - - name: Install Dependencies (Ignore Platform Req) - run: composer install --ignore-platform-req=php - if: ${{ matrix.php == '8.2' }} - name: Run PHPStan run: vendor/bin/phpstan @@ -75,7 +65,7 @@ jobs: - name: Setup PHP uses: shivammathur/setup-php@v2 with: - php-version: 8.1 + php-version: 8.4 tools: composer:v2 - name: Checkout Repository @@ -83,11 +73,6 @@ jobs: - name: Install Dependencies run: composer install - if: ${{ matrix.php != '8.2' }} - - - name: Install Dependencies (Ignore Platform Req) - run: composer install --ignore-platform-req=php - if: ${{ matrix.php == '8.2' }} - name: PHP Code Sniffer run: vendor/bin/phpcs @@ -98,7 +83,7 @@ jobs: continue-on-error: true strategy: matrix: - php: ['8.1', '8.2'] + php: ['8.2', '8.3', '8.4'] steps: - name: Setup PHP uses: shivammathur/setup-php@v2 @@ -113,11 +98,6 @@ jobs: - name: Install Dependencies run: composer install - if: ${{ matrix.php != '8.2' }} - - - name: Install Dependencies (Ignore Platform Req) - run: composer install --ignore-platform-req=php - if: ${{ matrix.php == '8.2' }} - name: Check for Mutants env: diff --git a/composer.json b/composer.json index 3d8beeb..011e664 100644 --- a/composer.json +++ b/composer.json @@ -21,13 +21,18 @@ } }, "require": { - "php": "^8.1" + "php": "^8.2" + }, + "config": { + "allow-plugins": { + "infection/extension-installer": true + } }, "require-dev": { "jetbrains/phpstorm-attributes": "^1", "phpunit/phpunit": "^9.5", - "phpstan/phpstan": "^1", - "infection/infection": "^0.26.0", + "phpstan/phpstan": "^2", + "infection/infection": "^0.31.0", "squizlabs/php_codesniffer": "^3.6", "roave/security-advisories": "dev-master" } diff --git a/phpstan.neon b/phpstan.neon index 3e639cd..776ccd8 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,4 +1,4 @@ parameters: - level: 9 + level: max paths: - src diff --git a/src/SmartString.php b/src/SmartString.php index 2325c82..8c54431 100644 --- a/src/SmartString.php +++ b/src/SmartString.php @@ -89,7 +89,7 @@ public function strrpos(Stringable|string $needle, int $offset = 0): int|false #[Pure] public function findLastPosition(Stringable|string $needle, int $offset = 0, int $flags = 0): int|false { - if (($flags & static::CASE_INSENSITIVE) == static::CASE_INSENSITIVE) { + if (($flags & self::CASE_INSENSITIVE) == self::CASE_INSENSITIVE) { return $this->strripos($needle, $offset); } return $this->strrpos($needle, $offset); @@ -124,7 +124,7 @@ public function strpos(Stringable|string $needle, int $offset = 0): int|false #[Pure] public function findPosition(Stringable|string $needle, int $offset = 0, int $flags = 0): int|false { - if (($flags & static::CASE_INSENSITIVE) == static::CASE_INSENSITIVE) { + if (($flags & self::CASE_INSENSITIVE) == self::CASE_INSENSITIVE) { return $this->stripos($needle, $offset); } return $this->strpos($needle, $offset); @@ -147,7 +147,7 @@ public function substringFromNeedle( bool $beforeNeedle = false, int $flags = 0 ): SmartString|false { - if (($flags & static::CASE_INSENSITIVE) == static::CASE_INSENSITIVE) { + if (($flags & self::CASE_INSENSITIVE) == self::CASE_INSENSITIVE) { return $this->stristr($needle, $beforeNeedle); } return $this->strstr($needle, $beforeNeedle); From 70a2bab01b0f4dbdde5d4795a36244059499e4aa Mon Sep 17 00:00:00 2001 From: Navarr Barnier Date: Sat, 18 Jun 2022 10:07:17 -0400 Subject: [PATCH 18/21] Allow manually triggering the CI workflow --- .github/workflows/commit.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/commit.yml b/.github/workflows/commit.yml index fcee7d8..d727b87 100644 --- a/.github/workflows/commit.yml +++ b/.github/workflows/commit.yml @@ -1,6 +1,7 @@ name: Continuous Integration on: push: + workflow_dispatch: schedule: - cron: 0 0 * * 0 From dbfbc461615dca37adf251866620179654f4fa33 Mon Sep 17 00:00:00 2001 From: Navarr Date: Mon, 6 Oct 2025 16:40:14 -0400 Subject: [PATCH 19/21] Update artifact upload/download scripts --- .github/workflows/commit.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/commit.yml b/.github/workflows/commit.yml index 748c5c3..6ab9ff2 100644 --- a/.github/workflows/commit.yml +++ b/.github/workflows/commit.yml @@ -42,7 +42,7 @@ jobs: run: vendor/bin/phpunit tests --testdox --coverage-clover coverage.xml - name: Upload Coverage Artifact - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: codecov path: coverage.xml @@ -53,7 +53,7 @@ jobs: needs: phpunit steps: - name: Download Coverage Artifact - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v4 with: name: codecov From de6f9905725c3a3d7e0bb08d3fcca04f657b56c3 Mon Sep 17 00:00:00 2001 From: Navarr Date: Mon, 6 Oct 2025 16:40:45 -0400 Subject: [PATCH 20/21] Static -> Self for constant --- src/SmartString.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SmartString.php b/src/SmartString.php index 51de1ab..b8a7bd2 100644 --- a/src/SmartString.php +++ b/src/SmartString.php @@ -149,7 +149,7 @@ public function substringFromNeedle( Stringable|string $needle, int $flags = 0 ): SmartString|false { - if (($flags & static::CASE_INSENSITIVE) == static::CASE_INSENSITIVE) { + if (($flags & self::CASE_INSENSITIVE) == self::CASE_INSENSITIVE) { return $this->stristr($needle); } return $this->strstr($needle); From ae2990ac90379096b89267f25f94456c730bd121 Mon Sep 17 00:00:00 2001 From: Navarr Date: Mon, 6 Oct 2025 16:42:03 -0400 Subject: [PATCH 21/21] Only upload artifact for Ubuntu PHP 8.4 --- .github/workflows/commit.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/commit.yml b/.github/workflows/commit.yml index 6ab9ff2..5cddb3e 100644 --- a/.github/workflows/commit.yml +++ b/.github/workflows/commit.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - os: [unbuntu-latest, macos-latest, windows-latest] + os: [ubuntu-latest, macos-latest, windows-latest] php: ['8.2', '8.3', '8.4'] steps: - name: Setup PHP @@ -43,6 +43,7 @@ jobs: - name: Upload Coverage Artifact uses: actions/upload-artifact@v4 + if: ${{ matrix.php == '8.4' && matrix.os == 'ubuntu-latest' }} with: name: codecov path: coverage.xml