From e787d6aa9dbf0bf89f2f166dc59a2f68b530d17f Mon Sep 17 00:00:00 2001 From: OMOTO Kenji Date: Thu, 17 Jul 2014 18:18:41 +0900 Subject: [PATCH] Add Len() --- assert/assertions.go | 30 +++++++++++ assert/assertions_test.go | 84 +++++++++++++++++++++++++++++++ assert/doc.go | 4 ++ assert/forward_assertions.go | 10 ++++ assert/forward_assertions_test.go | 40 +++++++++++++++ 5 files changed, 168 insertions(+) diff --git a/assert/assertions.go b/assert/assertions.go index cc05752..95dc675 100644 --- a/assert/assertions.go +++ b/assert/assertions.go @@ -324,6 +324,36 @@ func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { } +// getLen try to get length of object. +// return (false, 0) if impossible. +func getLen(x interface{}) (ok bool, length int) { + v := reflect.ValueOf(x) + defer func() { + if e := recover(); e != nil { + ok = false + } + }() + return true, v.Len() +} + +// Len asserts that the specified object has specific length. +// Len also fails if the object has a type that len() not accept. +// +// assert.Len(t, mySlice, 3, "The size of slice is not 3") +// +// Returns whether the assertion was successful (true) or not (false). +func Len(t TestingT, object interface{}, length int, msgAndArgs ...interface{}) bool { + ok, l := getLen(object) + if !ok { + return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", object), msgAndArgs...) + } + + if l != length { + return Fail(t, fmt.Sprintf("\"%s\" should have %d item(s), but have %d", object, length, l), msgAndArgs...) + } + return true +} + // True asserts that the specified value is true. // // assert.True(t, myBool, "myBool should be true") diff --git a/assert/assertions_test.go b/assert/assertions_test.go index ecb74e3..4f91c21 100644 --- a/assert/assertions_test.go +++ b/assert/assertions_test.go @@ -400,6 +400,90 @@ func TestNotEmpty(t *testing.T) { True(t, NotEmpty(mockT, chWithValue), "Channel with values is not empty") } +func Test_getLen(t *testing.T) { + falseCases := []interface{}{ + nil, + 0, + true, + false, + 'A', + struct{}{}, + } + for _, v := range falseCases { + ok, l := getLen(v) + False(t, ok, "Expected getLen fail to get length of %#v", v) + Equal(t, 0, l, "getLen should return 0 for %#v", v) + } + + ch := make(chan int, 5) + ch <- 1 + ch <- 2 + ch <- 3 + trueCases := []struct { + v interface{} + l int + }{ + {[]int{1, 2, 3}, 3}, + {[...]int{1, 2, 3}, 3}, + {"ABC", 3}, + {map[int]int{1: 2, 2: 4, 3: 6}, 3}, + {ch, 3}, + + {[]int{}, 0}, + {map[int]int{}, 0}, + {make(chan int), 0}, + + {[]int(nil), 0}, + {map[int]int(nil), 0}, + {(chan int)(nil), 0}, + } + + for _, c := range trueCases { + ok, l := getLen(c.v) + True(t, ok, "Expected getLen success to get length of %#v", c.v) + Equal(t, c.l, l) + } +} + +func TestLen(t *testing.T) { + mockT := new(testing.T) + + False(t, Len(mockT, nil, 0), "nil does not have length") + False(t, Len(mockT, 0, 0), "int does not have length") + False(t, Len(mockT, true, 0), "true does not have length") + False(t, Len(mockT, false, 0), "false does not have length") + False(t, Len(mockT, 'A', 0), "Rune does not have length") + False(t, Len(mockT, struct{}{}, 0), "Struct does not have length") + + ch := make(chan int, 5) + ch <- 1 + ch <- 2 + ch <- 3 + + cases := []struct { + v interface{} + l int + }{ + {[]int{1, 2, 3}, 3}, + {[...]int{1, 2, 3}, 3}, + {"ABC", 3}, + {map[int]int{1: 2, 2: 4, 3: 6}, 3}, + {ch, 3}, + + {[]int{}, 0}, + {map[int]int{}, 0}, + {make(chan int), 0}, + + {[]int(nil), 0}, + {map[int]int(nil), 0}, + {(chan int)(nil), 0}, + } + + for _, c := range cases { + True(t, Len(mockT, c.v, c.l), "%#v have %d items", c.v, c.l) + } +} + func TestWithinDuration(t *testing.T) { mockT := new(testing.T) diff --git a/assert/doc.go b/assert/doc.go index a660769..4c72f42 100644 --- a/assert/doc.go +++ b/assert/doc.go @@ -61,6 +61,8 @@ // // assert.NotEmpty(t, actualObject [, message [, format-args]]) // +// assert.Len(t, actualObject, expectedLength, [, message [, format-args]]) +// // assert.Error(t, errorObject [, message [, format-args]]) // // assert.NoError(t, errorObject [, message [, format-args]]) @@ -112,6 +114,8 @@ // // assert.NotEmpty(actualObject [, message [, format-args]]) // +// assert.Len(actualObject, expectedLength, [, message [, format-args]]) +// // assert.Error(errorObject [, message [, format-args]]) // // assert.NoError(errorObject [, message [, format-args]]) diff --git a/assert/forward_assertions.go b/assert/forward_assertions.go index 0b77aaf..7c2eea7 100644 --- a/assert/forward_assertions.go +++ b/assert/forward_assertions.go @@ -87,6 +87,16 @@ func (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interface{}) boo return NotEmpty(a.t, object, msgAndArgs...) } +// Len asserts that the specified object has specific length. +// Len also fails if the object has a type that len() not accept. +// +// assert.Len(mySlice, 3, "The size of slice is not 3") +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) Len(object interface{}, length int, msgAndArgs ...interface{}) bool { + return Len(a.t, object, length, msgAndArgs...) +} + // True asserts that the specified value is true. // // assert.True(myBool, "myBool should be true") diff --git a/assert/forward_assertions_test.go b/assert/forward_assertions_test.go index 291b2ec..7982b07 100644 --- a/assert/forward_assertions_test.go +++ b/assert/forward_assertions_test.go @@ -320,6 +320,46 @@ func TestNotEmptyWrapper(t *testing.T) { } +func TestLenWrapper(t *testing.T) { + assert := New(t) + mockAssert := New(new(testing.T)) + + assert.False(mockAssert.Len(nil, 0), "nil does not have length") + assert.False(mockAssert.Len(0, 0), "int does not have length") + assert.False(mockAssert.Len(true, 0), "true does not have length") + assert.False(mockAssert.Len(false, 0), "false does not have length") + assert.False(mockAssert.Len('A', 0), "Rune does not have length") + assert.False(mockAssert.Len(struct{}{}, 0), "Struct does not have length") + + ch := make(chan int, 5) + ch <- 1 + ch <- 2 + ch <- 3 + + cases := []struct { + v interface{} + l int + }{ + {[]int{1, 2, 3}, 3}, + {[...]int{1, 2, 3}, 3}, + {"ABC", 3}, + {map[int]int{1: 2, 2: 4, 3: 6}, 3}, + {ch, 3}, + + {[]int{}, 0}, + {map[int]int{}, 0}, + {make(chan int), 0}, + + {[]int(nil), 0}, + {map[int]int(nil), 0}, + {(chan int)(nil), 0}, + } + + for _, c := range cases { + assert.True(mockAssert.Len(c.v, c.l), "%#v have %d items", c.v, c.l) + } +} + func TestWithinDurationWrapper(t *testing.T) { assert := New(t) mockAssert := New(new(testing.T))