phpunit
phpunit copied to clipboard
JSON assertions should treat objects as unordered
| Q | A |
|---|---|
| PHPUnit version | 9.5.4 |
| PHP version | 9.0.1 |
| Installation Method | Composer |
Summary
According to the JSON spec outlined at json.org, an object (dictionaries) "is an unordered set of name/value pairs". PHPUnit's JSON comparsion assertions (assertJsonStringEqualsJsonString and friends) appear to enforce an ordered set.
The internals suggest this is supposed to be handled already. I tried adding SORT_STRING as a flag to ksort here and it seemed to fix things, but I hardly did exhaustive testing.
Somewhat related to #4584, but more in the sense that it's impossible to maintain a native PHP array that 1:1 matches certain JSON due to numeric key conversion. Getting that all correct is tragically difficult.
Current behavior
good compare
Failed asserting that '{"a":{},"d":1,"b":[],"e":-1,"0":null,"c":"1","f":[1,2],"h":{"2":"2","1":"1","0":"0"},"g":[2,1]}' matches JSON string "{
"0": null,
"a": {},
"b": [],
"c": "1",
"d": 1,
"e": -1,
"f": [1,2],
"g": [2,1],
"h": {"0":"0","1":"1","2":"2"}
}".
--- Expected
+++ Actual
@@ @@
{
- "0": null,
"a": {},
"b": [],
- "c": "1",
"d": 1,
"e": -1,
+ "0": null,
+ "c": "1",
"f": [
1,
2
How to reproduce
public function testJson(): void
{
$expected = <<<'JSON'
{
"0": null,
"a": {},
"b": [],
"c": "1",
"d": 1,
"e": -1,
"f": [1,2],
"g": [2,1],
"h": {"0":"0","1":"1","2":"2"}
}
JSON;
$this->assertJsonStringEqualsJsonString(
$expected,
'{"a":{},"d":1,"b":[],"e":-1,"0":null,"c":"1","f":[1,2],"h":{"2":"2","1":"1","0":"0"},"g":[2,1]}',
'good compare',
);
try {
$this->assertJsonStringEqualsJsonString(
$expected,
'{"a":{},"d":1,"b":[],"e":-1,"0":null,"c":"1","f":[2,1],"h":{"2":"2","1":"1","0":"0"},"g":[2,1]}',
'bad!',
);
$this->fail('should fail: f is transposed');
} catch (\Throwable $e) {}
try {
$this->assertJsonStringEqualsJsonString(
$expected,
'{"a":{},"d":1,"b":[],"e":-1,"0":null,"c":"1","f":[1,2],"h":[0,1,2],"g":[2,1]}',
'bad!',
);
$this->fail('should fail: h changed from obj to array (intvals)');
} catch (\Throwable $e) {}
//#4584?
try {
$this->assertJsonStringEqualsJsonString(
$expected,
'{"a":{},"d":1,"b":[],"e":-1,"0":null,"c":"1","f":[1,2],"h":["0","1","2"],"g":[2,1]}',
'bad!',
);
$this->fail('should fail: h changed from obj to array (strings)');
} catch (\Throwable $e) {}
}
Expected behavior
Above test case passes.