Skip to content

Commit 185453e

Browse files
committed
Add StringEndsWith constraint
1 parent 0c71437 commit 185453e

File tree

3 files changed

+114
-0
lines changed

3 files changed

+114
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ class ExampleTest extends PHPUnit\Framework\TestCase
4040
* [IsURL](./src/Constraint/IsURL.php): asserts that a string contains only an URL
4141
* [IsEmail](./src/Constraint/IsEmail.php): asserts that a string contains only an email address
4242
* [StringStartsWith](./src/Constraint/StringStartsWith.php): asserts that a string starts with another string
43+
* [StringEndsWith](./src/Constraint/StringEndsWith.php): asserts that a string ends with another string
4344

4445
## Tests
4546

src/Constraint/StringEndsWith.php

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PHPUnitExtraConstraints\Constraint;
6+
7+
use PHPUnit\Framework\Constraint\Constraint;
8+
9+
use function is_string;
10+
use function strlen;
11+
use function substr_compare;
12+
13+
/**
14+
* Constraint that asserts that a string ends with another string.
15+
*/
16+
final class StringEndsWith extends Constraint
17+
{
18+
/** @var string */
19+
private $needle;
20+
21+
public function __construct(string $needle)
22+
{
23+
$this->needle = $needle;
24+
}
25+
26+
/**
27+
* @inheritDoc
28+
*/
29+
protected function matches($other): bool
30+
{
31+
return is_string($other)
32+
&& self::endsWith($other, $this->needle);
33+
}
34+
35+
private static function endsWith(string $haystack, string $needle): bool
36+
{
37+
return '' === $needle || ('' !== $haystack && 0 === substr_compare($haystack, $needle, -strlen($needle)));
38+
}
39+
40+
/**
41+
* @inheritDoc
42+
*/
43+
public function toString(): string
44+
{
45+
return 'ends with ' . $this->needle;
46+
}
47+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Tests\PHPUnitExtraConstraints\Constraint;
6+
7+
use PHPUnitExtraConstraints\Constraint\StringEndsWith;
8+
use Tests\PHPUnitExtraConstraints\CustomTestCase;
9+
10+
class StringEndsWithTest extends CustomTestCase
11+
{
12+
/**
13+
* @dataProvider provideValidStrings
14+
* @testdox testWithValidString: $value ends with $needle
15+
*
16+
* @param string $needle
17+
* @param string $value
18+
*/
19+
public function testWithValidString(string $needle, string $value): void
20+
{
21+
$constraint = new StringEndsWith($needle);
22+
self::assertThat($value, $constraint);
23+
}
24+
25+
/**
26+
* @return iterable<array<string>>
27+
*/
28+
public function provideValidStrings(): iterable
29+
{
30+
yield ['c', 'abc'];
31+
yield ['bc', 'abc'];
32+
yield ['abc', 'abc'];
33+
yield ['', 'abc'];
34+
yield ['0', '00'];
35+
}
36+
37+
/**
38+
* @dataProvider provideInvalidStrings
39+
* @testdox testWithInvalidString: $value doesn't end with $needle
40+
*
41+
* @param string $needle
42+
* @param mixed $value
43+
*/
44+
public function testWithInvalidString(string $needle, $value): void
45+
{
46+
$constraint = new StringEndsWith($needle);
47+
$this->expectAssertionFailedError('ends with ' . $needle);
48+
self::assertThat($value, $constraint);
49+
}
50+
51+
/**
52+
* @return iterable<array<mixed>>
53+
*/
54+
public function provideInvalidStrings(): iterable
55+
{
56+
yield ['zzz', null];
57+
yield ['zzz', true];
58+
yield ['zzz', false];
59+
yield ['zzz', 0];
60+
yield ['zzz', 1];
61+
yield ['zzz', []];
62+
yield ['zzz', (object) []];
63+
yield ['zzz', 'abc'];
64+
yield ['zzz', 'z'];
65+
}
66+
}

0 commit comments

Comments
 (0)