Skip to content

Commit

Permalink
Merge pull request #109 from Yoast/feature/phpunit-10-add-assertignor…
Browse files Browse the repository at this point in the history
…inglineendingstrait

PHPUnit 10 | AssertIgnoringLineEndings trait: polyfill the Assert::assertStringEqualsStringIgnoringLineEndings() et al methods
  • Loading branch information
jrfnl committed Apr 1, 2023
2 parents 73bf346 + bf4f816 commit 53764b3
Show file tree
Hide file tree
Showing 9 changed files with 592 additions and 0 deletions.
52 changes: 52 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ Set of polyfills for changed PHPUnit functionality to allow for creating PHPUnit
- [PHPUnit support](#phpunit-support)
* [Using this library](#using-this-library)
- [Supported ways of calling the assertions](#supported-ways-of-calling-the-assertions)
- [Use with PHPUnit < 7.5.0](#use-with-phpunit--750)
* [Features](#features)
- [Polyfill traits](#polyfill-traits)
- [Helper traits](#helper-traits)
Expand Down Expand Up @@ -147,6 +148,45 @@ For the polyfills to work, a test class is **required** to be a (grand-)child of

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

### Use with PHPUnit < 7.5.0

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.

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.

You will need to make sure to `use` any additional traits needed for the polyfills to work.

| PHPUnit | When `use`-ing this trait | You also need to `use` this trait |
|-----------|-----------------------------|-----------------------------------|
| 5.7 < 7.5 | `AssertIgnoringLineEndings` | `AssertStringContains` |

_**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.**_

Code example for a test using the `AssertIgnoringLineEndings` trait, which needs to be able to run on PHPUnit 5.7:
```php
<?php

namespace Vendor\YourPackage\Tests;

use PHPUnit\Framework\TestCase;
use Yoast\PHPUnitPolyfills\Polyfills\AssertIgnoringLineEndings;
use Yoast\PHPUnitPolyfills\Polyfills\AssertStringContains;

class FooTest extends TestCase
{
use AssertIgnoringLineEndings;
use AssertStringContains;

public function testSomething()
{
$this->assertStringContainsStringIgnoringLineEndings(
"something\nelse",
"this is something\r\nelse"
);
}
}
```


Features
--------
Expand Down Expand Up @@ -354,6 +394,18 @@ The `assertObjectEquals()` assertion was introduced in PHPUnit 9.4.0.

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

#### PHPUnit < 10.0.0: `Yoast\PHPUnitPolyfills\Polyfills\AssertIgnoringLineEndings`

Polyfills the following methods:
| | |
|-----------------------------------------------------------|-------------------------------------------------------------|
| [`Assert::assertStringEqualsStringIgnoringLineEndings()`] | [`Assert::assertStringContainsStringIgnoringLineEndings()`] |

These methods were introduced in PHPUnit 10.0.0.

[`Assert::assertStringEqualsStringIgnoringLineEndings()`]: https://docs.phpunit.de/en/main/assertions.html#assertstringequalsstringignoringlineendings
[`Assert::assertStringContainsStringIgnoringLineEndings()`]: https://docs.phpunit.de/en/main/assertions.html#assertstringcontainsstringignoringlineendings


### Helper traits

Expand Down
21 changes: 21 additions & 0 deletions phpunitpolyfills-autoload.php
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,10 @@ public static function load( $className ) {
self::loadAssertObjectEquals();
return true;

case 'Yoast\PHPUnitPolyfills\Polyfills\AssertIgnoringLineEndings':
self::loadAssertIgnoringLineEndings();
return true;

case 'Yoast\PHPUnitPolyfills\TestCases\TestCase':
self::loadTestCase();
return true;
Expand Down Expand Up @@ -289,6 +293,23 @@ public static function loadAssertObjectEquals() {
require_once __DIR__ . '/src/Polyfills/AssertObjectEquals_Empty.php';
}

/**
* Load the AssertIgnoringLineEndings polyfill or an empty trait with the same name
* if a PHPUnit version is used which already contains this functionality.
*
* @return void
*/
public static function loadAssertIgnoringLineEndings() {
if ( \method_exists( Assert::class, 'assertStringEqualsStringIgnoringLineEndings' ) === false ) {
// PHPUnit < 10.0.0.
require_once __DIR__ . '/src/Polyfills/AssertIgnoringLineEndings.php';
return;
}

// PHPUnit >= 10.0.0.
require_once __DIR__ . '/src/Polyfills/AssertIgnoringLineEndings_Empty.php';
}

/**
* Load the appropriate TestCase class based on the PHPUnit version being used.
*
Expand Down
130 changes: 130 additions & 0 deletions src/Polyfills/AssertIgnoringLineEndings.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
<?php

namespace Yoast\PHPUnitPolyfills\Polyfills;

use PHPUnit\SebastianBergmann\Exporter\Exporter as Exporter_In_Phar;
use SebastianBergmann\Exporter\Exporter;
use TypeError;

/**
* Polyfill the Assert::assertStringEqualsStringIgnoringLineEndings() and the
* Assert::assertStringContainsStringIgnoringLineEndings() methods.
*
* Introduced in PHPUnit 10.0.0.
*
* @link https://github.com/sebastianbergmann/phpunit/issues/4641
* @link https://github.com/sebastianbergmann/phpunit/pull/4670
* @link https://github.com/sebastianbergmann/phpunit/issues/4935
* @link https://github.com/sebastianbergmann/phpunit/pull/5279
*/
trait AssertIgnoringLineEndings {

/**
* Asserts that two strings are equal except for line endings.
*
* @param string $expected Expected value.
* @param string $actual The value to test.
* @param string $message Optional failure message to display.
*
* @return void
*
* @throws TypeError When any of the passed arguments do not meet the required type.
*/
final public static function assertStringEqualsStringIgnoringLineEndings( $expected, $actual, $message = '' ) {
/*
* Parameter input validation.
* In PHPUnit this is done via PHP native type declarations. Emulating this for the polyfill.
* Note: using `is_scalar()` instead of `is_string()` as test files may not be using strict_types.
*/
if ( \is_scalar( $expected ) === false ) {
throw new TypeError(
\sprintf(
'Argument 1 passed to assertStringEqualsStringIgnoringLineEndings() must be of type string, %s given',
\gettype( $expected )
)
);
}
if ( \is_scalar( $actual ) === false ) {
throw new TypeError(
\sprintf(
'Argument 2 passed to assertStringEqualsStringIgnoringLineEndings() must be of type string, %s given',
\gettype( $actual )
)
);
}


$expected = self::normalizeLineEndingsForIgnoringLineEndingsAssertions( (string) $expected );
$exporter = \class_exists( Exporter::class ) ? new Exporter() : new Exporter_In_Phar();
$msg = \sprintf(
'Failed asserting that %s is equal to "%s" ignoring line endings.',
$exporter->export( $actual ),
$expected
);

if ( $message !== '' ) {
$msg = $message . \PHP_EOL . $msg;
}

$actual = self::normalizeLineEndingsForIgnoringLineEndingsAssertions( (string) $actual );

static::assertSame( $expected, $actual, $msg );
}

/**
* Asserts that two variables are equal (ignoring case).
*
* @param string $needle The string to search for.
* @param string $haystack The string to treat as the haystack.
* @param string $message Optional failure message to display.
*
* @return void
*
* @throws TypeError When any of the passed arguments do not meet the required type.
*/
final public static function assertStringContainsStringIgnoringLineEndings( $needle, $haystack, $message = '' ) {
/*
* Parameter input validation.
* In PHPUnit this is done via PHP native type declarations. Emulating this for the polyfill.
* Note: using `is_scalar()` instead of `is_string()` as test files may not be using strict_types.
*/
if ( \is_scalar( $needle ) === false ) {
throw new TypeError(
\sprintf(
'Argument 1 passed to assertStringContainsStringIgnoringLineEndings() must be of type string, %s given',
\gettype( $needle )
)
);
}
if ( \is_scalar( $haystack ) === false ) {
throw new TypeError(
\sprintf(
'Argument 2 passed to assertStringContainsStringIgnoringLineEndings() must be of type string, %s given',
\gettype( $haystack )
)
);
}

$needle = self::normalizeLineEndingsForIgnoringLineEndingsAssertions( (string) $needle );
$haystack = self::normalizeLineEndingsForIgnoringLineEndingsAssertions( (string) $haystack );

static::assertStringContainsString( $needle, $haystack, $message );
}

/**
* Normalize line endings.
*
* @param string $value The text to normalize.
*
* @return string
*/
private static function normalizeLineEndingsForIgnoringLineEndingsAssertions( $value ) {
return \strtr(
$value,
[
"\r\n" => "\n",
"\r" => "\n",
]
);
}
}
8 changes: 8 additions & 0 deletions src/Polyfills/AssertIgnoringLineEndings_Empty.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

namespace Yoast\PHPUnitPolyfills\Polyfills;

/**
* Empty trait for use with PHPUnit >= 10.0.0 in which this polyfill is not needed.
*/
trait AssertIgnoringLineEndings {}
2 changes: 2 additions & 0 deletions src/TestCases/TestCasePHPUnitGte8.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use Yoast\PHPUnitPolyfills\Helpers\AssertAttributeHelper;
use Yoast\PHPUnitPolyfills\Polyfills\AssertClosedResource;
use Yoast\PHPUnitPolyfills\Polyfills\AssertFileEqualsSpecializations;
use Yoast\PHPUnitPolyfills\Polyfills\AssertIgnoringLineEndings;
use Yoast\PHPUnitPolyfills\Polyfills\AssertionRenames;
use Yoast\PHPUnitPolyfills\Polyfills\AssertObjectEquals;
use Yoast\PHPUnitPolyfills\Polyfills\EqualToSpecializations;
Expand All @@ -25,6 +26,7 @@ abstract class TestCase extends PHPUnit_TestCase {
use AssertAttributeHelper;
use AssertClosedResource;
use AssertFileEqualsSpecializations;
use AssertIgnoringLineEndings;
use AssertionRenames;
use AssertObjectEquals;
use EqualToSpecializations;
Expand Down
2 changes: 2 additions & 0 deletions src/TestCases/TestCasePHPUnitLte7.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Yoast\PHPUnitPolyfills\Polyfills\AssertClosedResource;
use Yoast\PHPUnitPolyfills\Polyfills\AssertEqualsSpecializations;
use Yoast\PHPUnitPolyfills\Polyfills\AssertFileEqualsSpecializations;
use Yoast\PHPUnitPolyfills\Polyfills\AssertIgnoringLineEndings;
use Yoast\PHPUnitPolyfills\Polyfills\AssertionRenames;
use Yoast\PHPUnitPolyfills\Polyfills\AssertIsType;
use Yoast\PHPUnitPolyfills\Polyfills\AssertObjectEquals;
Expand All @@ -30,6 +31,7 @@ abstract class TestCase extends PHPUnit_TestCase {
use AssertClosedResource;
use AssertEqualsSpecializations;
use AssertFileEqualsSpecializations;
use AssertIgnoringLineEndings;
use AssertionRenames;
use AssertIsType;
use AssertObjectEquals;
Expand Down
2 changes: 2 additions & 0 deletions src/TestCases/XTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Yoast\PHPUnitPolyfills\Polyfills\AssertClosedResource;
use Yoast\PHPUnitPolyfills\Polyfills\AssertEqualsSpecializations;
use Yoast\PHPUnitPolyfills\Polyfills\AssertFileEqualsSpecializations;
use Yoast\PHPUnitPolyfills\Polyfills\AssertIgnoringLineEndings;
use Yoast\PHPUnitPolyfills\Polyfills\AssertionRenames;
use Yoast\PHPUnitPolyfills\Polyfills\AssertIsType;
use Yoast\PHPUnitPolyfills\Polyfills\AssertObjectEquals;
Expand All @@ -32,6 +33,7 @@ abstract class XTestCase extends PHPUnit_TestCase {
use AssertClosedResource;
use AssertEqualsSpecializations;
use AssertFileEqualsSpecializations;
use AssertIgnoringLineEndings;
use AssertionRenames;
use AssertIsType;
use AssertObjectEquals;
Expand Down
Loading

0 comments on commit 53764b3

Please sign in to comment.