phpunit icon indicating copy to clipboard operation
phpunit copied to clipboard

assertEqualsCanonicalizing() produces confusing message when elements cannot be converted to string

Open kiler129 opened this issue 3 years ago • 2 comments

Q A
PHPUnit version 9.5.18
PHP version 8.1.2
Installation Method PHAR

Summary

When assertEqualsCanonicalizing() is utilized the assertion result display will crash when one of the array elements, which is presented in the diff, is not castable to string.

Current behavior

When test is run the testing framework crashes with, at-first confusing, error message:

1) FooTest::testFoo
Object of class stdClass could not be converted to int

How to reproduce

<?php declare(strict_types=1);
use PHPUnit\Framework\TestCase;

final class FooTest extends TestCase
{
    public function testFoo(): void
    {
       $data = [
            'one' => 123,
            'two' => new \stdClass(),
        ];

        $copy = $data;
        $copy['one'] = 1234;

        $this->assertEqualsCanonicalizing($data, $copy);
    }
}

Expected behavior

The diff should handle such cases properly and display e.g. object ID, similarly to how e.g. assertSame() does it:

1) FooTest::testFoo
Failed asserting that two arrays are identical.
--- Expected
+++ Actual
@@ @@
 Array &0 (
-    'one' => 123
+    'one' => 1234
     'two' => stdClass Object &000000000000000d0000000000000000 ()
 )

kiler129 avatar Mar 09 '22 07:03 kiler129

I can confirm this bug.

It seems to happen here: https://github.com/sebastianbergmann/comparator/blob/main/src/ArrayComparator.php#L56

It seems to happen when an array contains both objects and scalar values, which would be a common case for serialized objects.

This is a problem in cases where you want to compare a list of objects, but the order doesn't matter.

A potential solution could be to use usort() with a custom sorting function that handles cases like this. I would assume that if it handled objects compared to scalar values with simply saying that a scalar value is lower than an object and then compared other cases as per usual, then the problem would be solved.

A temporary fix in the case I've encountered is to "pre-serialize" the objects in the list before asserting.

thomasnordahl-dk avatar Oct 24 '22 13:10 thomasnordahl-dk