diff options
Diffstat (limited to 'Godeps/_workspace/src/github.com/stretchr/testify/assert/assertions.go')
-rw-r--r-- | Godeps/_workspace/src/github.com/stretchr/testify/assert/assertions.go | 226 |
1 files changed, 176 insertions, 50 deletions
diff --git a/Godeps/_workspace/src/github.com/stretchr/testify/assert/assertions.go b/Godeps/_workspace/src/github.com/stretchr/testify/assert/assertions.go index 818cd7b0e..1935d18da 100644 --- a/Godeps/_workspace/src/github.com/stretchr/testify/assert/assertions.go +++ b/Godeps/_workspace/src/github.com/stretchr/testify/assert/assertions.go @@ -3,6 +3,7 @@ package assert import ( "bufio" "bytes" + "encoding/json" "fmt" "math" "reflect" @@ -10,6 +11,11 @@ import ( "runtime" "strings" "time" + "unicode" + "unicode/utf8" + + "github.com/davecgh/go-spew/spew" + "github.com/pmezard/go-difflib/difflib" ) // TestingT is an interface wrapper around *testing.T @@ -33,11 +39,7 @@ func ObjectsAreEqual(expected, actual interface{}) bool { return expected == actual } - if reflect.DeepEqual(expected, actual) { - return true - } - - return false + return reflect.DeepEqual(expected, actual) } @@ -49,12 +51,13 @@ func ObjectsAreEqualValues(expected, actual interface{}) bool { } actualType := reflect.TypeOf(actual) + if actualType == nil { + return false + } expectedValue := reflect.ValueOf(expected) - if expectedValue.Type().ConvertibleTo(actualType) { + if expectedValue.IsValid() && expectedValue.Type().ConvertibleTo(actualType) { // Attempt comparison after type conversion - if reflect.DeepEqual(actual, expectedValue.Convert(actualType).Interface()) { - return true - } + return reflect.DeepEqual(expectedValue.Convert(actualType).Interface(), actual) } return false @@ -64,28 +67,67 @@ func ObjectsAreEqualValues(expected, actual interface{}) bool { internally, causing it to print the file:line of the assert method, rather than where the problem actually occured in calling code.*/ -// CallerInfo returns a string containing the file and line number of the assert call -// that failed. -func CallerInfo() string { +// CallerInfo returns an array of strings containing the file and line number +// of each stack frame leading from the current test to the assert call that +// failed. +func CallerInfo() []string { + pc := uintptr(0) file := "" line := 0 ok := false + name := "" + callers := []string{} for i := 0; ; i++ { - _, file, line, ok = runtime.Caller(i) + pc, file, line, ok = runtime.Caller(i) if !ok { - return "" + return nil } + + // This is a huge edge case, but it will panic if this is the case, see #180 + if file == "<autogenerated>" { + break + } + parts := strings.Split(file, "/") dir := parts[len(parts)-2] file = parts[len(parts)-1] if (dir != "assert" && dir != "mock" && dir != "require") || file == "mock_test.go" { + callers = append(callers, fmt.Sprintf("%s:%d", file, line)) + } + + f := runtime.FuncForPC(pc) + if f == nil { + break + } + name = f.Name() + // Drop the package + segments := strings.Split(name, ".") + name = segments[len(segments)-1] + if isTest(name, "Test") || + isTest(name, "Benchmark") || + isTest(name, "Example") { break } } - return fmt.Sprintf("%s:%d", file, line) + return callers +} + +// Stolen from the `go test` tool. +// isTest tells whether name looks like a test (or benchmark, according to prefix). +// It is a Test (say) if there is a character after Test that is not a lower-case letter. +// We don't want TesticularCancer. +func isTest(name, prefix string) bool { + if !strings.HasPrefix(name, prefix) { + return false + } + if len(name) == len(prefix) { // "Test" is ok + return true + } + rune, _ := utf8.DecodeRuneInString(name[len(prefix):]) + return !unicode.IsLower(rune) } // getWhitespaceString returns a string that is long enough to overwrite the default @@ -144,19 +186,20 @@ func Fail(t TestingT, failureMessage string, msgAndArgs ...interface{}) bool { message := messageFromMsgAndArgs(msgAndArgs...) + errorTrace := strings.Join(CallerInfo(), "\n\r\t\t\t") if len(message) > 0 { - t.Errorf("\r%s\r\tLocation:\t%s\n"+ + t.Errorf("\r%s\r\tError Trace:\t%s\n"+ "\r\tError:%s\n"+ "\r\tMessages:\t%s\n\r", getWhitespaceString(), - CallerInfo(), + errorTrace, indentMessageLines(failureMessage, 2), message) } else { - t.Errorf("\r%s\r\tLocation:\t%s\n"+ + t.Errorf("\r%s\r\tError Trace:\t%s\n"+ "\r\tError:%s\n\r", getWhitespaceString(), - CallerInfo(), + errorTrace, indentMessageLines(failureMessage, 2)) } @@ -171,7 +214,7 @@ func Implements(t TestingT, interfaceObject interface{}, object interface{}, msg interfaceType := reflect.TypeOf(interfaceObject).Elem() if !reflect.TypeOf(object).Implements(interfaceType) { - return Fail(t, fmt.Sprintf("Object must implement %v", interfaceType), msgAndArgs...) + return Fail(t, fmt.Sprintf("%T must implement %v", object, interfaceType), msgAndArgs...) } return true @@ -196,8 +239,9 @@ func IsType(t TestingT, expectedType interface{}, object interface{}, msgAndArgs func Equal(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool { if !ObjectsAreEqual(expected, actual) { + diff := diff(expected, actual) return Fail(t, fmt.Sprintf("Not equal: %#v (expected)\n"+ - " != %#v (actual)", expected, actual), msgAndArgs...) + " != %#v (actual)%s", expected, actual, diff), msgAndArgs...) } return true @@ -232,7 +276,7 @@ func Exactly(t TestingT, expected, actual interface{}, msgAndArgs ...interface{} bType := reflect.TypeOf(actual) if aType != bType { - return Fail(t, "Types expected to match exactly", "%v != %v", aType, bType) + return Fail(t, fmt.Sprintf("Types expected to match exactly\n\r\t%v != %v", aType, bType), msgAndArgs...) } return Equal(t, expected, actual, msgAndArgs...) @@ -245,24 +289,10 @@ func Exactly(t TestingT, expected, actual interface{}, msgAndArgs ...interface{} // // Returns whether the assertion was successful (true) or not (false). func NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { - - success := true - - if object == nil { - success = false - } else { - value := reflect.ValueOf(object) - kind := value.Kind() - if kind >= reflect.Chan && kind <= reflect.Slice && value.IsNil() { - success = false - } - } - - if !success { - Fail(t, "Expected not to be nil.", msgAndArgs...) + if !isNil(object) { + return true } - - return success + return Fail(t, "Expected value not to be nil.", msgAndArgs...) } // isNil checks if a specified object is nil or not, without Failing. @@ -292,7 +322,7 @@ func Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { return Fail(t, fmt.Sprintf("Expected nil, but got: %#v", object), msgAndArgs...) } -var zeros = []interface{}{ +var numericZeros = []interface{}{ int(0), int8(0), int16(0), @@ -318,7 +348,7 @@ func isEmpty(object interface{}) bool { return true } - for _, v := range zeros { + for _, v := range numericZeros { if object == v { return true } @@ -335,6 +365,9 @@ func isEmpty(object interface{}) bool { } case reflect.Ptr: { + if objValue.IsNil() { + return true + } switch object.(type) { case *time.Time: return object.(*time.Time).IsZero() @@ -349,7 +382,7 @@ func isEmpty(object interface{}) bool { // Empty asserts that the specified object is empty. I.e. nil, "", false, 0 or either // a slice or a channel with len == 0. // -// assert.Empty(t, obj) +// assert.Empty(t, obj) // // Returns whether the assertion was successful (true) or not (false). func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { @@ -366,9 +399,9 @@ func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { // NotEmpty asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either // a slice or a channel with len == 0. // -// if assert.NotEmpty(t, obj) { -// assert.Equal(t, "two", obj[1]) -// } +// if assert.NotEmpty(t, obj) { +// assert.Equal(t, "two", obj[1]) +// } // // Returns whether the assertion was successful (true) or not (false). func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { @@ -450,7 +483,7 @@ func False(t TestingT, value bool, msgAndArgs ...interface{}) bool { func NotEqual(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool { if ObjectsAreEqual(expected, actual) { - return Fail(t, "Should not be equal", msgAndArgs...) + return Fail(t, fmt.Sprintf("Should not be: %#v\n", actual), msgAndArgs...) } return true @@ -476,6 +509,16 @@ func includeElement(list interface{}, element interface{}) (ok, found bool) { return true, strings.Contains(listValue.String(), elementValue.String()) } + if reflect.TypeOf(list).Kind() == reflect.Map { + mapKeys := listValue.MapKeys() + for i := 0; i < len(mapKeys); i++ { + if ObjectsAreEqual(mapKeys[i].Interface(), element) { + return true, true + } + } + return true, false + } + for i := 0; i < listValue.Len(); i++ { if ObjectsAreEqual(listValue.Index(i).Interface(), element) { return true, true @@ -485,11 +528,12 @@ func includeElement(list interface{}, element interface{}) (ok, found bool) { } -// Contains asserts that the specified string or list(array, slice...) contains the +// Contains asserts that the specified string, list(array, slice...) or map contains the // specified substring or element. // // assert.Contains(t, "Hello World", "World", "But 'Hello World' does contain 'World'") // assert.Contains(t, ["Hello", "World"], "World", "But ["Hello", "World"] does contain 'World'") +// assert.Contains(t, {"Hello": "World"}, "Hello", "But {'Hello': 'World'} does contain 'Hello'") // // Returns whether the assertion was successful (true) or not (false). func Contains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bool { @@ -506,11 +550,12 @@ func Contains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bo } -// NotContains asserts that the specified string or list(array, slice...) does NOT contain the +// NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the // specified substring or element. // // assert.NotContains(t, "Hello World", "Earth", "But 'Hello World' does NOT contain 'Earth'") // assert.NotContains(t, ["Hello", "World"], "Earth", "But ['Hello', 'World'] does NOT contain 'Earth'") +// assert.NotContains(t, {"Hello": "World"}, "Earth", "But {'Hello': 'World'} does NOT contain 'Earth'") // // Returns whether the assertion was successful (true) or not (false). func NotContains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bool { @@ -766,7 +811,7 @@ func NoError(t TestingT, err error, msgAndArgs ...interface{}) bool { return true } - return Fail(t, fmt.Sprintf("No error is expected but got %v", err), msgAndArgs...) + return Fail(t, fmt.Sprintf("Received unexpected error %q", err), msgAndArgs...) } // Error asserts that a function returned an error (i.e. not `nil`). @@ -800,7 +845,7 @@ func EqualError(t TestingT, theError error, errString string, msgAndArgs ...inte return false } s := "An error with value \"%s\" is expected but got \"%s\". %s" - return Equal(t, theError.Error(), errString, + return Equal(t, errString, theError.Error(), s, errString, theError.Error(), message) } @@ -851,3 +896,84 @@ func NotRegexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interf return !match } + +// Zero asserts that i is the zero value for its type and returns the truth. +func Zero(t TestingT, i interface{}, msgAndArgs ...interface{}) bool { + if i != nil && !reflect.DeepEqual(i, reflect.Zero(reflect.TypeOf(i)).Interface()) { + return Fail(t, fmt.Sprintf("Should be zero, but was %v", i), msgAndArgs...) + } + return true +} + +// NotZero asserts that i is not the zero value for its type and returns the truth. +func NotZero(t TestingT, i interface{}, msgAndArgs ...interface{}) bool { + if i == nil || reflect.DeepEqual(i, reflect.Zero(reflect.TypeOf(i)).Interface()) { + return Fail(t, fmt.Sprintf("Should not be zero, but was %v", i), msgAndArgs...) + } + return true +} + +// JSONEq asserts that two JSON strings are equivalent. +// +// assert.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) +// +// Returns whether the assertion was successful (true) or not (false). +func JSONEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) bool { + var expectedJSONAsInterface, actualJSONAsInterface interface{} + + if err := json.Unmarshal([]byte(expected), &expectedJSONAsInterface); err != nil { + return Fail(t, fmt.Sprintf("Expected value ('%s') is not valid json.\nJSON parsing error: '%s'", expected, err.Error()), msgAndArgs...) + } + + if err := json.Unmarshal([]byte(actual), &actualJSONAsInterface); err != nil { + return Fail(t, fmt.Sprintf("Input ('%s') needs to be valid json.\nJSON parsing error: '%s'", actual, err.Error()), 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 "" + } + + spew.Config.SortKeys = true + 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 +} |