From c0690951ce59ba46a03d14185395ae2d6aed8873 Mon Sep 17 00:00:00 2001 From: gaurav0107 Date: Sun, 24 May 2026 23:49:22 +0530 Subject: [PATCH 1/2] assert: include map key in InDeltaMapValues error message When InDeltaMapValues fails for a particular map entry, the failure message did not say which key produced the mismatch. The output looked like: Error: Max difference between 3 and 4 allowed is 0.01, but difference was -1 leaving the user to bisect their map by hand. Inline the relevant InDelta math so the failure message can be prefixed with key[]:, producing: Error: key[a]: Max difference between 3 and 4 allowed is 0.01, but difference was -1 The behaviour for valid input is unchanged. Fixes #1254 --- assert/assertion_format.go | 2 ++ assert/assertion_forward.go | 4 ++++ assert/assertions.go | 27 +++++++++++++++++++-------- assert/assertions_test.go | 14 ++++++++++++++ require/require.go | 4 ++++ require/require_forward.go | 4 ++++ 6 files changed, 47 insertions(+), 8 deletions(-) diff --git a/assert/assertion_format.go b/assert/assertion_format.go index a19a89279..6078db869 100644 --- a/assert/assertion_format.go +++ b/assert/assertion_format.go @@ -366,6 +366,8 @@ func InDeltaf(t TestingT, expected interface{}, actual interface{}, delta float6 } // InDeltaMapValuesf is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys. +// When the assertion fails for a particular key, the failure message is prefixed with key[]: +// so the offending entry can be identified at a glance. func InDeltaMapValuesf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() diff --git a/assert/assertion_forward.go b/assert/assertion_forward.go index cd2a86061..7d38786fe 100644 --- a/assert/assertion_forward.go +++ b/assert/assertion_forward.go @@ -713,6 +713,8 @@ func (a *Assertions) InDelta(expected interface{}, actual interface{}, delta flo } // InDeltaMapValues is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys. +// When the assertion fails for a particular key, the failure message is prefixed with key[]: +// so the offending entry can be identified at a glance. func (a *Assertions) InDeltaMapValues(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -721,6 +723,8 @@ func (a *Assertions) InDeltaMapValues(expected interface{}, actual interface{}, } // InDeltaMapValuesf is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys. +// When the assertion fails for a particular key, the failure message is prefixed with key[]: +// so the offending entry can be identified at a glance. func (a *Assertions) InDeltaMapValuesf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() diff --git a/assert/assertions.go b/assert/assertions.go index 1419e4776..aa5551c27 100644 --- a/assert/assertions.go +++ b/assert/assertions.go @@ -1508,6 +1508,8 @@ func InDeltaSlice(t TestingT, expected, actual interface{}, delta float64, msgAn } // InDeltaMapValues is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys. +// When the assertion fails for a particular key, the failure message is prefixed with key[]: +// so the offending entry can be identified at a glance. func InDeltaMapValues(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -1537,14 +1539,23 @@ func InDeltaMapValues(t TestingT, expected, actual interface{}, delta float64, m return Fail(t, fmt.Sprintf("missing key %q in actual map", k), msgAndArgs...) } - if !InDelta( - t, - ev.Interface(), - av.Interface(), - delta, - msgAndArgs..., - ) { - return false + af, aok := toFloat(ev.Interface()) + bf, bok := toFloat(av.Interface()) + if !aok || !bok { + return Fail(t, fmt.Sprintf("key[%v]: Parameters must be numerical", k), msgAndArgs...) + } + if math.IsNaN(af) && math.IsNaN(bf) { + continue + } + if math.IsNaN(af) { + return Fail(t, fmt.Sprintf("key[%v]: Expected must not be NaN", k), msgAndArgs...) + } + if math.IsNaN(bf) { + return Fail(t, fmt.Sprintf("key[%v]: Expected %v with delta %v, but was NaN", k, ev.Interface(), delta), msgAndArgs...) + } + dt := af - bf + if dt < -delta || dt > delta { + return Fail(t, fmt.Sprintf("key[%v]: Max difference between %v and %v allowed is %v, but difference was %v", k, ev.Interface(), av.Interface(), delta, dt), msgAndArgs...) } } diff --git a/assert/assertions_test.go b/assert/assertions_test.go index 11642e096..a8477499b 100644 --- a/assert/assertions_test.go +++ b/assert/assertions_test.go @@ -2442,6 +2442,20 @@ func TestInDeltaMapValues(t *testing.T) { } } +func TestInDeltaMapValues_ErrorIncludesKey(t *testing.T) { + t.Parallel() + + mockT := &mockTestingT{} + expected := map[string]int{"a": 3, "b": 1} + actual := map[string]int{"a": 4, "b": 1} + + False(t, InDeltaMapValues(mockT, expected, actual, 0.01), + "InDeltaMapValues should fail when value at key a exceeds delta") + True(t, mockT.Failed(), "mockT should have recorded a failure") + Contains(t, mockT.errorString(), "key[a]:", + "failure message should be prefixed with the offending map key") +} + func TestInEpsilon(t *testing.T) { t.Parallel() diff --git a/require/require.go b/require/require.go index 652871f2e..4a22263f7 100644 --- a/require/require.go +++ b/require/require.go @@ -867,6 +867,8 @@ func InDelta(t TestingT, expected interface{}, actual interface{}, delta float64 } // InDeltaMapValues is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys. +// When the assertion fails for a particular key, the failure message is prefixed with key[]: +// so the offending entry can be identified at a glance. func InDeltaMapValues(t TestingT, expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -878,6 +880,8 @@ func InDeltaMapValues(t TestingT, expected interface{}, actual interface{}, delt } // InDeltaMapValuesf is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys. +// When the assertion fails for a particular key, the failure message is prefixed with key[]: +// so the offending entry can be identified at a glance. func InDeltaMapValuesf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() diff --git a/require/require_forward.go b/require/require_forward.go index edac147ef..861d76380 100644 --- a/require/require_forward.go +++ b/require/require_forward.go @@ -690,6 +690,8 @@ func (a *Assertions) InDelta(expected interface{}, actual interface{}, delta flo } // InDeltaMapValues is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys. +// When the assertion fails for a particular key, the failure message is prefixed with key[]: +// so the offending entry can be identified at a glance. func (a *Assertions) InDeltaMapValues(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -698,6 +700,8 @@ func (a *Assertions) InDeltaMapValues(expected interface{}, actual interface{}, } // InDeltaMapValuesf is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys. +// When the assertion fails for a particular key, the failure message is prefixed with key[]: +// so the offending entry can be identified at a glance. func (a *Assertions) InDeltaMapValuesf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() From 4faad33f1de3e19a4f12386e795dbf90fd42d405 Mon Sep 17 00:00:00 2001 From: gaurav0107 Date: Sun, 24 May 2026 23:53:08 +0530 Subject: [PATCH 2/2] assert: extend InDeltaMapValues key-in-error coverage Replace the single-case test with a table covering: - string-keyed map with int values - int-keyed map with float values - non-numerical value at a key (Parameters must be numerical) - NaN actual value This pins the new key[]: prefix across the four message branches introduced for #1254. --- assert/assertions_test.go | 54 ++++++++++++++++++++++++++++++++------- 1 file changed, 45 insertions(+), 9 deletions(-) diff --git a/assert/assertions_test.go b/assert/assertions_test.go index a8477499b..a983c1307 100644 --- a/assert/assertions_test.go +++ b/assert/assertions_test.go @@ -2445,15 +2445,51 @@ func TestInDeltaMapValues(t *testing.T) { func TestInDeltaMapValues_ErrorIncludesKey(t *testing.T) { t.Parallel() - mockT := &mockTestingT{} - expected := map[string]int{"a": 3, "b": 1} - actual := map[string]int{"a": 4, "b": 1} - - False(t, InDeltaMapValues(mockT, expected, actual, 0.01), - "InDeltaMapValues should fail when value at key a exceeds delta") - True(t, mockT.Failed(), "mockT should have recorded a failure") - Contains(t, mockT.errorString(), "key[a]:", - "failure message should be prefixed with the offending map key") + for _, tc := range []struct { + title string + expected interface{} + actual interface{} + delta float64 + wantSub string + }{ + { + title: "delta exceeded on string key", + expected: map[string]int{"a": 3, "b": 1}, + actual: map[string]int{"a": 4, "b": 1}, + delta: 0.01, + wantSub: "key[a]:", + }, + { + title: "delta exceeded on int key", + expected: map[int]float64{1: 1.0, 2: 2.0}, + actual: map[int]float64{1: 1.0, 2: 5.0}, + delta: 0.1, + wantSub: "key[2]:", + }, + { + title: "non-numerical value at key", + expected: map[string]interface{}{"a": "not-a-number"}, + actual: map[string]interface{}{"a": "still-not"}, + delta: 0.1, + wantSub: "key[a]: Parameters must be numerical", + }, + { + title: "actual is NaN", + expected: map[string]float64{"x": 1.0}, + actual: map[string]float64{"x": math.NaN()}, + delta: 0.1, + wantSub: "key[x]:", + }, + } { + t.Run(tc.title, func(t *testing.T) { + mockT := new(mockTestingT) + False(t, InDeltaMapValues(mockT, tc.expected, tc.actual, tc.delta), + "InDeltaMapValues should fail for %s", tc.title) + True(t, mockT.Failed(), "mockT should have recorded a failure") + Contains(t, mockT.errorString(), tc.wantSub, + "failure message should mention the offending map key") + }) + } } func TestInEpsilon(t *testing.T) {