Skip to content

Commit a3622b2

Browse files
PHPUnit 11.2.0 | AssertObjectNotEquals trait: polyfill the Assert::assertObjectNotEquals() method
PHPUnit 11.2.0 introduced the new `Assert::assertObjectNotEquals()` method. This commit: * Adds two traits with the same name. One to polyfill the method when not available in PHPUnit. The other to allow for `use`-ing the trait in PHPUnit versions in which the method is already natively available. * Logic to the custom autoloader which will load the correct trait depending on the PHPUnit version used. * Adds tests. As the polyfill contains logic to match the PHPUnit native implementation as closely as possible, while still being PHP and PHPUnit cross-version compatible, extensive unit tests have been added to ensure the behaviour of the polyfill matches that of the original function. Includes: * Adding information on the new polyfill to the README. * Adding the new polyfill to the existing `TestCases` classes. * Updating the class docs for the `InvalidComparisonMethodException` and the `ComparatorValidator` classes. Refs: * sebastianbergmann/phpunit#5811 * sebastianbergmann/phpunit@8e3b7c1 Co-authored-by: Sebastian Bergmann <[email protected]>
1 parent 6d1b945 commit a3622b2

11 files changed

+677
-3
lines changed

README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,17 @@ Refactoring tests which still use `Assert::assertArraySubset()` to use the new a
443443
[`Assert::assertArrayIsIdenticalToArrayOnlyConsideringListOfKeys()`]: https://docs.phpunit.de/en/main/assertions.html#assertarrayisidenticaltoarrayonlyconsideringlistofkeys
444444
[`Assert::assertArrayIsIdenticalToArrayIgnoringListOfKeys()`]: https://docs.phpunit.de/en/main/assertions.html#assertarrayisidenticaltoarrayignoringlistofkeys
445445

446+
#### PHPUnit < 11.2.0: `Yoast\PHPUnitPolyfills\Polyfills\AssertObjectNotEquals`
447+
448+
Polyfills the [`Assert::assertObjectNotEquals()`] method to verify two (value) objects are **_not_** considered equal.
449+
This is the sister-method to the PHPUnit 9.4+ `Assert::assertObjectEquals()` method.
450+
451+
This assertion expects an object to contain a comparator method in the object itself. This comparator method is subsequently called to verify the "equalness" of the objects.
452+
453+
The `assertObjectNotEquals()` assertion was introduced in PHPUnit 11.2.0.
454+
455+
[`Assert::assertObjectNotEquals()`]: https://docs.phpunit.de/en/main/assertions.html#assertobjectequals
456+
446457

447458
### TestCases
448459

