Skip to content

Commit bf4f816

Browse files
jrfnlvjiksebastianbergmann
committed
PHPUnit 10 | AssertIgnoringLineEndings trait: polyfill the Assert::assertStringEqualsStringIgnoringLineEndings() et al methods
PHPUnit 10.0.0 introduces the new `Assert::assertStringEqualsStringIgnoringLineEndings()` and `Assert::assertStringContainsStringIgnoringLineEndings()` methods. This commit: * Adds two traits with the same name. One to polyfill the methods when not available in PHPUnit. The other - an empty trait - to allow for `use`-ing the trait in PHPUnit versions in which the methods are already natively available. * Logic to the custom autoloader which will load the correct trait depending on the PHPUnit version used. * An availability test and limited functional test for the functionality polyfilled. Note: the function name for the `private` `normalizeLineEndings()` method is a little convoluted - `normalizeLineEndingsForIgnoringLineEndingsAssertions()`. This is intentional to prevent potential naming collisions with pre-existing end-user defined methods for the same, which may exist in other traits used in tests, which would be hard to solve due to the method only existing in the non-empty trait. Includes: * Adding the new polyfill to the existing `TestCases` classes. Refs: * sebastianbergmann/phpunit#4641 * sebastianbergmann/phpunit#4670 (and follow up commits) * sebastianbergmann/phpunit#5279 Co-authored-by: Sergei Predvoditelev <sergey.predvoditelev@gmail.com> Co-authored-by: Sebastian Bergmann <sb@sebastian-bergmann.de>
1 parent 73bf346 commit bf4f816

File tree

9 files changed

+592
-0
lines changed

9 files changed

+592
-0
lines changed

