[Str] add grarpheme support

This commit is contained in:
azjezz 2020-10-03 18:56:55 +01:00 committed by Saif Eddin G
parent c5256f3006
commit e1b45c2680
30 changed files with 994 additions and 1 deletions

View File

@ -14,7 +14,8 @@
"ext-bcmath": "*",
"ext-json": "*",
"ext-mbstring": "*",
"ext-sodium": "*"
"ext-sodium": "*",
"ext-intl": "*"
},
"require-dev": {
"phpunit/phpunit": "^9.4",

View File

@ -336,6 +336,20 @@ final class Loader
'Psl\Hash\equals',
'Psl\Hash\Hmac\hash',
'Psl\Hash\Hmac\algorithms',
'Psl\Str\Grapheme\contains',
'Psl\Str\Grapheme\contains_ci',
'Psl\Str\Grapheme\ends_with',
'Psl\Str\Grapheme\ends_with_ci',
'Psl\Str\Grapheme\length',
'Psl\Str\Grapheme\search',
'Psl\Str\Grapheme\search_ci',
'Psl\Str\Grapheme\search_last',
'Psl\Str\Grapheme\search_last_ci',
'Psl\Str\Grapheme\slice',
'Psl\Str\Grapheme\starts_with',
'Psl\Str\Grapheme\starts_with_ci',
'Psl\Str\Grapheme\strip_prefix',
'Psl\Str\Grapheme\strip_suffix',
];
public const INTERFACES = [

View File

@ -0,0 +1,30 @@
<?php
declare(strict_types=1);
namespace Psl\Str\Grapheme;
use Psl;
/**
* Returns whether the 'haystack' string contains the 'needle' string.
*
* An optional offset determines where in the haystack the search begins. If the
* offset is negative, the search will begin that many characters from the end
* of the string. If the offset is out-of-bounds, a ViolationException will be
* thrown.
*
* @psalm-pure
*
* @throws Psl\Exception\InvariantViolationException If the $offset is out-of-bounds.
*/
function contains(string $haystack, string $needle, int $offset = 0): bool
{
if ('' === $needle) {
Psl\Internal\validate_offset($offset, length($haystack));
return true;
}
return null !== search($haystack, $needle, $offset);
}

View File

@ -0,0 +1,30 @@
<?php
declare(strict_types=1);
namespace Psl\Str\Grapheme;
use Psl;
/**
* Returns whether the 'haystack' string contains the 'needle' string.
*
* An optional offset determines where in the haystack the search begins. If the
* offset is negative, the search will begin that many characters from the end
* of the string. If the offset is out-of-bounds, a ViolationException will be
* thrown.
*
* @psalm-pure
*
* @throws Psl\Exception\InvariantViolationException If the $offset is out-of-bounds.
*/
function contains_ci(string $haystack, string $needle, int $offset = 0): bool
{
if ('' === $needle) {
Psl\Internal\validate_offset($offset, length($haystack));
return true;
}
return null !== search_ci($haystack, $needle, $offset);
}

View File

@ -0,0 +1,36 @@
<?php
declare(strict_types=1);
namespace Psl\Str\Grapheme;
use Psl;
/**
* Returns whether the string ends with the given suffix.
*
* @psalm-pure
*
* @throws Psl\Exception\InvariantViolationException If unable to convert $string to UTF-16,
* or split it into graphemes.
*/
function ends_with(string $string, string $suffix): bool
{
if ($suffix === $string) {
return true;
}
$suffix_length = length($suffix);
$total_length = length($string);
if ($suffix_length > $total_length) {
return false;
}
/** @psalm-suppress MissingThrowsDocblock */
$position = search_last($string, $suffix);
if (null === $position) {
return false;
}
return $position + $suffix_length === $total_length;
}

View File

@ -0,0 +1,36 @@
<?php
declare(strict_types=1);
namespace Psl\Str\Grapheme;
use Psl;
/**
* Returns whether the string ends with the given suffix (case-insensitive).
*
* @psalm-pure
*
* @throws Psl\Exception\InvariantViolationException If unable to convert $string to UTF-16,
* or split it into graphemes.
*/
function ends_with_ci(string $string, string $suffix): bool
{
if ($suffix === $string) {
return true;
}
$suffix_length = length($suffix);
$total_length = length($string);
if ($suffix_length > $total_length) {
return false;
}
/** @psalm-suppress MissingThrowsDocblock */
$position = search_last_ci($string, $suffix);
if (null === $position) {
return false;
}
return $position + $suffix_length === $total_length;
}

View File

@ -0,0 +1,27 @@
<?php
declare(strict_types=1);
namespace Psl\Str\Grapheme;
use Psl;
use function grapheme_strlen;
/**
* Returns the length of the given string in grapheme units
*
* @psalm-pure
*
* @throws Psl\Exception\InvariantViolationException If unable to convert $string to UTF-16,
* or split it into graphemes.
*/
function length(string $string): int
{
$length = grapheme_strlen($string);
Psl\invariant(null !== $length, 'unable to convert $string to UTF-16');
Psl\invariant(false !== $length, 'unable to split $string into graphemes');
return $length;
}

View File

@ -0,0 +1,34 @@
<?php
declare(strict_types=1);
namespace Psl\Str\Grapheme;
use Psl;
use function grapheme_strpos;
/**
* Returns the first position of the 'needle' string in the 'haystack' string
* grapheme units, or null if it isn't found.
*
* An optional offset determines where in the haystack the search begins. If the
* offset is negative, the search will begin that many characters from the end
* of the string.
*
* @psalm-pure
*
* @throws Psl\Exception\InvariantViolationException If the $offset is out-of-bounds.
*/
function search(string $haystack, string $needle, int $offset = 0): ?int
{
if ('' === $needle) {
return null;
}
$offset = Psl\Internal\validate_offset($offset, length($haystack));
return false === ($pos = grapheme_strpos($haystack, $needle, $offset)) ?
null :
$pos;
}

View File

@ -0,0 +1,34 @@
<?php
declare(strict_types=1);
namespace Psl\Str\Grapheme;
use Psl;
use function grapheme_stripos;
/**
* Returns the first position of the 'needle' string in the 'haystack' string,
* in grapheme units, or null if it isn't found (case-insensitive).
*
* An optional offset determines where in the haystack the search begins. If the
* offset is negative, the search will begin that many characters from the end
* of the string.
*
* @psalm-pure
*
* @throws Psl\Exception\InvariantViolationException If $offset is out-of-bounds.
*/
function search_ci(string $haystack, string $needle, int $offset = 0): ?int
{
if ('' === $needle) {
return null;
}
$offset = Psl\Internal\validate_offset($offset, length($haystack));
return false === ($pos = grapheme_stripos($haystack, $needle, $offset)) ?
null :
$pos;
}

View File

@ -0,0 +1,35 @@
<?php
declare(strict_types=1);
namespace Psl\Str\Grapheme;
use Psl;
use function grapheme_strrpos;
/**
* Returns the last position of the 'needle' string in the 'haystack' string,
* or null if it isn't found.
*
* An optional offset determines where in the haystack (from the beginning) the
* search begins. If the offset is negative, the search will begin that many
* characters from the end of the string and go backwards.
*
* @psalm-pure
*
* @throws Psl\Exception\InvariantViolationException If the $offset is out-of-bounds.
*/
function search_last(string $haystack, string $needle, int $offset = 0): ?int
{
if ('' === $needle) {
return null;
}
$haystack_length = length($haystack);
Psl\invariant($offset >= -$haystack_length && $offset <= $haystack_length, 'Offset is out-of-bounds.');
return false === ($pos = grapheme_strrpos($haystack, $needle, $offset)) ?
null :
$pos;
}

View File

@ -0,0 +1,35 @@
<?php
declare(strict_types=1);
namespace Psl\Str\Grapheme;
use Psl;
use function grapheme_strripos;
/**
* Returns the last position of the 'needle' string in the 'haystack' string,
* or null if it isn't found (case-insensitive).
*
* An optional offset determines where in the haystack (from the beginning) the
* search begins. If the offset is negative, the search will begin that many
* characters from the end of the string and go backwards.
*
* @psalm-pure
*
* @throws Psl\Exception\InvariantViolationException If the offset is out-of-bounds.
*/
function search_last_ci(string $haystack, string $needle, int $offset = 0): ?int
{
if ('' === $needle) {
return null;
}
$haystack_length = length($haystack);
Psl\invariant($offset >= -$haystack_length && $offset <= $haystack_length, 'Offset is out-of-bounds.');
return false === ($pos = grapheme_strripos($haystack, $needle, $offset)) ?
null :
$pos;
}

View File

@ -0,0 +1,36 @@
<?php
declare(strict_types=1);
namespace Psl\Str\Grapheme;
use Psl;
/**
* Returns a substring of length `$length` of the given string starting at the
* `$offset`.
*
* If no length is given, the slice will contain the rest of the
* string. If the length is zero, the empty string will be returned. If the
* offset is out-of-bounds, an InvariantViolationException will be thrown.
*
* @psalm-pure
*
* @throws Psl\Exception\InvariantViolationException If a negative $length is given, or $offset is out-of-bounds.
*/
function slice(string $string, int $offset, ?int $length = null): string
{
Psl\invariant(null === $length || $length >= 0, 'Expected a non-negative length.');
$string_length = length($string);
$offset = Psl\Internal\validate_offset($offset, $string_length);
if (0 === $offset && (null === $length || $string_length <= $length)) {
return $string;
}
if (null === $length) {
return (string) grapheme_substr($string, $offset);
}
return (string) grapheme_substr($string, $offset, $length);
}

View File

@ -0,0 +1,16 @@
<?php
declare(strict_types=1);
namespace Psl\Str\Grapheme;
/**
* Returns whether the string starts with the given prefix.
*
* @psalm-pure
*/
function starts_with(string $string, string $prefix): bool
{
/** @psalm-suppress MissingThrowsDocblock */
return 0 === search($string, $prefix);
}

View File

@ -0,0 +1,16 @@
<?php
declare(strict_types=1);
namespace Psl\Str\Grapheme;
/**
* Returns whether the string starts with the given prefix (case-insensitive).
*
* @psalm-pure
*/
function starts_with_ci(string $string, string $prefix): bool
{
/** @psalm-suppress MissingThrowsDocblock */
return 0 === search_ci($string, $prefix);
}

View File

@ -0,0 +1,21 @@
<?php
declare(strict_types=1);
namespace Psl\Str\Grapheme;
/**
* Returns the string with the given prefix removed, or the string itself if
* it doesn't start with the prefix.
*
* @psalm-pure
*/
function strip_prefix(string $string, string $prefix): string
{
if ('' === $prefix || !starts_with($string, $prefix)) {
return $string;
}
/** @psalm-suppress MissingThrowsDocblock */
return slice($string, length($prefix));
}

View File

@ -0,0 +1,21 @@
<?php
declare(strict_types=1);
namespace Psl\Str\Grapheme;
/**
* Returns the string with the given suffix removed, or the string itself if
* it doesn't end with the suffix.
*
* @psalm-pure
*/
function strip_suffix(string $string, string $suffix): string
{
if ('' === $suffix || !ends_with($string, $suffix)) {
return $string;
}
/** @psalm-suppress MissingThrowsDocblock */
return slice($string, 0, length($string) - length($suffix));
}

View File

@ -0,0 +1,32 @@
<?php
declare(strict_types=1);
namespace Psl\Tests\Str\Grapheme;
use PHPUnit\Framework\TestCase;
use Psl\Str\Grapheme;
final class ContainsCiTest extends TestCase
{
/**
* @dataProvider provideData
*/
public function testContainsCi(bool $expected, string $haystack, string $needle, int $offset = 0): void
{
static::assertSame($expected, Grapheme\contains_ci($haystack, $needle, $offset));
}
public function provideData(): array
{
return [
[true, 'Hello, World', 'Hello', 0],
[true, 'Hello, World', 'world', 0],
[true, 'Hello, World', '', 8],
[false, 'hello, world', 'hey', 5],
[true, 'Azjezz', 'az', 0],
[false, 'azjezz', 'Az', 2],
[true, 'مرحبا بكم', 'بكم', 5],
];
}
}

View File

@ -0,0 +1,72 @@
<?php
declare(strict_types=1);
namespace Psl\Tests\Str\Grapheme;
use PHPUnit\Framework\TestCase;
use Psl\Str\Grapheme;
final class ContainsTest extends TestCase
{
/**
* @dataProvider provideData
*/
public function testContains(bool $expected, string $haystack, string $needle, int $offset = 0): void
{
static::assertSame($expected, Grapheme\contains($haystack, $needle, $offset));
}
public function provideData(): array
{
return [
[
true,
'Hello, World',
'Hello',
0
],
[
false,
'Hello, World',
'world',
0
],
[
true,
'Hello, World',
'',
8
],
[
false,
'hello, world',
'hey',
5
],
[
true,
'azjezz',
'az',
0
],
[
false,
'azjezz',
'Az',
2
],
[
true,
'مرحبا بكم',
'بكم',
5
]
];
}
}

View File

@ -0,0 +1,35 @@
<?php
declare(strict_types=1);
namespace Psl\Tests\Str\Grapheme;
use PHPUnit\Framework\TestCase;
use Psl\Str\Grapheme;
final class EndsWithCiTest extends TestCase
{
/**
* @dataProvider provideData
*/
public function testEndsWithCi(bool $expected, string $haystack, string $suffix): void
{
static::assertSame($expected, Grapheme\ends_with_ci($haystack, $suffix));
}
public function provideData(): array
{
return [
[true, 'Hello', 'Hello'],
[true, 'Hello, World', 'world', ],
[true, 'Hello, WorlḐ', 'worlḑ', ],
[false, 'T U N I S I A', 'e', ],
[true, 'تونس', 'س'],
[false, 'Hello, World', '', ],
[false, 'hello, world', 'hey', ],
[false, 'hello, world', 'hello cruel world'],
[true, 'azjezz', 'z', ],
[true, 'مرحبا بكم', 'بكم', ],
];
}
}

View File

@ -0,0 +1,34 @@
<?php
declare(strict_types=1);
namespace Psl\Tests\Str\Grapheme;
use PHPUnit\Framework\TestCase;
use Psl\Str\Grapheme;
final class EndsWithTest extends TestCase
{
/**
* @dataProvider provideData
*/
public function testEndsWith(bool $expected, string $haystack, string $suffix): void
{
static::assertSame($expected, Grapheme\ends_with($haystack, $suffix));
}
public function provideData(): array
{
return [
[true, 'Hello', 'Hello'],
[false, 'Hello, World', 'world', ],
[false, 'T U N I S I A', 'e', ],
[true, 'تونس', 'س'],
[false, 'Hello, World', '', ],
[false, 'Hello, World', 'Hello, cruel world!', ],
[false, 'hello, world', 'hey', ],
[true, 'azjezz', 'z', ],
[true, 'مرحبا بكم', 'بكم', ],
];
}
}

View File

@ -0,0 +1,33 @@
<?php
declare(strict_types=1);
namespace Psl\Tests\Str\Grapheme;
use PHPUnit\Framework\TestCase;
use Psl\Str\Grapheme;
final class LengthTest extends TestCase
{
/**
* @dataProvider provideData
*/
public function testLength(int $expected, string $str): void
{
static::assertSame($expected, Grapheme\length($str));
}
public function provideData(): array
{
return [
[6, 'azjezz'],
[4, 'تونس'],
[3, 'سيف'],
[7, 'こんにちは世界'],
[3, '🥇🥈🥉'],
[2, '你好'],
[4, 'สวัสดี'],
[3, 'ؤخى']
];
}
}

View File

@ -0,0 +1,33 @@
<?php
declare(strict_types=1);
namespace Psl\Tests\Str\Grapheme;
use PHPUnit\Framework\TestCase;
use Psl\Str\Grapheme;
final class SearchCiTest extends TestCase
{
/**
* @dataProvider provideData
*/
public function testSearchCi(?int $expected, string $haystack, string $needle, int $offset = 0): void
{
static::assertSame($expected, Grapheme\search_ci($haystack, $needle, $offset));
}
public function provideData(): array
{
return [
[7, 'Hello, you!', 'You', ],
[7, 'Hello, You!', 'You', ],
[0, 'Ho! Ho! Ho!', 'ho', ],
[0, 'Ho! Ho! Ho!', 'Ho', ],
[7, 'Hello, You!', 'You', 5],
[null, 'Hello, World!', 'You', 5],
[6, 'مرحبا سيف', 'سيف', 4],
[null, 'foo', 'bar', 2],
];
}
}

View File

@ -0,0 +1,33 @@
<?php
declare(strict_types=1);
namespace Psl\Tests\Str\Grapheme;
use PHPUnit\Framework\TestCase;
use Psl\Str\Grapheme;
final class SearchLastCiTest extends TestCase
{
/**
* @dataProvider provideData
*/
public function testSearchLastCi(?int $expected, string $haystack, string $needle, int $offset = 0): void
{
static::assertSame($expected, Grapheme\search_last_ci($haystack, $needle, $offset));
}
public function provideData(): array
{
return [
[7, 'Hello, you!', 'You', ],
[7, 'Hello, You!', 'You', ],
[8, 'Ho! Ho! Ho!', 'ho', ],
[8, 'Ho! Ho! Ho!', 'Ho', ],
[7, 'Hello, You!', 'You', 5],
[null, 'Hello, World!', 'You', 5],
[6, 'مرحبا سيف', 'سيف', 4],
[null, 'foo', 'bar', 2],
];
}
}

View File

@ -0,0 +1,33 @@
<?php
declare(strict_types=1);
namespace Psl\Tests\Str\Grapheme;
use PHPUnit\Framework\TestCase;
use Psl\Str\Grapheme;
final class SearchLastTest extends TestCase
{
/**
* @dataProvider provideData
*/
public function testSearchLast(?int $expected, string $haystack, string $needle, int $offset = 0): void
{
static::assertSame($expected, Grapheme\search_last($haystack, $needle, $offset));
}
public function provideData(): array
{
return [
[null, 'Hello, you!', 'You', ],
[7, 'Hello, You!', 'You', ],
[null, 'Ho! Ho! Ho!', 'ho', ],
[8, 'Ho! Ho! Ho!', 'Ho', ],
[7, 'Hello, You!', 'You', 5],
[null, 'Hello, World!', 'You', 5],
[6, 'مرحبا سيف', 'سيف', 4],
[null, 'foo', 'bar', 2],
];
}
}

View File

@ -0,0 +1,33 @@
<?php
declare(strict_types=1);
namespace Psl\Tests\Str\Grapheme;
use PHPUnit\Framework\TestCase;
use Psl\Str\Grapheme;
final class SearchTest extends TestCase
{
/**
* @dataProvider provideData
*/
public function testSearch(?int $expected, string $haystack, string $needle, int $offset = 0): void
{
static::assertSame($expected, Grapheme\search($haystack, $needle, $offset));
}
public function provideData(): array
{
return [
[null, 'Hello, you!', 'You', ],
[7, 'Hello, You!', 'You', ],
[null, 'Ho! Ho! Ho!', 'ho', ],
[0, 'Ho! Ho! Ho!', 'Ho', ],
[7, 'Hello, You!', 'You', 5],
[null, 'Hello, World!', 'You', 5],
[6, 'مرحبا سيف', 'سيف', 4],
[null, 'foo', 'bar', 2],
];
}
}

View File

@ -0,0 +1,62 @@
<?php
declare(strict_types=1);
namespace Psl\Tests\Str\Grapheme;
use PHPUnit\Framework\TestCase;
use Psl\Exception;
use Psl\Str\Grapheme;
final class SliceTest extends TestCase
{
/**
* @dataProvider provideData
*/
public function testSlice(string $expected, string $string, int $offset, ?int $length = null): void
{
static::assertSame($expected, Grapheme\slice($string, $offset, $length));
}
public function provideData(): array
{
return [
['', '', 0, 0, ],
['Hello', 'Hello, World!', 0, 5],
['Hello, World!', 'Hello, World!', 0],
['World', 'Hello, World!', 7, 5],
['سيف', 'مرحبا سيف', 6, 3],
['اهلا', 'اهلا بكم', 0, 4],
['destiny', 'People linked by destiny will always find each other.', 17, 7],
['lö ', 'héllö wôrld', 3, 3, ],
['lö wôrld', 'héllö wôrld', 3, null, ],
['', 'héllö wôrld', 3, 0],
['', 'fôo', 3, null, ],
['', 'fôo', 3, 12, ],
['wôrld', 'héllö wôrld', -5, null, ],
['wôrld', 'héllö wôrld', -5, 100, ],
['wôr', 'héllö wôrld', -5, 3, ],
];
}
public function testSliceThrowsForNegativeLength(): void
{
$this->expectException(Exception\InvariantViolationException::class);
Grapheme\slice('Hello', 0, -1);
}
public function testSliceThrowsForOutOfBoundOffset(): void
{
$this->expectException(Exception\InvariantViolationException::class);
Grapheme\slice('Hello', 10);
}
public function testSliceThrowsForNegativeOutOfBoundOffset(): void
{
$this->expectException(Exception\InvariantViolationException::class);
Grapheme\slice('hello', -6);
}
}

View File

@ -0,0 +1,41 @@
<?php
declare(strict_types=1);
namespace Psl\Tests\Str\Grapheme;
use PHPUnit\Framework\TestCase;
use Psl\Str\Grapheme;
final class StartsWithCiTest extends TestCase
{
/**
* @dataProvider provideData
*/
public function testStartsWithCi(bool $expected, string $haystack, string $prefix): void
{
static::assertSame($expected, Grapheme\starts_with_ci($haystack, $prefix));
}
public function provideData(): array
{
return [
[true, 'Hello, World', 'Hello', ],
[false, 'Hello, World', 'world', ],
[false, 'Hello, World', '', ],
[false, 'hello, world', 'hey', ],
[true, 'azjezz', 'az', ],
[true, 'azjezz', 'Az', ],
[false, 'مرحبا بكم', 'بكم', ],
[true, 'مرحبا بكم', 'مرحبا', ],
[true, 'مرحبا سيف', 'مرحبا', 3],
[false, 'مرحبا سيف', 'سيف', 3],
[true, 'اهلا بكم', 'اهلا', 2],
[true, 'héllö wôrld', 'héllö', ],
[false, 'héllö wôrld', 'hello', ],
[true, 'fôo', 'fôo', ],
[true, 'fôo', 'f', ],
[true, 'fôo', 'fô', ],
];
}
}

View File

@ -0,0 +1,41 @@
<?php
declare(strict_types=1);
namespace Psl\Tests\Str\Grapheme;
use PHPUnit\Framework\TestCase;
use Psl\Str\Grapheme;
final class StartsWithTest extends TestCase
{
/**
* @dataProvider provideData
*/
public function testStartsWith(bool $expected, string $haystack, string $prefix): void
{
static::assertSame($expected, Grapheme\starts_with($haystack, $prefix));
}
public function provideData(): array
{
return [
[true, 'Hello, World', 'Hello', ],
[false, 'Hello, World', 'world', ],
[false, 'Hello, World', '', ],
[false, 'hello, world', 'hey', ],
[true, 'azjezz', 'az', ],
[false, 'azjezz', 'Az', ],
[false, 'مرحبا بكم', 'بكم', ],
[true, 'مرحبا بكم', 'مرحبا', ],
[true, 'مرحبا سيف', 'مرحبا', 3],
[false, 'مرحبا سيف', 'سيف', 3],
[true, 'اهلا بكم', 'اهلا', 2],
[true, 'héllö wôrld', 'héllö', ],
[false, 'héllö wôrld', 'hello', ],
[true, 'fôo', 'fôo', ],
[true, 'fôo', 'f', ],
[true, 'fôo', 'fô', ],
];
}
}

View File

@ -0,0 +1,41 @@
<?php
declare(strict_types=1);
namespace Psl\Tests\Str\Grapheme;
use PHPUnit\Framework\TestCase;
use Psl\Str\Grapheme;
class StripPrefixTest extends TestCase
{
/**
* @dataProvider provideData
*/
public function testStripPrefix(string $expected, string $haystack, string $prefix): void
{
static::assertSame($expected, Grapheme\strip_prefix($haystack, $prefix));
}
public function provideData(): array
{
return [
['World', 'Hello, World', 'Hello, '],
['Hello, World', 'Hello, World', 'world'],
['Hello, World', 'Hello, World', ''],
['hello, world', 'hello, world', 'hey'],
['jezz', 'azjezz', 'az'],
['azjezz', 'azjezz', 'Az'],
['مرحبا بكم', 'مرحبا بكم', 'بكم'],
['بكم', 'مرحبا بكم', 'مرحبا '],
['سيف', 'مرحبا سيف', 'مرحبا ', 3],
['مرحبا سيف', 'مرحبا سيف', 'سيف', 3],
[' بكم', 'اهلا بكم', 'اهلا', 2],
['wôrld', 'héllö wôrld', 'héllö '],
['héllö wôrld', 'héllö wôrld', 'hello'],
['', 'fôo', 'fôo'],
['ôo', 'fôo', 'f'],
['o', 'fôo', 'fô'],
];
}
}

View File

@ -0,0 +1,48 @@
<?php
declare(strict_types=1);
namespace Psl\Tests\Str\Grapheme;
use PHPUnit\Framework\TestCase;
use Psl\Str\Grapheme;
final class StripSuffixTest extends TestCase
{
/**
* @dataProvider provideData
*/
public function testStripSuffix(string $expected, string $haystack, string $suffix): void
{
static::assertSame($expected, Grapheme\strip_suffix($haystack, $suffix));
}
public function provideData(): array
{
return [
['', 'Hello', 'Hello'],
['Hello, World', 'Hello, World', 'world', ],
['T U N I S I A', 'T U N I S I A', 'e', ],
['تون', 'تونس', 'س'],
['Hello, World', 'Hello, World', '', ],
['Hello, World', 'Hello, World', 'Hello, cruel world!', ],
['hello, world', 'hello, world', 'hey', ],
['azjez', 'azjezz', 'z', ],
['مرحبا ', 'مرحبا بكم', 'بكم', ],
['Hello', 'Hello, World', ', World', ],
['Hello, World', 'Hello, World', 'world', ],
['Hello, World', 'Hello, World', '', ],
['hello, world', 'hello, world', 'universe', ],
['azje', 'azjezz', 'zz', ],
['azjezz', 'azjezz', 'ZZ', ],
['مرحبا', 'مرحبا سيف', ' سيف', 3],
['اهلا', 'اهلا بكم', ' بكم', 3],
['héllö', 'héllö wôrld', ' wôrld', ],
['héllö wôrld', 'héllö wôrld', ' world', ],
['fô', 'fôo', 'o', ],
['fôo', 'fôo', 'ô', ],
['f', 'fôo', 'ôo', ],
];
}
}