ext-ds icon indicating copy to clipboard operation
ext-ds copied to clipboard

PhpUnit always returns true when comparing Ds\Map

Open robincafolla opened this issue 5 years ago • 10 comments

php -v: PHP 7.2.9-1+ubuntu16.04.1+deb.sury.org+1

When PHPUnit\Framework\TestCase::assertEquals is used to compare two Maps it always returns true, regardless of contents.

Example:

use Ds\Map;
use PHPUnit\Framework\TestCase;

class MyTest extends TestCase

  public function testMaps():void {
    $mapA = new Map([
      1 => 'Foo',
      2 => 'Bar'
    ]);
    $mapB = new Map([
      3 => 'Cat',
      4 => 'Car'
    ]);

    $this->assertEquals($mapA, $mapB); // returns true
  }
}

Explanation:

This seems to happen because SebastianBergmann\Exporter::toArray uses (array) to cast objects for comparison. Since whenever you cast a Ds\Map to an array it becomes an empty array this means that assertEquals always returns true.

You might argue that this is a bug in PhpUnit, but I felt I should open it here first to see how you think a comparison should be done on Maps.

robincafolla avatar Sep 19 '18 16:09 robincafolla

This btw is my hacky fix; add a custom comparator which compares the json versions of the two maps.

https://gist.github.com/robincafolla/739e3253a7c9f4b4363d4d1aa39e2af5

But it won't work if you're using objects as keys.

robincafolla avatar Sep 19 '18 17:09 robincafolla

Since whenever you cast a Ds\Map to an array it becomes an empty array

This is the bug right here.

rtheunissen avatar Sep 19 '18 17:09 rtheunissen

I think this is also a poor choice to convert objects to arrays for comparison. Any object that overrides comparison (ie. ==) will fail for assertEquals

rtheunissen avatar Oct 08 '18 16:10 rtheunissen

I agree. I was originally going to open the issue on PHPUnit, but I didn't have a suggestion for them on how to improve it. I'll open an issue later for them to add support for Ds\Hashable.

robincafolla avatar Oct 16 '18 09:10 robincafolla

@robincafolla it's simple, they should use == for comparing objects.

rtheunissen avatar Oct 17 '18 17:10 rtheunissen

I'm going to open an issue on the comparator repo.

rtheunissen avatar Oct 17 '18 17:10 rtheunissen

See https://github.com/sebastianbergmann/comparator/pull/63

rtheunissen avatar Oct 17 '18 17:10 rtheunissen

This issue happens for every Ds\Collection, not only Ds\Map.

Since issue on the comparator repo was closed and I needed something better than the fix posted here, I created the following comparator: https://gist.github.com/jacek-foremski/999af8e488efb1316ccbd0e52ead58b3

@robincafolla 's comparator result (for a empty Vector vs Vector with two empty objects):

There was 1 failure:

1) xxx::xxx with data set #1 (Ds\Vector Object ())
Objects are not equivalent
--- Expected
+++ Actual
@@ @@
-[]
+[
+    {},
+    {}
+]

My comparator result:

There was 1 failure:

1) xxx::xxx with data set #1 (Ds\Vector Object ())
Failed asserting that two objects are equal.
--- Expected
+++ Actual
@@ @@
 Ds\Vector Object (
+    0 => App\Example Object (...)
+    1 => App\Example Object (...)
 )

Hopefully someone will find that useful.

jacek-foremski avatar Apr 04 '19 13:04 jacek-foremski

@jacek-foremski I think you should also check that both arguments are an instance of the same class.

rtheunissen avatar Apr 04 '19 13:04 rtheunissen

@rtheunissen This is done in the parent class (SebastianBergmann\Comparator\ObjectComparator)

jacek-foremski avatar Apr 04 '19 14:04 jacek-foremski