diff --git a/assert/assertions.go b/assert/assertions.go index 166f637..176e9dd 100644 --- a/assert/assertions.go +++ b/assert/assertions.go @@ -1955,8 +1955,13 @@ func diff(expected interface{}, actual interface{}) string { e = spewConfigStringerEnabled.Sdump(expected) a = spewConfigStringerEnabled.Sdump(actual) default: - e = spewConfig.Sdump(expected) - a = spewConfig.Sdump(actual) + if hasStringer(et) { + e = spewConfigStringerEnabled.Sdump(expected) + a = spewConfigStringerEnabled.Sdump(actual) + } else { + e = spewConfig.Sdump(expected) + a = spewConfig.Sdump(actual) + } } diff, _ := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{ @@ -1972,6 +1977,25 @@ func diff(expected interface{}, actual interface{}) string { return "\n\nDiff:\n" + diff } +var stringerType = reflect.TypeOf((*fmt.Stringer)(nil)).Elem() + +// hasStringer reports whether t, or the element type of a slice or array, +// implements fmt.Stringer. It lets diff render such values through the +// Stringer-enabled spew config, so a named string like peer.ID is shown by its +// String output instead of its raw bytes. This influences diff presentation +// only: equality is decided by ObjectsAreEqual and is unaffected, and the +// default spew config keeps DisableMethods for every other type. +func hasStringer(t reflect.Type) bool { + if t.Implements(stringerType) { + return true + } + switch t.Kind() { + case reflect.Slice, reflect.Array: + return t.Elem().Implements(stringerType) + } + return false +} + func isFunction(arg interface{}) bool { if arg == nil { return false diff --git a/assert/assertions_test.go b/assert/assertions_test.go index 11642e0..16b819c 100644 --- a/assert/assertions_test.go +++ b/assert/assertions_test.go @@ -2902,6 +2902,12 @@ func (d *diffTestingStruct) String() string { return d.A } +type diffTestingStringer string + +func (id diffTestingStringer) String() string { + return "stringer:" + string(id) +} + func TestDiff(t *testing.T) { t.Parallel() @@ -3036,6 +3042,24 @@ Diff: time.Date(2020, 9, 25, 0, 0, 0, 0, time.UTC), ) Equal(t, expected, actual) + + expected = ` + +Diff: +--- Expected ++++ Actual +@@ -2,3 +2,3 @@ + (assert.diffTestingStringer) (len=3) stringer:one, +- (assert.diffTestingStringer) (len=3) stringer:two ++ (assert.diffTestingStringer) (len=5) stringer:three + } +` + + actual = diff( + []diffTestingStringer{"one", "two"}, + []diffTestingStringer{"one", "three"}, + ) + Equal(t, expected, actual) } func TestTimeEqualityErrorFormatting(t *testing.T) {