Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve ApiTestAssertionsTrait::assertJsonEquals with assertEquals insteads of assertEqualsCanonicalizing #5751

Closed
DaedalusDev opened this issue Aug 16, 2023 · 3 comments
Labels

Comments

@DaedalusDev
Copy link

Description

Dear ApiPlatform,

this issue is a development tools improvement to make functionnal tests easier and more effective.

I suggest to replace this code :

static::assertEqualsCanonicalizing($json, self::getHttpResponse()->toArray(false), $message);

With :

        static::assertEqualsCanonicalizing($json, self::getHttpResponse()->toArray(false), $message);

Why ?

assertEqualsCanonicalizing can produce unexpected results

According to PhpUnit's doc, by canonicalizing comparison, keys are ignored and will produce non expected results.

Example

<?php

namespace App\Tests\Api;

use ApiPlatform\Symfony\Bundle\Test\ApiTestCase;

class CanolicalizingTest extends ApiTestCase
{
    public function testCanonicalizing(): void
    {
        static::assertEqualsCanonicalizing(
            [
                'a' => 5,
                'b' => 10,
            ],
            [
                'c' => 5,
                'd' => 10,
            ],
            'assertEqualsCanonicalizing :-(',
        );
        static::assertEquals(
            [
                'a' => 5,
                'b' => 10,
            ],
            [
                'c' => 5,
                'd' => 10,
            ],
            'assertEquals :-(',
        );
    }
}

This exemple with produce :

assertEquals :-(
Failed asserting that two arrays are equal.

Object are supposed be an unordered collection of zero or more name/value pairs

According https://www.rfc-editor.org/rfc/rfc7159.html :

An object is an unordered collection of zero or more name/value
pairs, where a name is a string and a value is a string, number,
boolean, null, object, or array.

So, i think order of properties won't be used to assert a result. That mean this changed won't produce regression for existing projects (or will improve tests with previously false positive passing tests 😝).

Reference

This issues refer to another issue from api-platform/api-platform api-platform/api-platform#1372

Thanks for your great work.

@dunglas
Copy link
Member

dunglas commented Aug 17, 2023

JSON objects aren't ordered but PHP arrays are. To prevent false positives we will have to order the keys of associative array keys.

A better fix would be to correct the underlying PHPUnit bug: sebastianbergmann/phpunit#5019

@DaedalusDev
Copy link
Author

DaedalusDev commented Aug 17, 2023

JSON objects aren't ordered but PHP arrays are. To prevent false positives we will have to order the keys of associative array keys.

A better fix would be to correct the underlying PHPUnit bug: sebastianbergmann/phpunit#5019

Sure ! But assertEquals compare elements recurcively as key paired value, so if i don't say a mistake, order is "not implicitly" compared, but value would not match.

Exemple :

<?php

namespace App\Tests\Api;

use ApiPlatform\Symfony\Bundle\Test\ApiTestCase;

/**
 * @internal
 *
 * @coversNothing
 */
class CanolicalizingTest extends ApiTestCase
{
    public function testAssertEquals(): void
    {

        static::assertEquals(
            [
                'a' => 5,
                'b' => 10,
            ],
            [
                'b' => 10,
                'a' => 5,
            ],
            'It work',
        );
        static::assertEquals(
            [
                5,
                10,
            ],
            [
                10,
                5,
            ],
            'assertEquals :-(',
        );
    }
}

Result :

assertEquals :-(
Failed asserting that two arrays are equal.
<Click to see difference>

image

This exemple will also fail for deep arrays :

// [..]
        static::assertEquals(
            [
                [
                    'id' => 1,
                ],
                [
                    'id' => 2,
                ],
            ],
            [
                [
                    'id' => 2,
                ],
                [
                    'id' => 1,
                ],
            ],
            'assertEquals :-(',
        );
// [..]

image

@stale
Copy link

stale bot commented Oct 16, 2023

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the stale label Oct 16, 2023
@stale stale bot closed this as completed Oct 24, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants