testify icon indicating copy to clipboard operation
testify copied to clipboard

JSONEq returning error due to difference in ordering

Open NamanJain8 opened this issue 4 years ago • 9 comments

The following snippet returns error:

require.JSONEq(t, `[
		{"uid":"0x2","name@en":"pho\ton"},
		{"uid":"0x1","name":"pho\ton"}
		]`, `[
			{"uid":"0x1","name":"pho\ton"},
			{"uid":"0x2","name@en":"pho\ton"}
			]`
	)

Is there any work-around for this? This seems like a bug to me.

NamanJain8 avatar Nov 11 '20 11:11 NamanJain8

Json is unordered collection (see json.org)

roppa avatar Nov 17 '20 12:11 roppa

Anyone have a workaround for this? This would be a really nice feature.

gitstashpop avatar Mar 01 '21 18:03 gitstashpop

@yulicrunchy I've been working on a workaround for equating proto objects that have lists without a guaranteed order:

https://github.com/anz-bank/equals

it takes a generic interface, and converts it to json before doing any comparisons:

func TestStruct(t *testing.T) {
	type Bar struct {
		Arr []int
	}
	type Foo struct {
		A Bar
	}
	ElementsMatchRec(t,
		Foo{A: Bar{Arr: []int{1, 2, 3}}},
		Foo{A: Bar{Arr: []int{3, 2, 1}}})
}

joshcarp avatar Mar 02 '21 00:03 joshcarp

Json is unordered collection (see json.org)

In JSON, they take on these forms: An object is an unordered set ... An array is an ordered collection ...

from https://www.json.org/json-en.html

black-desk avatar Jul 20 '21 03:07 black-desk

@roppa @black-desk maybe I'm misunderstanding your messages, but exactly because objects are unordered, OPs test should pass.

fugkco avatar May 26 '22 15:05 fugkco

@roppa @black-desk maybe I'm misunderstanding your messages, but exactly because objects are unordered, OPs test should pass.

The OP's JSON blobs are both arrays, which are ordered, and the elements are in different orders, this is correctly failing.

I don't know why we're mentioning that JSON objects are unordered, it's not relevant to the OP's question. Perhaps we've all answered "that question" too many times and we missed that this is not an instance of "that question".

Anyone that would like to assert that two JSON arrays contain the same elements will need to first unmarshal them, like this:

func TestJSON(t *testing.T) {
	var expected, actual []interface{}
	require.NoError(t, json.Unmarshal([]byte(`[
		{"uid":"0x2","name@en":"pho\ton"},
		{"uid":"0x1","name":"pho\ton"}
		]`), &expected))
	require.NoError(t, json.Unmarshal([]byte(`[
		{"uid":"0x1","name":"pho\ton"},
		{"uid":"0x2","name@en":"pho\ton"}
		]`), &actual))
	require.ElementsMatch(t, expected, actual)
}

This is not a bug.

brackendawson avatar May 27 '22 10:05 brackendawson

Pardon me, for some reason I thought the arrays in OPs post was indeed ordered. But yes, you're right. OPs test should fail.

fugkco avatar Jun 17 '22 16:06 fugkco

String everything back to the normal

Edward601 avatar Jun 18 '22 00:06 Edward601

I don't want anything to fail

Edward601 avatar Jun 18 '22 14:06 Edward601

at least provide an option to ignore orders..

goyzhang avatar Sep 08 '23 02:09 goyzhang

I don't want anything to fail

You and me both, buddy.

at least provide an option to ignore orders..

What would you call it? assert.JSONElementsMatch I'd say no because ElementsMatch can only be called on slices and arrays. assert.JSONEqExeptWithArraysInAnyOrder I'd say no because it's deliberately silly.

I did provide a sane example. I don't think this issue warrants any change. If you can describe a good change that would address this need then comment and I'll re-open.

brackendawson avatar Feb 01 '24 00:02 brackendawson