This is my scenario, where there are 2 hashes that have been decoded from 2 JSON files.
I have 2 complex hash,
$hash1 = {k1=> { k11 => v1, k12 => v2}, k2 => { k21 => [v1, v2, v3] }}
$hash2 = {k1=> { k11 => v1, k12 => v2}, k2 => { k21 => [v3, v2, v1] }}
I want to compare these 2 hash for equality, and used Compare of Data::Compare and is_deeply of Test::More. Both do not ignore the order of the array.
I want to compare ignoring the order of array values of key 'k21'.
My App populates the array from 'keys %hash' which gives random order.
Tried 'ignore_hash_keys' of Data::Compare, but my hash sometimes can be complex and don't want to ignore.
Key 'k21' can also sometimes have array of hashes.
$hash3 = {k1=> { k11 => v1}, k2 => { k21 => [{v3 => v31}, {v2 => v22}] }}
How do I compare such complex hash by ignoring the array order.
You can use Test::Deep, which provides
cmp_deeply
. It's a lot more versatile than Test::More'sis_deeply
.The trick is the
bag()
function, which ignores the order of elements.Update: From your comment:
Some digging in the code of Test::Deep showed that it's possible to overwrite it. I looked at Test::Deep itself first, and found that there is a Test::Deep::Array, which deals with arrays. All of the packages that handle stuff inside of T::D have a
descend
method. So that's where we need to hook in.Sub::Override is great to temporarily override stuff, instead of messing with typeglobs.
Basically all we need to do is replace the call to
Test::Deep::arrayelementsonly
inTest::Deep::Array::descend
's final line with a call tobag()
. The rest is simply copied (indentation is mine). For small monkey-patching a copy of the existing code with a slight modification is usually the easiest approach.This will make the test pass.
Make sure to reset the override by undefining
$sub
or letting it go out of scope, or you might have some weird surprises if the rest of your test suite also uses Test::Deep.