Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions assert/assertion_format.go
Original file line number Diff line number Diff line change
Expand Up @@ -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[<k>]:
// 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()
Expand Down
4 changes: 4 additions & 0 deletions assert/assertion_forward.go
Original file line number Diff line number Diff line change
Expand Up @@ -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[<k>]:
// 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()
Expand All @@ -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[<k>]:
// 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()
Expand Down
27 changes: 19 additions & 8 deletions assert/assertions.go
Original file line number Diff line number Diff line change
Expand Up @@ -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[<k>]:
// 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()
Expand Down Expand Up @@ -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...)
}
}

Expand Down
50 changes: 50 additions & 0 deletions assert/assertions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2442,6 +2442,56 @@ func TestInDeltaMapValues(t *testing.T) {
}
}

func TestInDeltaMapValues_ErrorIncludesKey(t *testing.T) {
t.Parallel()

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) {
t.Parallel()

Expand Down
4 changes: 4 additions & 0 deletions require/require.go
Original file line number Diff line number Diff line change
Expand Up @@ -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[<k>]:
// 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()
Expand All @@ -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[<k>]:
// 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()
Expand Down
4 changes: 4 additions & 0 deletions require/require_forward.go
Original file line number Diff line number Diff line change
Expand Up @@ -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[<k>]:
// 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()
Expand All @@ -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[<k>]:
// 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()
Expand Down