mirror of https://github.com/stretchr/testify.git
generalize Empty assertion
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`.pull/523/merge
parent
2aa2c176b9
commit
88a414d072
|
@ -414,65 +414,33 @@ func Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
|
||||||
return Fail(t, fmt.Sprintf("Expected nil, but got: %#v", object), msgAndArgs...)
|
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.
|
// isEmpty gets whether the specified object is considered empty or not.
|
||||||
func isEmpty(object interface{}) bool {
|
func isEmpty(object interface{}) bool {
|
||||||
|
|
||||||
|
// get nil case out of the way
|
||||||
if object == nil {
|
if object == nil {
|
||||||
return true
|
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)
|
objValue := reflect.ValueOf(object)
|
||||||
|
|
||||||
switch objValue.Kind() {
|
switch objValue.Kind() {
|
||||||
case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice, reflect.String:
|
// collection types are empty when they have no element
|
||||||
{
|
case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice:
|
||||||
return (objValue.Len() == 0)
|
return objValue.Len() == 0
|
||||||
}
|
// pointers are empty if nil or if the value they point to is empty
|
||||||
case reflect.Struct:
|
|
||||||
switch object.(type) {
|
|
||||||
case time.Time:
|
|
||||||
return object.(time.Time).IsZero()
|
|
||||||
}
|
|
||||||
case reflect.Ptr:
|
case reflect.Ptr:
|
||||||
{
|
|
||||||
if objValue.IsNil() {
|
if objValue.IsNil() {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
switch object.(type) {
|
deref := objValue.Elem().Interface()
|
||||||
case *time.Time:
|
return isEmpty(deref)
|
||||||
return object.(*time.Time).IsZero()
|
// for all other types, compare against the zero value
|
||||||
default:
|
default:
|
||||||
return false
|
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
|
// Empty asserts that the specified object is empty. I.e. nil, "", false, 0 or either
|
||||||
// a slice or a channel with len == 0.
|
// a slice or a channel with len == 0.
|
||||||
|
|
|
@ -806,6 +806,15 @@ func TestEmpty(t *testing.T) {
|
||||||
var tiNP time.Time
|
var tiNP time.Time
|
||||||
var s *string
|
var s *string
|
||||||
var f *os.File
|
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, ""), "Empty string is empty")
|
||||||
True(t, Empty(mockT, nil), "Nil is empty")
|
True(t, Empty(mockT, nil), "Nil is empty")
|
||||||
|
@ -817,6 +826,9 @@ func TestEmpty(t *testing.T) {
|
||||||
True(t, Empty(mockT, f), "Nil os.File pointer is empty")
|
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, tiP), "Nil time.Time pointer is empty")
|
||||||
True(t, Empty(mockT, tiNP), "time.Time 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, "something"), "Non Empty string is not empty")
|
||||||
False(t, Empty(mockT, errors.New("something")), "Non nil object is not empty")
|
False(t, Empty(mockT, errors.New("something")), "Non nil object is not empty")
|
||||||
|
@ -824,6 +836,9 @@ func TestEmpty(t *testing.T) {
|
||||||
False(t, Empty(mockT, 1), "Non-zero int value 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, true), "True value is not empty")
|
||||||
False(t, Empty(mockT, chWithValue), "Channel with values 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) {
|
func TestNotEmpty(t *testing.T) {
|
||||||
|
|
Loading…
Reference in New Issue