diff --git a/assert/assertions.go b/assert/assertions.go index 44b854da6..c5619f636 100644 --- a/assert/assertions.go +++ b/assert/assertions.go @@ -174,6 +174,17 @@ func ObjectsAreEqualValues(expected, actual interface{}) bool { expectedType := expectedValue.Type() actualType := actualValue.Type() + + if expectedType.Kind() == actualType.Kind() { + // Test when object type is array/slice/map + switch actualType.Kind() { + case reflect.Array, reflect.Slice: + return listsAreEqualValues(expected, actual) + case reflect.Map: + return mapsAreEqualValues(expected, actual) + } + } + if !expectedType.ConvertibleTo(actualType) { return false } @@ -202,6 +213,68 @@ func isNumericType(t reflect.Type) bool { return t.Kind() >= reflect.Int && t.Kind() <= reflect.Complex128 } +// listsAreEqualValues gets whether two lists(arrays, slices) are equal, or if their +// values are equal. +// +// This function should only be used by ObjectsAreEqualValues. +func listsAreEqualValues(expected, actual interface{}) bool { + expectedValue := reflect.ValueOf(expected) + actualValue := reflect.ValueOf(actual) + + // Assure two objects have the same length + expectedLen, expectedOK := getLen(expected) + actualLen, actualOK := getLen(actual) + if !expectedOK || !actualOK { + return false + } + if expectedLen != actualLen { + return false + } + + // Iterate over elements and compare + for i := 0; i < expectedLen; i++ { + if !ObjectsAreEqualValues(expectedValue.Index(i).Interface(), actualValue.Index(i).Interface()) { + return false + } + } + return true +} + +// mapsAreEqualValues gets whether two maps are equal, or if their +// values are equal. +// +// This function should only be used by ObjectsAreEqualValues. +func mapsAreEqualValues(expected, actual interface{}) bool { + expectedValue := reflect.ValueOf(expected) + actualValue := reflect.ValueOf(actual) + + expectedKeys := expectedValue.MapKeys() + actualKeys := actualValue.MapKeys() + if len(expectedKeys) != len(actualKeys) { + return false + } + + // Key types should be convertible + expectedKeyType := expectedValue.Type().Key() + actualKeyType := actualValue.Type().Key() + if !expectedKeyType.ConvertibleTo(actualKeyType) { + return false + } + + for _, expectedKey := range expectedKeys { + actualKey := expectedKey.Convert(actualKeyType) + expectedElem := expectedValue.MapIndex(expectedKey) + actualElem := actualValue.MapIndex(actualKey) + if !actualElem.IsValid() { // if key doesn't exist + return false + } + if !ObjectsAreEqualValues(expectedElem.Interface(), actualElem.Interface()) { + return false + } + } + return true +} + /* CallerInfo is necessary because the assert functions use the testing object internally, causing it to print the file:line of the assert method, rather than where the problem actually occurred in calling code.*/ diff --git a/assert/assertions_test.go b/assert/assertions_test.go index e158688f2..228450731 100644 --- a/assert/assertions_test.go +++ b/assert/assertions_test.go @@ -113,6 +113,7 @@ func TestObjectsAreEqual(t *testing.T) { {123.5, 123.5, true}, {[]byte("Hello World"), []byte("Hello World"), true}, {nil, nil, true}, + {[]interface{}{1}, []interface{}{1}, true}, // cases that are expected not to be equal {map[int]int{5: 10}, map[int]int{10: 20}, false}, @@ -160,6 +161,9 @@ func TestObjectsAreEqualValues(t *testing.T) { {3.14, complex128(1e+100 + 1e+100i), false}, {complex128(1e+10 + 1e+10i), complex64(1e+10 + 1e+10i), true}, {complex64(1e+10 + 1e+10i), complex128(1e+10 + 1e+10i), true}, + {map[string]interface{}{"1": int32(1)}, map[string]interface{}{"1": int64(1)}, true}, + {map[int]interface{}{1: int32(1)}, map[int64]interface{}{1: int64(1)}, true}, + {map[interface{}]interface{}{1: int32(1)}, map[interface{}]interface{}{"1": int64(1)}, false}, } for _, c := range cases {