From 3bfb674961683373c06133bc4976a5a12e01c976 Mon Sep 17 00:00:00 2001 From: Jordan Olshevski Date: Wed, 6 Jul 2016 18:01:58 -0700 Subject: [PATCH 1/4] Print types in failed numeric equality assertions This addresses vague and misleading output when asserting on the equality of two values of differing numeric types. Example: assert.Equal(t, int64(123), int32(123)) Previously, the user would have received a vague message claiming that 123 != 123. Now the message will read "int64(123) != int32(123)". --- assert/assertions.go | 43 +++++++++++++++++++++++++++++++++++++-- assert/assertions_test.go | 14 +++++++++++++ 2 files changed, 55 insertions(+), 2 deletions(-) diff --git a/assert/assertions.go b/assert/assertions.go index 348d5f1..642f621 100644 --- a/assert/assertions.go +++ b/assert/assertions.go @@ -262,14 +262,53 @@ func Equal(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) if !ObjectsAreEqual(expected, actual) { diff := diff(expected, actual) - return Fail(t, fmt.Sprintf("Not equal: %#v (expected)\n"+ - " != %#v (actual)%s", expected, actual, diff), msgAndArgs...) + expected, actual = formatUnequalValues(expected, actual) + return Fail(t, fmt.Sprintf("Not equal: %v (expected)\n"+ + " != %v (actual)%s", expected, actual, diff), msgAndArgs...) } return true } +// formatUnequalValues takes two values of arbitrary types and returns string +// representations appropriate to be presented to the user. +// +// If the values are not of like type, the returned strings will be prefixed +// with the type name, and the value will be enclosed in parenthesis similar +// to a type conversion in the Go grammar. +func formatUnequalValues(expected, actual interface{}) (e string, a string) { + aType := reflect.TypeOf(expected) + bType := reflect.TypeOf(actual) + + if aType != bType && isNumericType(aType) && isNumericType(bType) { + return fmt.Sprintf("%v(%#v)", aType, expected), + fmt.Sprintf("%v(%#v)", bType, actual) + } + + return fmt.Sprintf("%#v", expected), + fmt.Sprintf("%#v", actual) +} + +var numericTypes = map[string]bool{ + "float32": true, + "float64": true, + "int": true, + "int8": true, + "int16": true, + "int32": true, + "int64": true, + "uint": true, + "uint8": true, + "uint16": true, + "uint32": true, + "uint64": true, +} + +func isNumericType(t reflect.Type) bool { + return numericTypes[t.String()] +} + // EqualValues asserts that two objects are equal or convertable to the same types // and equal. // diff --git a/assert/assertions_test.go b/assert/assertions_test.go index 12d8151..7318877 100644 --- a/assert/assertions_test.go +++ b/assert/assertions_test.go @@ -195,6 +195,20 @@ func TestEqual(t *testing.T) { } +func TestFormatUnequalValues(t *testing.T) { + expected, actual := formatUnequalValues("foo", "bar") + Equal(t, `"foo"`, expected, "value should not include type") + Equal(t, `"bar"`, actual, "value should not include type") + + expected, actual = formatUnequalValues(123, 123) + Equal(t, `123`, expected, "value should not include type") + Equal(t, `123`, actual, "value should not include type") + + expected, actual = formatUnequalValues(int64(123), int32(123)) + Equal(t, `int64(123)`, expected, "value should include type") + Equal(t, `int32(123)`, actual, "value should include type") +} + func TestNotNil(t *testing.T) { mockT := new(testing.T) From c48fed335158f0071ca6e1a7869d5675cd694e99 Mon Sep 17 00:00:00 2001 From: Jordan Olshevski Date: Sat, 24 Sep 2016 17:17:28 -0700 Subject: [PATCH 2/4] Use %s instead of %v when printing inequal values Since the values are already strings, there is no reason to use %v. --- assert/assertions.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/assert/assertions.go b/assert/assertions.go index 642f621..dac671e 100644 --- a/assert/assertions.go +++ b/assert/assertions.go @@ -263,8 +263,8 @@ func Equal(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) if !ObjectsAreEqual(expected, actual) { diff := diff(expected, actual) expected, actual = formatUnequalValues(expected, actual) - return Fail(t, fmt.Sprintf("Not equal: %v (expected)\n"+ - " != %v (actual)%s", expected, actual, diff), msgAndArgs...) + return Fail(t, fmt.Sprintf("Not equal: %s (expected)\n"+ + " != %s (actual)%s", expected, actual, diff), msgAndArgs...) } return true From a34cbb254a856d7a320c097b95e817195360153a Mon Sep 17 00:00:00 2001 From: Jordan Olshevski Date: Sat, 24 Sep 2016 17:19:22 -0700 Subject: [PATCH 3/4] Use switch statement instead of numericTypes map --- assert/assertions.go | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/assert/assertions.go b/assert/assertions.go index dac671e..df108ee 100644 --- a/assert/assertions.go +++ b/assert/assertions.go @@ -290,23 +290,17 @@ func formatUnequalValues(expected, actual interface{}) (e string, a string) { fmt.Sprintf("%#v", actual) } -var numericTypes = map[string]bool{ - "float32": true, - "float64": true, - "int": true, - "int8": true, - "int16": true, - "int32": true, - "int64": true, - "uint": true, - "uint8": true, - "uint16": true, - "uint32": true, - "uint64": true, -} - func isNumericType(t reflect.Type) bool { - return numericTypes[t.String()] + switch t.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return true + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return true + case reflect.Float32, reflect.Float64: + return true + } + + return false } // EqualValues asserts that two objects are equal or convertable to the same types From d2b5f588088d99984384e8d9fe9be9168a323a76 Mon Sep 17 00:00:00 2001 From: Jordan Olshevski Date: Sat, 24 Sep 2016 17:22:54 -0700 Subject: [PATCH 4/4] Add formatUnequalValues struct test coverage This expands the TestFormatUnequalValues test case to cover the behavior of the function when provided two struct type'd values. --- assert/assertions_test.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/assert/assertions_test.go b/assert/assertions_test.go index 7318877..09b861f 100644 --- a/assert/assertions_test.go +++ b/assert/assertions_test.go @@ -207,6 +207,14 @@ func TestFormatUnequalValues(t *testing.T) { expected, actual = formatUnequalValues(int64(123), int32(123)) Equal(t, `int64(123)`, expected, "value should include type") Equal(t, `int32(123)`, actual, "value should include type") + + type testStructType struct { + Val string + } + + expected, actual = formatUnequalValues(&testStructType{Val: "test"}, &testStructType{Val: "test"}) + Equal(t, `&assert.testStructType{Val:"test"}`, expected, "value should not include type annotation") + Equal(t, `&assert.testStructType{Val:"test"}`, actual, "value should not include type annotation") } func TestNotNil(t *testing.T) {