README.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ Set of polyfills for changed PHPUnit functionality to allow for creating PHPUnit
1818
- [PHPUnit support](#phpunit-support)
1919
* [Using this library](#using-this-library)
2020
- [Supported ways of calling the assertions](#supported-ways-of-calling-the-assertions)
21+
- [Use with PHPUnit < 7.5.0](#use-with-phpunit--750)
2122
* [Features](#features)
2223
- [Polyfill traits](#polyfill-traits)
2324
- [Helper traits](#helper-traits)
@@ -147,6 +148,45 @@ For the polyfills to work, a test class is **required** to be a (grand-)child of
147148

148149
[four ways of calling assertions]: https://docs.phpunit.de/en/9.6/assertions.html#static-vs-non-static-usage-of-assertion-methods
149150

151+
### Use with PHPUnit < 7.5.0
152+
153+
If your library still needs to support PHP < 7.1 and therefore needs PHPUnit < 7 for testing, there are a few caveats when using the traits stand-alone as we then enter "double-polyfill" territory.
154+
155+
To prevent _"conflicting method names"_ errors when a trait is `use`d multiple times in a class, the traits offered here do not attempt to solve this.
156+
157+
You will need to make sure to `use` any additional traits needed for the polyfills to work.
158+
159+
| PHPUnit | When `use`-ing this trait | You also need to `use` this trait |
160+
|-----------|-----------------------------|-----------------------------------|
161+
| 5.7 < 7.5 | `AssertIgnoringLineEndings` | `AssertStringContains` |
162+
163+
_**Note: this only applies to the stand-alone use of the traits. The [`TestCase` classes](#testcases) provided by this library already take care of this automatically.**_
164+
165+
Code example for a test using the `AssertIgnoringLineEndings` trait, which needs to be able to run on PHPUnit 5.7:
166+
```php
167+
<?php
168+
169+
namespace Vendor\YourPackage\Tests;
170+
171+
use PHPUnit\Framework\TestCase;
172+
use Yoast\PHPUnitPolyfills\Polyfills\AssertIgnoringLineEndings;
173+
use Yoast\PHPUnitPolyfills\Polyfills\AssertStringContains;
174+
175+
class FooTest extends TestCase
176+
{
177+
use AssertIgnoringLineEndings;
178+
use AssertStringContains;
179+
180+
public function testSomething()
181+
{
182+
$this->assertStringContainsStringIgnoringLineEndings(
183+
"something\nelse",
184+
"this is something\r\nelse"
185+
);
186+
}
187+
}
188+
```
189+
150190

151191
Features
152192
--------
@@ -354,6 +394,18 @@ The `assertObjectEquals()` assertion was introduced in PHPUnit 9.4.0.
354394

355395
[`Assert::assertObjectEquals()`]: https://docs.phpunit.de/en/9.6/assertions.html#assertobjectequals
356396

397+
#### PHPUnit < 10.0.0: `Yoast\PHPUnitPolyfills\Polyfills\AssertIgnoringLineEndings`
398+
399+
Polyfills the following methods:
400+
| | |
401+
|-----------------------------------------------------------|-------------------------------------------------------------|
402+
| [`Assert::assertStringEqualsStringIgnoringLineEndings()`] | [`Assert::assertStringContainsStringIgnoringLineEndings()`] |
403+
404+
These methods were introduced in PHPUnit 10.0.0.
405+
406+
[`Assert::assertStringEqualsStringIgnoringLineEndings()`]: https://docs.phpunit.de/en/main/assertions.html#assertstringequalsstringignoringlineendings
407+
[`Assert::assertStringContainsStringIgnoringLineEndings()`]: https://docs.phpunit.de/en/main/assertions.html#assertstringcontainsstringignoringlineendings
408+
357409

358410
### Helper traits
359411

phpunitpolyfills-autoload.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,10 @@ public static function load( $className ) {
9191
self::loadAssertObjectEquals();
9292
return true;
9393

94+
case 'Yoast\PHPUnitPolyfills\Polyfills\AssertIgnoringLineEndings':
95+
self::loadAssertIgnoringLineEndings();
96+
return true;
97+
9498
case 'Yoast\PHPUnitPolyfills\TestCases\TestCase':
9599
self::loadTestCase();
96100
return true;
@@ -289,6 +293,23 @@ public static function loadAssertObjectEquals() {
289293
require_once __DIR__ . '/src/Polyfills/AssertObjectEquals_Empty.php';
290294
}
291295

296+
/**
297+
* Load the AssertIgnoringLineEndings polyfill or an empty trait with the same name
298+
* if a PHPUnit version is used which already contains this functionality.
299+
*
300+
* @return void
301+
*/
302+
public static function loadAssertIgnoringLineEndings() {
303+
if ( \method_exists( Assert::class, 'assertStringEqualsStringIgnoringLineEndings' ) === false ) {
304+
// PHPUnit < 10.0.0.
305+
require_once __DIR__ . '/src/Polyfills/AssertIgnoringLineEndings.php';
306+
return;
307+
}
308+
309+
// PHPUnit >= 10.0.0.
310+
require_once __DIR__ . '/src/Polyfills/AssertIgnoringLineEndings_Empty.php';
311+
}
312+
292313
/**
293314
* Load the appropriate TestCase class based on the PHPUnit version being used.
294315
*
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
<?php
2+
3+
namespace Yoast\PHPUnitPolyfills\Polyfills;
4+
5+
use PHPUnit\SebastianBergmann\Exporter\Exporter as Exporter_In_Phar;
6+
use SebastianBergmann\Exporter\Exporter;
7+
use TypeError;
8+
9+
/**
10+
* Polyfill the Assert::assertStringEqualsStringIgnoringLineEndings() and the
11+
* Assert::assertStringContainsStringIgnoringLineEndings() methods.
12+
*
13+
* Introduced in PHPUnit 10.0.0.
14+
*
15+
* @link https://github.com/sebastianbergmann/phpunit/issues/4641
16+
* @link https://github.com/sebastianbergmann/phpunit/pull/4670
17+
* @link https://github.com/sebastianbergmann/phpunit/issues/4935
18+
* @link https://github.com/sebastianbergmann/phpunit/pull/5279
19+
*/
20+
trait AssertIgnoringLineEndings {
21+
22+
/**
23+
* Asserts that two strings are equal except for line endings.
24+
*
25+
* @param string $expected Expected value.
26+
* @param string $actual The value to test.
27+
* @param string $message Optional failure message to display.
28+
*
29+
* @return void
30+
*
31+
* @throws TypeError When any of the passed arguments do not meet the required type.
32+
*/
33+
final public static function assertStringEqualsStringIgnoringLineEndings( $expected, $actual, $message = '' ) {
34+
/*
35+
* Parameter input validation.
36+
* In PHPUnit this is done via PHP native type declarations. Emulating this for the polyfill.
37+
* Note: using `is_scalar()` instead of `is_string()` as test files may not be using strict_types.
38+
*/
39+
if ( \is_scalar( $expected ) === false ) {
40+
throw new TypeError(
41+
\sprintf(
42+
'Argument 1 passed to assertStringEqualsStringIgnoringLineEndings() must be of type string, %s given',
43+
\gettype( $expected )
44+
)
45+
);
46+
}
47+
if ( \is_scalar( $actual ) === false ) {
48+
throw new TypeError(
49+
\sprintf(
50+
'Argument 2 passed to assertStringEqualsStringIgnoringLineEndings() must be of type string, %s given',
51+
\gettype( $actual )
52+
)
53+
);
54+
}
55+
56+
57+
$expected = self::normalizeLineEndingsForIgnoringLineEndingsAssertions( (string) $expected );
58+
$exporter = \class_exists( Exporter::class ) ? new Exporter() : new Exporter_In_Phar();
59+
$msg = \sprintf(
60+
'Failed asserting that %s is equal to "%s" ignoring line endings.',
61+
$exporter->export( $actual ),
62+
$expected
63+
);
64+
65+
if ( $message !== '' ) {
66+
$msg = $message . \PHP_EOL . $msg;
67+
}
68+
69+
$actual = self::normalizeLineEndingsForIgnoringLineEndingsAssertions( (string) $actual );
70+
71+
static::assertSame( $expected, $actual, $msg );
72+
}
73+
74+
/**
75+
* Asserts that two variables are equal (ignoring case).
76+
*
77+
* @param string $needle The string to search for.
78+
* @param string $haystack The string to treat as the haystack.
79+
* @param string $message Optional failure message to display.
80+
*
81+
* @return void
82+
*
83+
* @throws TypeError When any of the passed arguments do not meet the required type.
84+
*/
85+
final public static function assertStringContainsStringIgnoringLineEndings( $needle, $haystack, $message = '' ) {
86+
/*
87+
* Parameter input validation.
88+
* In PHPUnit this is done via PHP native type declarations. Emulating this for the polyfill.
89+
* Note: using `is_scalar()` instead of `is_string()` as test files may not be using strict_types.
90+
*/
91+
if ( \is_scalar( $needle ) === false ) {
92+
throw new TypeError(
93+
\sprintf(
94+
'Argument 1 passed to assertStringContainsStringIgnoringLineEndings() must be of type string, %s given',
95+
\gettype( $needle )
96+
)
97+
);
98+
}
99+
if ( \is_scalar( $haystack ) === false ) {
100+
throw new TypeError(
101+
\sprintf(
102+
'Argument 2 passed to assertStringContainsStringIgnoringLineEndings() must be of type string, %s given',
103+
\gettype( $haystack )
104+
)
105+
);
106+
}
107+
108+
$needle = self::normalizeLineEndingsForIgnoringLineEndingsAssertions( (string) $needle );
109+
$haystack = self::normalizeLineEndingsForIgnoringLineEndingsAssertions( (string) $haystack );
110+
111+
static::assertStringContainsString( $needle, $haystack, $message );
112+
}
113+
114+
/**
115+
* Normalize line endings.
116+
*
117+
* @param string $value The text to normalize.
118+
*
119+
* @return string
120+
*/
121+
private static function normalizeLineEndingsForIgnoringLineEndingsAssertions( $value ) {
122+
return \strtr(
123+
$value,
124+
[
125+
"\r\n" => "\n",
126+
"\r" => "\n",
127+
]
128+
);
129+
}
130+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
3+
namespace Yoast\PHPUnitPolyfills\Polyfills;
4+
5+
/**
6+
* Empty trait for use with PHPUnit >= 10.0.0 in which this polyfill is not needed.
7+
*/
8+
trait AssertIgnoringLineEndings {}

src/TestCases/TestCasePHPUnitGte8.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use Yoast\PHPUnitPolyfills\Helpers\AssertAttributeHelper;
77
use Yoast\PHPUnitPolyfills\Polyfills\AssertClosedResource;
88
use Yoast\PHPUnitPolyfills\Polyfills\AssertFileEqualsSpecializations;
9+
use Yoast\PHPUnitPolyfills\Polyfills\AssertIgnoringLineEndings;
910
use Yoast\PHPUnitPolyfills\Polyfills\AssertionRenames;
1011
use Yoast\PHPUnitPolyfills\Polyfills\AssertObjectEquals;
1112
use Yoast\PHPUnitPolyfills\Polyfills\EqualToSpecializations;
@@ -25,6 +26,7 @@ abstract class TestCase extends PHPUnit_TestCase {
2526
use AssertAttributeHelper;
2627
use AssertClosedResource;
2728
use AssertFileEqualsSpecializations;
29+
use AssertIgnoringLineEndings;
2830
use AssertionRenames;
2931
use AssertObjectEquals;
3032
use EqualToSpecializations;

src/TestCases/TestCasePHPUnitLte7.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use Yoast\PHPUnitPolyfills\Polyfills\AssertClosedResource;
88
use Yoast\PHPUnitPolyfills\Polyfills\AssertEqualsSpecializations;
99
use Yoast\PHPUnitPolyfills\Polyfills\AssertFileEqualsSpecializations;
10+
use Yoast\PHPUnitPolyfills\Polyfills\AssertIgnoringLineEndings;
1011
use Yoast\PHPUnitPolyfills\Polyfills\AssertionRenames;
1112
use Yoast\PHPUnitPolyfills\Polyfills\AssertIsType;
1213
use Yoast\PHPUnitPolyfills\Polyfills\AssertObjectEquals;
@@ -30,6 +31,7 @@ abstract class TestCase extends PHPUnit_TestCase {
3031
use AssertClosedResource;
3132
use AssertEqualsSpecializations;
3233
use AssertFileEqualsSpecializations;
34+
use AssertIgnoringLineEndings;
3335
use AssertionRenames;
3436
use AssertIsType;
3537
use AssertObjectEquals;

src/TestCases/XTestCase.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use Yoast\PHPUnitPolyfills\Polyfills\AssertClosedResource;
88
use Yoast\PHPUnitPolyfills\Polyfills\AssertEqualsSpecializations;
99
use Yoast\PHPUnitPolyfills\Polyfills\AssertFileEqualsSpecializations;
10+
use Yoast\PHPUnitPolyfills\Polyfills\AssertIgnoringLineEndings;
1011
use Yoast\PHPUnitPolyfills\Polyfills\AssertionRenames;
1112
use Yoast\PHPUnitPolyfills\Polyfills\AssertIsType;
1213
use Yoast\PHPUnitPolyfills\Polyfills\AssertObjectEquals;
@@ -32,6 +33,7 @@ abstract class XTestCase extends PHPUnit_TestCase {
3233
use AssertClosedResource;
3334
use AssertEqualsSpecializations;
3435
use AssertFileEqualsSpecializations;
36+
use AssertIgnoringLineEndings;
3537
use AssertionRenames;
3638
use AssertIsType;
3739
use AssertObjectEquals;

0 commit comments

Comments
 (0)