phpunitpolyfills-autoload.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,10 @@ public static function load( $className ) {
8686
self::loadAssertArrayWithListKeys();
8787
return true;
8888

89+
case 'Yoast\PHPUnitPolyfills\Polyfills\AssertObjectNotEquals':
90+
self::loadAssertObjectNotEquals();
91+
return true;
92+
8993
case 'Yoast\PHPUnitPolyfills\TestCases\TestCase':
9094
self::loadTestCase();
9195
return true;
@@ -334,6 +338,23 @@ public static function loadAssertArrayWithListKeys() {
334338
require_once __DIR__ . '/src/Polyfills/AssertArrayWithListKeys_Empty.php';
335339
}
336340

341+
/**
342+
* Load the AssertObjectNotEquals polyfill or an empty trait with the same name
343+
* if a PHPUnit version is used which already contains this functionality.
344+
*
345+
* @return void
346+
*/
347+
public static function loadAssertObjectNotEquals() {
348+
if ( \method_exists( Assert::class, 'assertObjectNotEquals' ) === false ) {
349+
// PHPUnit < 11.2.0.
350+
require_once __DIR__ . '/src/Polyfills/AssertObjectNotEquals.php';
351+
return;
352+
}
353+
354+
// PHPUnit >= 11.2.0.
355+
require_once __DIR__ . '/src/Polyfills/AssertObjectNotEquals_Empty.php';
356+
}
357+
337358
/**
338359
* Load the appropriate TestCase class based on the PHPUnit version being used.
339360
*

src/Exceptions/InvalidComparisonMethodException.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@
55
use Exception;
66

77
/**
8-
* Exception used for all errors throw by the polyfill for the `assertObjectEquals()` assertion.
8+
* Exception used for all errors throw by the polyfill for the `assertObjectEquals()` and the `assertObjectNotEquals()` assertions.
99
*
1010
* PHPUnit natively throws a range of different exceptions.
11-
* The polyfill throws just one exception type with different messages.
11+
* The polyfills throw just one exception type with different messages.
1212
*/
1313
final class InvalidComparisonMethodException extends Exception {
1414

src/Helpers/ComparatorValidator.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
* This class is only intended for internal use by PHPUnit Polyfills and is not part of the public API.
1515
* This also means that it has no promise of backward compatibility.
1616
*
17-
* End-users should use the {@see \Yoast\PHPUnitPolyfills\Polyfills\AssertObjectEquals} trait instead.
17+
* End-users should use the {@see \Yoast\PHPUnitPolyfills\Polyfills\AssertObjectEquals} and/or the
18+
* {@see \Yoast\PHPUnitPolyfills\Polyfills\AssertObjectNotEquals} trait instead.
1819
* ---------------------------------------------------------------------------------------------
1920
*
2021
* @internal
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
<?php
2+
3+
namespace Yoast\PHPUnitPolyfills\Polyfills;
4+
5+
use TypeError;
6+
use Yoast\PHPUnitPolyfills\Exceptions\InvalidComparisonMethodException;
7+
use Yoast\PHPUnitPolyfills\Helpers\ComparatorValidator;
8+
9+
/**
10+
* Polyfill the Assert::assertObjectNotEquals() method.
11+
*
12+
* Introduced in PHPUnit 11.2.0.
13+
*
14+
* The polyfill implementation closely matches the PHPUnit native implementation with the exception
15+
* of the thrown exceptions.
16+
*
17+
* @link https://github.com/sebastianbergmann/phpunit/issues/5811
18+
* @link https://github.com/sebastianbergmann/phpunit/commit/8e3b7c18506312df0676f2e079c414cc56b49f69
19+
*/
20+
trait AssertObjectNotEquals {
21+
22+
/**
23+
* Asserts that two objects are considered _not_ equal based on a custom object comparison
24+
* using a comparator method in the target object.
25+
*
26+
* The custom comparator method is expected to have the following method
27+
* signature: `equals(self $other): bool` (or similar with a different method name).
28+
*
29+
* Basically, the assertion checks the following:
30+
* - A method with name $method must exist on the $actual object.
31+
* - The method must accept exactly one argument and this argument must be required.
32+
* - This parameter must have a classname-based declared type.
33+
* - The $expected object must be compatible with this declared type.
34+
* - The method must have a declared bool return type.
35+
*
36+
* @param object $expected Expected value.
37+
* @param object $actual The value to test.
38+
* @param string $method The name of the comparator method within the object.
39+
* @param string $message Optional failure message to display.
40+
*
41+
* @return void
42+
*
43+
* @throws TypeError When any of the passed arguments do not meet the required type.
44+
* @throws InvalidComparisonMethodException When the comparator method does not comply with the requirements.
45+
*/
46+
final public static function assertObjectNotEquals( $expected, $actual, $method = 'equals', $message = '' ) {
47+
/*
48+
* Parameter input validation.
49+
* In PHPUnit this is done via PHP native type declarations. Emulating this for the polyfill.
50+
*/
51+
if ( \is_object( $expected ) === false ) {
52+
throw new TypeError(
53+
\sprintf(
54+
'Argument 1 passed to assertObjectNotEquals() must be an object, %s given',
55+
\gettype( $expected )
56+
)
57+
);
58+
}
59+
60+
if ( \is_object( $actual ) === false ) {
61+
throw new TypeError(
62+
\sprintf(
63+
'Argument 2 passed to assertObjectNotEquals() must be an object, %s given',
64+
\gettype( $actual )
65+
)
66+
);
67+
}
68+
69+
if ( \is_scalar( $method ) === false ) {
70+
throw new TypeError(
71+
\sprintf(
72+
'Argument 3 passed to assertObjectNotEquals() must be of the type string, %s given',
73+
\gettype( $method )
74+
)
75+
);
76+
}
77+
else {
78+
$method = (string) $method;
79+
}
80+
81+
/*
82+
* Validate the comparator method requirements.
83+
*
84+
* If the method does not validate, an InvalidComparisonMethodException is thrown,
85+
* which will cause the test to error out.
86+
*/
87+
try {
88+
ComparatorValidator::isValid( $expected, $actual, $method );
89+
} catch ( InvalidComparisonMethodException $e ) {
90+
// Rethrow to ensure a stack trace shows the exception comes from this method, not the helper.
91+
throw $e;
92+
}
93+
94+
/*
95+
* Execute the comparator method.
96+
*/
97+
$result = $actual->{$method}( $expected );
98+
99+
$msg = \sprintf(
100+
'Failed asserting that two objects are not equal. The objects are equal according to %s::%s()',
101+
\get_class( $actual ),
102+
$method
103+
);
104+
105+
if ( $message !== '' ) {
106+
$msg = $message . \PHP_EOL . $msg;
107+
}
108+
109+
static::assertFalse( $result, $msg );
110+
}
111+
}
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 >= 11.2.0 in which this polyfill is not needed.
7+
*/
8+
trait AssertObjectNotEquals {}

src/TestCases/TestCasePHPUnitGte8.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use Yoast\PHPUnitPolyfills\Polyfills\AssertionRenames;
1111
use Yoast\PHPUnitPolyfills\Polyfills\AssertIsList;
1212
use Yoast\PHPUnitPolyfills\Polyfills\AssertObjectEquals;
13+
use Yoast\PHPUnitPolyfills\Polyfills\AssertObjectNotEquals;
1314
use Yoast\PHPUnitPolyfills\Polyfills\AssertObjectProperty;
1415
use Yoast\PHPUnitPolyfills\Polyfills\EqualToSpecializations;
1516
use Yoast\PHPUnitPolyfills\Polyfills\ExpectExceptionMessageMatches;
@@ -32,6 +33,7 @@ abstract class TestCase extends PHPUnit_TestCase {
3233
use AssertionRenames;
3334
use AssertIsList;
3435
use AssertObjectEquals;
36+
use AssertObjectNotEquals;
3537
use AssertObjectProperty;
3638
use EqualToSpecializations;
3739
use ExpectExceptionMessageMatches;

src/TestCases/TestCasePHPUnitLte7.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use Yoast\PHPUnitPolyfills\Polyfills\AssertIsList;
1313
use Yoast\PHPUnitPolyfills\Polyfills\AssertIsType;
1414
use Yoast\PHPUnitPolyfills\Polyfills\AssertObjectEquals;
15+
use Yoast\PHPUnitPolyfills\Polyfills\AssertObjectNotEquals;
1516
use Yoast\PHPUnitPolyfills\Polyfills\AssertObjectProperty;
1617
use Yoast\PHPUnitPolyfills\Polyfills\AssertStringContains;
1718
use Yoast\PHPUnitPolyfills\Polyfills\EqualToSpecializations;
@@ -37,6 +38,7 @@ abstract class TestCase extends PHPUnit_TestCase {
3738
use AssertIsList;
3839
use AssertIsType;
3940
use AssertObjectEquals;
41+
use AssertObjectNotEquals;
4042
use AssertObjectProperty;
4143
use AssertStringContains;
4244
use EqualToSpecializations;

src/TestCases/XTestCase.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use Yoast\PHPUnitPolyfills\Polyfills\AssertIsList;
1717
use Yoast\PHPUnitPolyfills\Polyfills\AssertIsType;
1818
use Yoast\PHPUnitPolyfills\Polyfills\AssertObjectEquals;
19+
use Yoast\PHPUnitPolyfills\Polyfills\AssertObjectNotEquals;
1920
use Yoast\PHPUnitPolyfills\Polyfills\AssertObjectProperty;
2021
use Yoast\PHPUnitPolyfills\Polyfills\AssertStringContains;
2122
use Yoast\PHPUnitPolyfills\Polyfills\EqualToSpecializations;
@@ -43,6 +44,7 @@ abstract class XTestCase extends PHPUnit_TestCase {
4344
use AssertIsList;
4445
use AssertIsType;
4546
use AssertObjectEquals;
47+
use AssertObjectNotEquals;
4648
use AssertObjectProperty;
4749
use AssertStringContains;
4850
use EqualToSpecializations;

0 commit comments

Comments
 (0)