Skip to content

Commit

Permalink
generalize Empty assertion
Browse files Browse the repository at this point in the history
Make `Empty` work against any struct and custom types, by replacing
explicit zero value comparisons with a `DeepEqual` comparison with
the type's `reflect.ZeroValue`.
  • Loading branch information
vincentcr authored and ernesto-jimenez committed Dec 30, 2017
1 parent 2aa2c17 commit 88a414d
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 45 deletions.
58 changes: 13 additions & 45 deletions assert/assertions.go
Original file line number Diff line number Diff line change
Expand Up @@ -414,64 +414,32 @@ func Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
return Fail(t, fmt.Sprintf("Expected nil, but got: %#v", object), msgAndArgs...)
}

var numericZeros = []interface{}{
int(0),
int8(0),
int16(0),
int32(0),
int64(0),
uint(0),
uint8(0),
uint16(0),
uint32(0),
uint64(0),
float32(0),
float64(0),
}

// isEmpty gets whether the specified object is considered empty or not.
func isEmpty(object interface{}) bool {

// get nil case out of the way
if object == nil {
return true
} else if object == "" {
return true
} else if object == false {
return true
}

for _, v := range numericZeros {
if object == v {
return true
}
}

objValue := reflect.ValueOf(object)

switch objValue.Kind() {
case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice, reflect.String:
{
return (objValue.Len() == 0)
}
case reflect.Struct:
switch object.(type) {
case time.Time:
return object.(time.Time).IsZero()
}
// collection types are empty when they have no element
case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice:
return objValue.Len() == 0
// pointers are empty if nil or if the value they point to is empty
case reflect.Ptr:
{
if objValue.IsNil() {
return true
}
switch object.(type) {
case *time.Time:
return object.(*time.Time).IsZero()
default:
return false
}
if objValue.IsNil() {
return true
}
deref := objValue.Elem().Interface()
return isEmpty(deref)
// for all other types, compare against the zero value
default:
zero := reflect.Zero(objValue.Type())
return reflect.DeepEqual(object, zero.Interface())
}
return false
}

// Empty asserts that the specified object is empty. I.e. nil, "", false, 0 or either
Expand Down
15 changes: 15 additions & 0 deletions assert/assertions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -806,6 +806,15 @@ func TestEmpty(t *testing.T) {
var tiNP time.Time
var s *string
var f *os.File
sP := &s
x := 1
xP := &x

type TString string
type TStruct struct {
x int
s []int
}

True(t, Empty(mockT, ""), "Empty string is empty")
True(t, Empty(mockT, nil), "Nil is empty")
Expand All @@ -817,13 +826,19 @@ func TestEmpty(t *testing.T) {
True(t, Empty(mockT, f), "Nil os.File pointer is empty")
True(t, Empty(mockT, tiP), "Nil time.Time pointer is empty")
True(t, Empty(mockT, tiNP), "time.Time is empty")
True(t, Empty(mockT, TStruct{}), "struct with zero values is empty")
True(t, Empty(mockT, TString("")), "empty aliased string is empty")
True(t, Empty(mockT, sP), "ptr to nil value is empty")

False(t, Empty(mockT, "something"), "Non Empty string is not empty")
False(t, Empty(mockT, errors.New("something")), "Non nil object is not empty")
False(t, Empty(mockT, []string{"something"}), "Non empty string array is not empty")
False(t, Empty(mockT, 1), "Non-zero int value is not empty")
False(t, Empty(mockT, true), "True value is not empty")
False(t, Empty(mockT, chWithValue), "Channel with values is not empty")
False(t, Empty(mockT, TStruct{x: 1}), "struct with initialized values is empty")
False(t, Empty(mockT, TString("abc")), "non-empty aliased string is empty")
False(t, Empty(mockT, xP), "ptr to non-nil value is not empty")
}

func TestNotEmpty(t *testing.T) {
Expand Down

0 comments on commit 88a414d

Please sign in to comment.