package assert
import (
"bytes"
"fmt"
"reflect"
"time"
)
type CompareType = compareResult
type compareResult int
const (
compareLess compareResult = iota - 1
compareEqual
compareGreater
)
var (
intType = reflect .TypeOf (int (1 ))
int8Type = reflect .TypeOf (int8 (1 ))
int16Type = reflect .TypeOf (int16 (1 ))
int32Type = reflect .TypeOf (int32 (1 ))
int64Type = reflect .TypeOf (int64 (1 ))
uintType = reflect .TypeOf (uint (1 ))
uint8Type = reflect .TypeOf (uint8 (1 ))
uint16Type = reflect .TypeOf (uint16 (1 ))
uint32Type = reflect .TypeOf (uint32 (1 ))
uint64Type = reflect .TypeOf (uint64 (1 ))
uintptrType = reflect .TypeOf (uintptr (1 ))
float32Type = reflect .TypeOf (float32 (1 ))
float64Type = reflect .TypeOf (float64 (1 ))
stringType = reflect .TypeOf ("" )
timeType = reflect .TypeOf (time .Time {})
bytesType = reflect .TypeOf ([]byte {})
)
func compare(obj1 , obj2 interface {}, kind reflect .Kind ) (compareResult , bool ) {
obj1Value := reflect .ValueOf (obj1 )
obj2Value := reflect .ValueOf (obj2 )
switch kind {
case reflect .Int :
{
intobj1 , ok := obj1 .(int )
if !ok {
intobj1 = obj1Value .Convert (intType ).Interface ().(int )
}
intobj2 , ok := obj2 .(int )
if !ok {
intobj2 = obj2Value .Convert (intType ).Interface ().(int )
}
if intobj1 > intobj2 {
return compareGreater , true
}
if intobj1 == intobj2 {
return compareEqual , true
}
if intobj1 < intobj2 {
return compareLess , true
}
}
case reflect .Int8 :
{
int8obj1 , ok := obj1 .(int8 )
if !ok {
int8obj1 = obj1Value .Convert (int8Type ).Interface ().(int8 )
}
int8obj2 , ok := obj2 .(int8 )
if !ok {
int8obj2 = obj2Value .Convert (int8Type ).Interface ().(int8 )
}
if int8obj1 > int8obj2 {
return compareGreater , true
}
if int8obj1 == int8obj2 {
return compareEqual , true
}
if int8obj1 < int8obj2 {
return compareLess , true
}
}
case reflect .Int16 :
{
int16obj1 , ok := obj1 .(int16 )
if !ok {
int16obj1 = obj1Value .Convert (int16Type ).Interface ().(int16 )
}
int16obj2 , ok := obj2 .(int16 )
if !ok {
int16obj2 = obj2Value .Convert (int16Type ).Interface ().(int16 )
}
if int16obj1 > int16obj2 {
return compareGreater , true
}
if int16obj1 == int16obj2 {
return compareEqual , true
}
if int16obj1 < int16obj2 {
return compareLess , true
}
}
case reflect .Int32 :
{
int32obj1 , ok := obj1 .(int32 )
if !ok {
int32obj1 = obj1Value .Convert (int32Type ).Interface ().(int32 )
}
int32obj2 , ok := obj2 .(int32 )
if !ok {
int32obj2 = obj2Value .Convert (int32Type ).Interface ().(int32 )
}
if int32obj1 > int32obj2 {
return compareGreater , true
}
if int32obj1 == int32obj2 {
return compareEqual , true
}
if int32obj1 < int32obj2 {
return compareLess , true
}
}
case reflect .Int64 :
{
int64obj1 , ok := obj1 .(int64 )
if !ok {
int64obj1 = obj1Value .Convert (int64Type ).Interface ().(int64 )
}
int64obj2 , ok := obj2 .(int64 )
if !ok {
int64obj2 = obj2Value .Convert (int64Type ).Interface ().(int64 )
}
if int64obj1 > int64obj2 {
return compareGreater , true
}
if int64obj1 == int64obj2 {
return compareEqual , true
}
if int64obj1 < int64obj2 {
return compareLess , true
}
}
case reflect .Uint :
{
uintobj1 , ok := obj1 .(uint )
if !ok {
uintobj1 = obj1Value .Convert (uintType ).Interface ().(uint )
}
uintobj2 , ok := obj2 .(uint )
if !ok {
uintobj2 = obj2Value .Convert (uintType ).Interface ().(uint )
}
if uintobj1 > uintobj2 {
return compareGreater , true
}
if uintobj1 == uintobj2 {
return compareEqual , true
}
if uintobj1 < uintobj2 {
return compareLess , true
}
}
case reflect .Uint8 :
{
uint8obj1 , ok := obj1 .(uint8 )
if !ok {
uint8obj1 = obj1Value .Convert (uint8Type ).Interface ().(uint8 )
}
uint8obj2 , ok := obj2 .(uint8 )
if !ok {
uint8obj2 = obj2Value .Convert (uint8Type ).Interface ().(uint8 )
}
if uint8obj1 > uint8obj2 {
return compareGreater , true
}
if uint8obj1 == uint8obj2 {
return compareEqual , true
}
if uint8obj1 < uint8obj2 {
return compareLess , true
}
}
case reflect .Uint16 :
{
uint16obj1 , ok := obj1 .(uint16 )
if !ok {
uint16obj1 = obj1Value .Convert (uint16Type ).Interface ().(uint16 )
}
uint16obj2 , ok := obj2 .(uint16 )
if !ok {
uint16obj2 = obj2Value .Convert (uint16Type ).Interface ().(uint16 )
}
if uint16obj1 > uint16obj2 {
return compareGreater , true
}
if uint16obj1 == uint16obj2 {
return compareEqual , true
}
if uint16obj1 < uint16obj2 {
return compareLess , true
}
}
case reflect .Uint32 :
{
uint32obj1 , ok := obj1 .(uint32 )
if !ok {
uint32obj1 = obj1Value .Convert (uint32Type ).Interface ().(uint32 )
}
uint32obj2 , ok := obj2 .(uint32 )
if !ok {
uint32obj2 = obj2Value .Convert (uint32Type ).Interface ().(uint32 )
}
if uint32obj1 > uint32obj2 {
return compareGreater , true
}
if uint32obj1 == uint32obj2 {
return compareEqual , true
}
if uint32obj1 < uint32obj2 {
return compareLess , true
}
}
case reflect .Uint64 :
{
uint64obj1 , ok := obj1 .(uint64 )
if !ok {
uint64obj1 = obj1Value .Convert (uint64Type ).Interface ().(uint64 )
}
uint64obj2 , ok := obj2 .(uint64 )
if !ok {
uint64obj2 = obj2Value .Convert (uint64Type ).Interface ().(uint64 )
}
if uint64obj1 > uint64obj2 {
return compareGreater , true
}
if uint64obj1 == uint64obj2 {
return compareEqual , true
}
if uint64obj1 < uint64obj2 {
return compareLess , true
}
}
case reflect .Float32 :
{
float32obj1 , ok := obj1 .(float32 )
if !ok {
float32obj1 = obj1Value .Convert (float32Type ).Interface ().(float32 )
}
float32obj2 , ok := obj2 .(float32 )
if !ok {
float32obj2 = obj2Value .Convert (float32Type ).Interface ().(float32 )
}
if float32obj1 > float32obj2 {
return compareGreater , true
}
if float32obj1 == float32obj2 {
return compareEqual , true
}
if float32obj1 < float32obj2 {
return compareLess , true
}
}
case reflect .Float64 :
{
float64obj1 , ok := obj1 .(float64 )
if !ok {
float64obj1 = obj1Value .Convert (float64Type ).Interface ().(float64 )
}
float64obj2 , ok := obj2 .(float64 )
if !ok {
float64obj2 = obj2Value .Convert (float64Type ).Interface ().(float64 )
}
if float64obj1 > float64obj2 {
return compareGreater , true
}
if float64obj1 == float64obj2 {
return compareEqual , true
}
if float64obj1 < float64obj2 {
return compareLess , true
}
}
case reflect .String :
{
stringobj1 , ok := obj1 .(string )
if !ok {
stringobj1 = obj1Value .Convert (stringType ).Interface ().(string )
}
stringobj2 , ok := obj2 .(string )
if !ok {
stringobj2 = obj2Value .Convert (stringType ).Interface ().(string )
}
if stringobj1 > stringobj2 {
return compareGreater , true
}
if stringobj1 == stringobj2 {
return compareEqual , true
}
if stringobj1 < stringobj2 {
return compareLess , true
}
}
case reflect .Struct :
{
if !obj1Value .CanConvert (timeType ) {
break
}
timeObj1 , ok := obj1 .(time .Time )
if !ok {
timeObj1 = obj1Value .Convert (timeType ).Interface ().(time .Time )
}
timeObj2 , ok := obj2 .(time .Time )
if !ok {
timeObj2 = obj2Value .Convert (timeType ).Interface ().(time .Time )
}
if timeObj1 .Before (timeObj2 ) {
return compareLess , true
}
if timeObj1 .Equal (timeObj2 ) {
return compareEqual , true
}
return compareGreater , true
}
case reflect .Slice :
{
if !obj1Value .CanConvert (bytesType ) {
break
}
bytesObj1 , ok := obj1 .([]byte )
if !ok {
bytesObj1 = obj1Value .Convert (bytesType ).Interface ().([]byte )
}
bytesObj2 , ok := obj2 .([]byte )
if !ok {
bytesObj2 = obj2Value .Convert (bytesType ).Interface ().([]byte )
}
return compareResult (bytes .Compare (bytesObj1 , bytesObj2 )), true
}
case reflect .Uintptr :
{
uintptrObj1 , ok := obj1 .(uintptr )
if !ok {
uintptrObj1 = obj1Value .Convert (uintptrType ).Interface ().(uintptr )
}
uintptrObj2 , ok := obj2 .(uintptr )
if !ok {
uintptrObj2 = obj2Value .Convert (uintptrType ).Interface ().(uintptr )
}
if uintptrObj1 > uintptrObj2 {
return compareGreater , true
}
if uintptrObj1 == uintptrObj2 {
return compareEqual , true
}
if uintptrObj1 < uintptrObj2 {
return compareLess , true
}
}
}
return compareEqual , false
}
func Greater (t TestingT , e1 interface {}, e2 interface {}, msgAndArgs ...interface {}) bool {
if h , ok := t .(tHelper ); ok {
h .Helper ()
}
failMessage := fmt .Sprintf ("\"%v\" is not greater than \"%v\"" , e1 , e2 )
return compareTwoValues (t , e1 , e2 , []compareResult {compareGreater }, failMessage , msgAndArgs ...)
}
func GreaterOrEqual (t TestingT , e1 interface {}, e2 interface {}, msgAndArgs ...interface {}) bool {
if h , ok := t .(tHelper ); ok {
h .Helper ()
}
failMessage := fmt .Sprintf ("\"%v\" is not greater than or equal to \"%v\"" , e1 , e2 )
return compareTwoValues (t , e1 , e2 , []compareResult {compareGreater , compareEqual }, failMessage , msgAndArgs ...)
}
func Less (t TestingT , e1 interface {}, e2 interface {}, msgAndArgs ...interface {}) bool {
if h , ok := t .(tHelper ); ok {
h .Helper ()
}
failMessage := fmt .Sprintf ("\"%v\" is not less than \"%v\"" , e1 , e2 )
return compareTwoValues (t , e1 , e2 , []compareResult {compareLess }, failMessage , msgAndArgs ...)
}
func LessOrEqual (t TestingT , e1 interface {}, e2 interface {}, msgAndArgs ...interface {}) bool {
if h , ok := t .(tHelper ); ok {
h .Helper ()
}
failMessage := fmt .Sprintf ("\"%v\" is not less than or equal to \"%v\"" , e1 , e2 )
return compareTwoValues (t , e1 , e2 , []compareResult {compareLess , compareEqual }, failMessage , msgAndArgs ...)
}
func Positive (t TestingT , e interface {}, msgAndArgs ...interface {}) bool {
if h , ok := t .(tHelper ); ok {
h .Helper ()
}
zero := reflect .Zero (reflect .TypeOf (e ))
failMessage := fmt .Sprintf ("\"%v\" is not positive" , e )
return compareTwoValues (t , e , zero .Interface (), []compareResult {compareGreater }, failMessage , msgAndArgs ...)
}
func Negative (t TestingT , e interface {}, msgAndArgs ...interface {}) bool {
if h , ok := t .(tHelper ); ok {
h .Helper ()
}
zero := reflect .Zero (reflect .TypeOf (e ))
failMessage := fmt .Sprintf ("\"%v\" is not negative" , e )
return compareTwoValues (t , e , zero .Interface (), []compareResult {compareLess }, failMessage , msgAndArgs ...)
}
func compareTwoValues(t TestingT , e1 interface {}, e2 interface {}, allowedComparesResults []compareResult , failMessage string , msgAndArgs ...interface {}) bool {
if h , ok := t .(tHelper ); ok {
h .Helper ()
}
e1Kind := reflect .ValueOf (e1 ).Kind ()
e2Kind := reflect .ValueOf (e2 ).Kind ()
if e1Kind != e2Kind {
return Fail (t , "Elements should be the same type" , msgAndArgs ...)
}
compareResult , isComparable := compare (e1 , e2 , e1Kind )
if !isComparable {
return Fail (t , fmt .Sprintf (`Can not compare type "%T"` , e1 ), msgAndArgs ...)
}
if !containsValue (allowedComparesResults , compareResult ) {
return Fail (t , failMessage , msgAndArgs ...)
}
return true
}
func containsValue(values []compareResult , value compareResult ) bool {
for _ , v := range values {
if v == value {
return true
}
}
return false
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .