92 lines
3.3 KiB
Bash
92 lines
3.3 KiB
Bash
# shellcheck shell=bash
|
|
|
|
# Asserts that two maps are equal, printing out differences if they are not.
|
|
# Does not short circuit on the first difference.
|
|
assertEqualMap() {
|
|
if (($# != 2)); then
|
|
nixErrorLog "expected two arguments!"
|
|
nixErrorLog "usage: assertEqualMap expectedMapRef actualMapRef"
|
|
exit 1
|
|
fi
|
|
|
|
local -nr expectedMapRef="$1"
|
|
local -nr actualMapRef="$2"
|
|
|
|
if ! isDeclaredMap "${!expectedMapRef}"; then
|
|
nixErrorLog "first argument expectedMapRef must be a reference to an associative array"
|
|
exit 1
|
|
fi
|
|
|
|
if ! isDeclaredMap "${!actualMapRef}"; then
|
|
nixErrorLog "second argument actualMapRef must be a reference to an associative array"
|
|
exit 1
|
|
fi
|
|
|
|
local -ir expectedLength=${#expectedMapRef[@]}
|
|
local -ir actualLength=${#actualMapRef[@]}
|
|
|
|
local -i hasDiff=0
|
|
|
|
if ((expectedLength != actualLength)); then
|
|
nixErrorLog "maps differ in length: expectedMap has length $expectedLength but actualMap has length $actualLength"
|
|
hasDiff=1
|
|
fi
|
|
|
|
local -a sortedExpectedKeys=()
|
|
getSortedMapKeys "${!expectedMapRef}" sortedExpectedKeys
|
|
|
|
local -a sortedActualKeys=()
|
|
getSortedMapKeys "${!actualMapRef}" sortedActualKeys
|
|
|
|
local -i expectedKeyIdx=0
|
|
local expectedKey
|
|
local expectedValue
|
|
local -i actualKeyIdx=0
|
|
local actualKey
|
|
local actualValue
|
|
|
|
# We iterate so long as at least one map has keys we've not considered.
|
|
while ((expectedKeyIdx < expectedLength || actualKeyIdx < actualLength)); do
|
|
# Update values for variables which are still in range/valid.
|
|
if ((expectedKeyIdx < expectedLength)); then
|
|
expectedKey="${sortedExpectedKeys["$expectedKeyIdx"]}"
|
|
expectedValue="${expectedMapRef["$expectedKey"]}"
|
|
fi
|
|
|
|
if ((actualKeyIdx < actualLength)); then
|
|
actualKey="${sortedActualKeys["$actualKeyIdx"]}"
|
|
actualValue="${actualMapRef["$actualKey"]}"
|
|
fi
|
|
|
|
# In the case actualKeyIdx is valid and expectedKey comes after actualKey or expectedKeyIdx is invalid, actualMap
|
|
# has an extra key relative to expectedMap.
|
|
# NOTE: In Bash, && and || have the same precedence, so use the fact they're left-associative to enforce groups.
|
|
if ((actualKeyIdx < actualLength)) && [[ $expectedKey > $actualKey ]] || ((expectedKeyIdx >= expectedLength)); then
|
|
nixErrorLog "maps differ at key ${actualKey@Q}: expectedMap has no such key but actualMap has value ${actualValue@Q}"
|
|
hasDiff=1
|
|
actualKeyIdx+=1
|
|
|
|
# In the case actualKeyIdx is invalid or expectedKey comes before actualKey, expectedMap has an extra key relative
|
|
# to actualMap.
|
|
# NOTE: By virtue of the previous condition being false, we know the negation is true. Namely, expectedKeyIdx is
|
|
# valid AND (actualKeyIdx is invalid OR expectedKey <= actualKey).
|
|
elif ((actualKeyIdx >= actualLength)) || [[ $expectedKey < $actualKey ]]; then
|
|
nixErrorLog "maps differ at key ${expectedKey@Q}: expectedMap has value ${expectedValue@Q} but actualMap has no such key"
|
|
hasDiff=1
|
|
expectedKeyIdx+=1
|
|
|
|
# In the case where both key indices are valid and the keys are equal.
|
|
else
|
|
if [[ $expectedValue != "$actualValue" ]]; then
|
|
nixErrorLog "maps differ at key ${expectedKey@Q}: expectedMap has value ${expectedValue@Q} but actualMap has value ${actualValue@Q}"
|
|
hasDiff=1
|
|
fi
|
|
|
|
expectedKeyIdx+=1
|
|
actualKeyIdx+=1
|
|
fi
|
|
done
|
|
|
|
((hasDiff)) && exit 1 || return 0
|
|
}
|