mirror of
https://github.com/stretchr/testify.git
synced 2025-05-31 11:42:44 +00:00
Fixes #229 - show diffs for structs/maps/arrays/slices when Equal fails
This commit is contained in:
parent
0d5a14c5a4
commit
33c4c93911
@ -13,6 +13,9 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
"unicode"
|
"unicode"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
|
||||||
|
"github.com/davecgh/go-spew/spew"
|
||||||
|
"github.com/pmezard/go-difflib/difflib"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestingT is an interface wrapper around *testing.T
|
// TestingT is an interface wrapper around *testing.T
|
||||||
@ -233,8 +236,9 @@ func IsType(t TestingT, expectedType interface{}, object interface{}, msgAndArgs
|
|||||||
func Equal(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
|
func Equal(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
|
||||||
if !ObjectsAreEqual(expected, actual) {
|
if !ObjectsAreEqual(expected, actual) {
|
||||||
|
diff := diff(expected, actual)
|
||||||
return Fail(t, fmt.Sprintf("Not equal: %#v (expected)\n"+
|
return Fail(t, fmt.Sprintf("Not equal: %#v (expected)\n"+
|
||||||
" != %#v (actual)", expected, actual), msgAndArgs...)
|
" != %#v (actual)%s", expected, actual, diff), msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
@ -921,3 +925,48 @@ func JSONEq(t TestingT, expected string, actual string, msgAndArgs ...interface{
|
|||||||
|
|
||||||
return Equal(t, expectedJSONAsInterface, actualJSONAsInterface, msgAndArgs...)
|
return Equal(t, expectedJSONAsInterface, actualJSONAsInterface, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func typeAndKind(v interface{}) (reflect.Type, reflect.Kind) {
|
||||||
|
t := reflect.TypeOf(v)
|
||||||
|
k := t.Kind()
|
||||||
|
|
||||||
|
if k == reflect.Ptr {
|
||||||
|
t = t.Elem()
|
||||||
|
k = t.Kind()
|
||||||
|
}
|
||||||
|
return t, k
|
||||||
|
}
|
||||||
|
|
||||||
|
// diff returns a diff of both values as long as both are of the same type and
|
||||||
|
// are a struct, map, slice or array. Otherwise it returns an empty string.
|
||||||
|
func diff(expected interface{}, actual interface{}) string {
|
||||||
|
if expected == nil || actual == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
et, ek := typeAndKind(expected)
|
||||||
|
at, _ := typeAndKind(actual)
|
||||||
|
|
||||||
|
if et != at {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if ek != reflect.Struct && ek != reflect.Map && ek != reflect.Slice && ek != reflect.Array {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
e := spew.Sdump(expected)
|
||||||
|
a := spew.Sdump(actual)
|
||||||
|
|
||||||
|
diff, _ := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{
|
||||||
|
A: difflib.SplitLines(e),
|
||||||
|
B: difflib.SplitLines(a),
|
||||||
|
FromFile: "Expected",
|
||||||
|
FromDate: "",
|
||||||
|
ToFile: "Actual",
|
||||||
|
ToDate: "",
|
||||||
|
Context: 1,
|
||||||
|
})
|
||||||
|
|
||||||
|
return "\n\nDiff:\n" + diff
|
||||||
|
}
|
||||||
|
@ -984,3 +984,77 @@ func TestJSONEq_ArraysOfDifferentOrder(t *testing.T) {
|
|||||||
mockT := new(testing.T)
|
mockT := new(testing.T)
|
||||||
False(t, JSONEq(mockT, `["foo", {"hello": "world", "nested": "hash"}]`, `[{ "hello": "world", "nested": "hash"}, "foo"]`))
|
False(t, JSONEq(mockT, `["foo", {"hello": "world", "nested": "hash"}]`, `[{ "hello": "world", "nested": "hash"}, "foo"]`))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDiff(t *testing.T) {
|
||||||
|
expected := `
|
||||||
|
|
||||||
|
Diff:
|
||||||
|
--- Expected
|
||||||
|
+++ Actual
|
||||||
|
@@ -1,3 +1,3 @@
|
||||||
|
(struct { foo string }) {
|
||||||
|
- foo: (string) (len=5) "hello"
|
||||||
|
+ foo: (string) (len=3) "bar"
|
||||||
|
}
|
||||||
|
`
|
||||||
|
actual := diff(
|
||||||
|
struct{ foo string }{"hello"},
|
||||||
|
struct{ foo string }{"bar"},
|
||||||
|
)
|
||||||
|
Equal(t, expected, actual)
|
||||||
|
|
||||||
|
expected = `
|
||||||
|
|
||||||
|
Diff:
|
||||||
|
--- Expected
|
||||||
|
+++ Actual
|
||||||
|
@@ -2,5 +2,5 @@
|
||||||
|
(int) 1,
|
||||||
|
- (int) 2,
|
||||||
|
(int) 3,
|
||||||
|
- (int) 4
|
||||||
|
+ (int) 5,
|
||||||
|
+ (int) 7
|
||||||
|
}
|
||||||
|
`
|
||||||
|
actual = diff(
|
||||||
|
[]int{1, 2, 3, 4},
|
||||||
|
[]int{1, 3, 5, 7},
|
||||||
|
)
|
||||||
|
Equal(t, expected, actual)
|
||||||
|
|
||||||
|
expected = `
|
||||||
|
|
||||||
|
Diff:
|
||||||
|
--- Expected
|
||||||
|
+++ Actual
|
||||||
|
@@ -2,4 +2,4 @@
|
||||||
|
(int) 1,
|
||||||
|
- (int) 2,
|
||||||
|
- (int) 3
|
||||||
|
+ (int) 3,
|
||||||
|
+ (int) 5
|
||||||
|
}
|
||||||
|
`
|
||||||
|
actual = diff(
|
||||||
|
[]int{1, 2, 3, 4}[0:3],
|
||||||
|
[]int{1, 3, 5, 7}[0:3],
|
||||||
|
)
|
||||||
|
Equal(t, expected, actual)
|
||||||
|
|
||||||
|
// output for maps cannot be equally tested since order is random
|
||||||
|
actual = diff(
|
||||||
|
map[string]int{"one": 1, "two": 2, "three": 3, "four": 4},
|
||||||
|
map[string]int{"one": 1, "three": 3, "five": 5, "seven": 7},
|
||||||
|
)
|
||||||
|
NotZero(t, len(actual))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDiffEmptyCases(t *testing.T) {
|
||||||
|
Equal(t, "", diff(nil, nil))
|
||||||
|
Equal(t, "", diff(struct{ foo string }{}, nil))
|
||||||
|
Equal(t, "", diff(nil, struct{ foo string }{}))
|
||||||
|
Equal(t, "", diff(1, 2))
|
||||||
|
Equal(t, "", diff(1, 2))
|
||||||
|
Equal(t, "", diff([]int{1}, []bool{true}))
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user