mirror

Mirror free and open-source projects you like with minimal effort
git clone git://git.server.ky/slackcoder/mirror
Log | Files | Refs | README

assertion_compare.go (12166B)


      1 package assert
      2 
      3 import (
      4 	"bytes"
      5 	"fmt"
      6 	"reflect"
      7 	"time"
      8 )
      9 
     10 type CompareType int
     11 
     12 const (
     13 	compareLess CompareType = iota - 1
     14 	compareEqual
     15 	compareGreater
     16 )
     17 
     18 var (
     19 	intType   = reflect.TypeOf(int(1))
     20 	int8Type  = reflect.TypeOf(int8(1))
     21 	int16Type = reflect.TypeOf(int16(1))
     22 	int32Type = reflect.TypeOf(int32(1))
     23 	int64Type = reflect.TypeOf(int64(1))
     24 
     25 	uintType   = reflect.TypeOf(uint(1))
     26 	uint8Type  = reflect.TypeOf(uint8(1))
     27 	uint16Type = reflect.TypeOf(uint16(1))
     28 	uint32Type = reflect.TypeOf(uint32(1))
     29 	uint64Type = reflect.TypeOf(uint64(1))
     30 
     31 	uintptrType = reflect.TypeOf(uintptr(1))
     32 
     33 	float32Type = reflect.TypeOf(float32(1))
     34 	float64Type = reflect.TypeOf(float64(1))
     35 
     36 	stringType = reflect.TypeOf("")
     37 
     38 	timeType  = reflect.TypeOf(time.Time{})
     39 	bytesType = reflect.TypeOf([]byte{})
     40 )
     41 
     42 func compare(obj1, obj2 interface{}, kind reflect.Kind) (CompareType, bool) {
     43 	obj1Value := reflect.ValueOf(obj1)
     44 	obj2Value := reflect.ValueOf(obj2)
     45 
     46 	// throughout this switch we try and avoid calling .Convert() if possible,
     47 	// as this has a pretty big performance impact
     48 	switch kind {
     49 	case reflect.Int:
     50 		{
     51 			intobj1, ok := obj1.(int)
     52 			if !ok {
     53 				intobj1 = obj1Value.Convert(intType).Interface().(int)
     54 			}
     55 			intobj2, ok := obj2.(int)
     56 			if !ok {
     57 				intobj2 = obj2Value.Convert(intType).Interface().(int)
     58 			}
     59 			if intobj1 > intobj2 {
     60 				return compareGreater, true
     61 			}
     62 			if intobj1 == intobj2 {
     63 				return compareEqual, true
     64 			}
     65 			if intobj1 < intobj2 {
     66 				return compareLess, true
     67 			}
     68 		}
     69 	case reflect.Int8:
     70 		{
     71 			int8obj1, ok := obj1.(int8)
     72 			if !ok {
     73 				int8obj1 = obj1Value.Convert(int8Type).Interface().(int8)
     74 			}
     75 			int8obj2, ok := obj2.(int8)
     76 			if !ok {
     77 				int8obj2 = obj2Value.Convert(int8Type).Interface().(int8)
     78 			}
     79 			if int8obj1 > int8obj2 {
     80 				return compareGreater, true
     81 			}
     82 			if int8obj1 == int8obj2 {
     83 				return compareEqual, true
     84 			}
     85 			if int8obj1 < int8obj2 {
     86 				return compareLess, true
     87 			}
     88 		}
     89 	case reflect.Int16:
     90 		{
     91 			int16obj1, ok := obj1.(int16)
     92 			if !ok {
     93 				int16obj1 = obj1Value.Convert(int16Type).Interface().(int16)
     94 			}
     95 			int16obj2, ok := obj2.(int16)
     96 			if !ok {
     97 				int16obj2 = obj2Value.Convert(int16Type).Interface().(int16)
     98 			}
     99 			if int16obj1 > int16obj2 {
    100 				return compareGreater, true
    101 			}
    102 			if int16obj1 == int16obj2 {
    103 				return compareEqual, true
    104 			}
    105 			if int16obj1 < int16obj2 {
    106 				return compareLess, true
    107 			}
    108 		}
    109 	case reflect.Int32:
    110 		{
    111 			int32obj1, ok := obj1.(int32)
    112 			if !ok {
    113 				int32obj1 = obj1Value.Convert(int32Type).Interface().(int32)
    114 			}
    115 			int32obj2, ok := obj2.(int32)
    116 			if !ok {
    117 				int32obj2 = obj2Value.Convert(int32Type).Interface().(int32)
    118 			}
    119 			if int32obj1 > int32obj2 {
    120 				return compareGreater, true
    121 			}
    122 			if int32obj1 == int32obj2 {
    123 				return compareEqual, true
    124 			}
    125 			if int32obj1 < int32obj2 {
    126 				return compareLess, true
    127 			}
    128 		}
    129 	case reflect.Int64:
    130 		{
    131 			int64obj1, ok := obj1.(int64)
    132 			if !ok {
    133 				int64obj1 = obj1Value.Convert(int64Type).Interface().(int64)
    134 			}
    135 			int64obj2, ok := obj2.(int64)
    136 			if !ok {
    137 				int64obj2 = obj2Value.Convert(int64Type).Interface().(int64)
    138 			}
    139 			if int64obj1 > int64obj2 {
    140 				return compareGreater, true
    141 			}
    142 			if int64obj1 == int64obj2 {
    143 				return compareEqual, true
    144 			}
    145 			if int64obj1 < int64obj2 {
    146 				return compareLess, true
    147 			}
    148 		}
    149 	case reflect.Uint:
    150 		{
    151 			uintobj1, ok := obj1.(uint)
    152 			if !ok {
    153 				uintobj1 = obj1Value.Convert(uintType).Interface().(uint)
    154 			}
    155 			uintobj2, ok := obj2.(uint)
    156 			if !ok {
    157 				uintobj2 = obj2Value.Convert(uintType).Interface().(uint)
    158 			}
    159 			if uintobj1 > uintobj2 {
    160 				return compareGreater, true
    161 			}
    162 			if uintobj1 == uintobj2 {
    163 				return compareEqual, true
    164 			}
    165 			if uintobj1 < uintobj2 {
    166 				return compareLess, true
    167 			}
    168 		}
    169 	case reflect.Uint8:
    170 		{
    171 			uint8obj1, ok := obj1.(uint8)
    172 			if !ok {
    173 				uint8obj1 = obj1Value.Convert(uint8Type).Interface().(uint8)
    174 			}
    175 			uint8obj2, ok := obj2.(uint8)
    176 			if !ok {
    177 				uint8obj2 = obj2Value.Convert(uint8Type).Interface().(uint8)
    178 			}
    179 			if uint8obj1 > uint8obj2 {
    180 				return compareGreater, true
    181 			}
    182 			if uint8obj1 == uint8obj2 {
    183 				return compareEqual, true
    184 			}
    185 			if uint8obj1 < uint8obj2 {
    186 				return compareLess, true
    187 			}
    188 		}
    189 	case reflect.Uint16:
    190 		{
    191 			uint16obj1, ok := obj1.(uint16)
    192 			if !ok {
    193 				uint16obj1 = obj1Value.Convert(uint16Type).Interface().(uint16)
    194 			}
    195 			uint16obj2, ok := obj2.(uint16)
    196 			if !ok {
    197 				uint16obj2 = obj2Value.Convert(uint16Type).Interface().(uint16)
    198 			}
    199 			if uint16obj1 > uint16obj2 {
    200 				return compareGreater, true
    201 			}
    202 			if uint16obj1 == uint16obj2 {
    203 				return compareEqual, true
    204 			}
    205 			if uint16obj1 < uint16obj2 {
    206 				return compareLess, true
    207 			}
    208 		}
    209 	case reflect.Uint32:
    210 		{
    211 			uint32obj1, ok := obj1.(uint32)
    212 			if !ok {
    213 				uint32obj1 = obj1Value.Convert(uint32Type).Interface().(uint32)
    214 			}
    215 			uint32obj2, ok := obj2.(uint32)
    216 			if !ok {
    217 				uint32obj2 = obj2Value.Convert(uint32Type).Interface().(uint32)
    218 			}
    219 			if uint32obj1 > uint32obj2 {
    220 				return compareGreater, true
    221 			}
    222 			if uint32obj1 == uint32obj2 {
    223 				return compareEqual, true
    224 			}
    225 			if uint32obj1 < uint32obj2 {
    226 				return compareLess, true
    227 			}
    228 		}
    229 	case reflect.Uint64:
    230 		{
    231 			uint64obj1, ok := obj1.(uint64)
    232 			if !ok {
    233 				uint64obj1 = obj1Value.Convert(uint64Type).Interface().(uint64)
    234 			}
    235 			uint64obj2, ok := obj2.(uint64)
    236 			if !ok {
    237 				uint64obj2 = obj2Value.Convert(uint64Type).Interface().(uint64)
    238 			}
    239 			if uint64obj1 > uint64obj2 {
    240 				return compareGreater, true
    241 			}
    242 			if uint64obj1 == uint64obj2 {
    243 				return compareEqual, true
    244 			}
    245 			if uint64obj1 < uint64obj2 {
    246 				return compareLess, true
    247 			}
    248 		}
    249 	case reflect.Float32:
    250 		{
    251 			float32obj1, ok := obj1.(float32)
    252 			if !ok {
    253 				float32obj1 = obj1Value.Convert(float32Type).Interface().(float32)
    254 			}
    255 			float32obj2, ok := obj2.(float32)
    256 			if !ok {
    257 				float32obj2 = obj2Value.Convert(float32Type).Interface().(float32)
    258 			}
    259 			if float32obj1 > float32obj2 {
    260 				return compareGreater, true
    261 			}
    262 			if float32obj1 == float32obj2 {
    263 				return compareEqual, true
    264 			}
    265 			if float32obj1 < float32obj2 {
    266 				return compareLess, true
    267 			}
    268 		}
    269 	case reflect.Float64:
    270 		{
    271 			float64obj1, ok := obj1.(float64)
    272 			if !ok {
    273 				float64obj1 = obj1Value.Convert(float64Type).Interface().(float64)
    274 			}
    275 			float64obj2, ok := obj2.(float64)
    276 			if !ok {
    277 				float64obj2 = obj2Value.Convert(float64Type).Interface().(float64)
    278 			}
    279 			if float64obj1 > float64obj2 {
    280 				return compareGreater, true
    281 			}
    282 			if float64obj1 == float64obj2 {
    283 				return compareEqual, true
    284 			}
    285 			if float64obj1 < float64obj2 {
    286 				return compareLess, true
    287 			}
    288 		}
    289 	case reflect.String:
    290 		{
    291 			stringobj1, ok := obj1.(string)
    292 			if !ok {
    293 				stringobj1 = obj1Value.Convert(stringType).Interface().(string)
    294 			}
    295 			stringobj2, ok := obj2.(string)
    296 			if !ok {
    297 				stringobj2 = obj2Value.Convert(stringType).Interface().(string)
    298 			}
    299 			if stringobj1 > stringobj2 {
    300 				return compareGreater, true
    301 			}
    302 			if stringobj1 == stringobj2 {
    303 				return compareEqual, true
    304 			}
    305 			if stringobj1 < stringobj2 {
    306 				return compareLess, true
    307 			}
    308 		}
    309 	// Check for known struct types we can check for compare results.
    310 	case reflect.Struct:
    311 		{
    312 			// All structs enter here. We're not interested in most types.
    313 			if !obj1Value.CanConvert(timeType) {
    314 				break
    315 			}
    316 
    317 			// time.Time can be compared!
    318 			timeObj1, ok := obj1.(time.Time)
    319 			if !ok {
    320 				timeObj1 = obj1Value.Convert(timeType).Interface().(time.Time)
    321 			}
    322 
    323 			timeObj2, ok := obj2.(time.Time)
    324 			if !ok {
    325 				timeObj2 = obj2Value.Convert(timeType).Interface().(time.Time)
    326 			}
    327 
    328 			return compare(timeObj1.UnixNano(), timeObj2.UnixNano(), reflect.Int64)
    329 		}
    330 	case reflect.Slice:
    331 		{
    332 			// We only care about the []byte type.
    333 			if !obj1Value.CanConvert(bytesType) {
    334 				break
    335 			}
    336 
    337 			// []byte can be compared!
    338 			bytesObj1, ok := obj1.([]byte)
    339 			if !ok {
    340 				bytesObj1 = obj1Value.Convert(bytesType).Interface().([]byte)
    341 
    342 			}
    343 			bytesObj2, ok := obj2.([]byte)
    344 			if !ok {
    345 				bytesObj2 = obj2Value.Convert(bytesType).Interface().([]byte)
    346 			}
    347 
    348 			return CompareType(bytes.Compare(bytesObj1, bytesObj2)), true
    349 		}
    350 	case reflect.Uintptr:
    351 		{
    352 			uintptrObj1, ok := obj1.(uintptr)
    353 			if !ok {
    354 				uintptrObj1 = obj1Value.Convert(uintptrType).Interface().(uintptr)
    355 			}
    356 			uintptrObj2, ok := obj2.(uintptr)
    357 			if !ok {
    358 				uintptrObj2 = obj2Value.Convert(uintptrType).Interface().(uintptr)
    359 			}
    360 			if uintptrObj1 > uintptrObj2 {
    361 				return compareGreater, true
    362 			}
    363 			if uintptrObj1 == uintptrObj2 {
    364 				return compareEqual, true
    365 			}
    366 			if uintptrObj1 < uintptrObj2 {
    367 				return compareLess, true
    368 			}
    369 		}
    370 	}
    371 
    372 	return compareEqual, false
    373 }
    374 
    375 // Greater asserts that the first element is greater than the second
    376 //
    377 //	assert.Greater(t, 2, 1)
    378 //	assert.Greater(t, float64(2), float64(1))
    379 //	assert.Greater(t, "b", "a")
    380 func Greater(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
    381 	if h, ok := t.(tHelper); ok {
    382 		h.Helper()
    383 	}
    384 	return compareTwoValues(t, e1, e2, []CompareType{compareGreater}, "\"%v\" is not greater than \"%v\"", msgAndArgs...)
    385 }
    386 
    387 // GreaterOrEqual asserts that the first element is greater than or equal to the second
    388 //
    389 //	assert.GreaterOrEqual(t, 2, 1)
    390 //	assert.GreaterOrEqual(t, 2, 2)
    391 //	assert.GreaterOrEqual(t, "b", "a")
    392 //	assert.GreaterOrEqual(t, "b", "b")
    393 func GreaterOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
    394 	if h, ok := t.(tHelper); ok {
    395 		h.Helper()
    396 	}
    397 	return compareTwoValues(t, e1, e2, []CompareType{compareGreater, compareEqual}, "\"%v\" is not greater than or equal to \"%v\"", msgAndArgs...)
    398 }
    399 
    400 // Less asserts that the first element is less than the second
    401 //
    402 //	assert.Less(t, 1, 2)
    403 //	assert.Less(t, float64(1), float64(2))
    404 //	assert.Less(t, "a", "b")
    405 func Less(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
    406 	if h, ok := t.(tHelper); ok {
    407 		h.Helper()
    408 	}
    409 	return compareTwoValues(t, e1, e2, []CompareType{compareLess}, "\"%v\" is not less than \"%v\"", msgAndArgs...)
    410 }
    411 
    412 // LessOrEqual asserts that the first element is less than or equal to the second
    413 //
    414 //	assert.LessOrEqual(t, 1, 2)
    415 //	assert.LessOrEqual(t, 2, 2)
    416 //	assert.LessOrEqual(t, "a", "b")
    417 //	assert.LessOrEqual(t, "b", "b")
    418 func LessOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
    419 	if h, ok := t.(tHelper); ok {
    420 		h.Helper()
    421 	}
    422 	return compareTwoValues(t, e1, e2, []CompareType{compareLess, compareEqual}, "\"%v\" is not less than or equal to \"%v\"", msgAndArgs...)
    423 }
    424 
    425 // Positive asserts that the specified element is positive
    426 //
    427 //	assert.Positive(t, 1)
    428 //	assert.Positive(t, 1.23)
    429 func Positive(t TestingT, e interface{}, msgAndArgs ...interface{}) bool {
    430 	if h, ok := t.(tHelper); ok {
    431 		h.Helper()
    432 	}
    433 	zero := reflect.Zero(reflect.TypeOf(e))
    434 	return compareTwoValues(t, e, zero.Interface(), []CompareType{compareGreater}, "\"%v\" is not positive", msgAndArgs...)
    435 }
    436 
    437 // Negative asserts that the specified element is negative
    438 //
    439 //	assert.Negative(t, -1)
    440 //	assert.Negative(t, -1.23)
    441 func Negative(t TestingT, e interface{}, msgAndArgs ...interface{}) bool {
    442 	if h, ok := t.(tHelper); ok {
    443 		h.Helper()
    444 	}
    445 	zero := reflect.Zero(reflect.TypeOf(e))
    446 	return compareTwoValues(t, e, zero.Interface(), []CompareType{compareLess}, "\"%v\" is not negative", msgAndArgs...)
    447 }
    448 
    449 func compareTwoValues(t TestingT, e1 interface{}, e2 interface{}, allowedComparesResults []CompareType, failMessage string, msgAndArgs ...interface{}) bool {
    450 	if h, ok := t.(tHelper); ok {
    451 		h.Helper()
    452 	}
    453 
    454 	e1Kind := reflect.ValueOf(e1).Kind()
    455 	e2Kind := reflect.ValueOf(e2).Kind()
    456 	if e1Kind != e2Kind {
    457 		return Fail(t, "Elements should be the same type", msgAndArgs...)
    458 	}
    459 
    460 	compareResult, isComparable := compare(e1, e2, e1Kind)
    461 	if !isComparable {
    462 		return Fail(t, fmt.Sprintf("Can not compare type \"%s\"", reflect.TypeOf(e1)), msgAndArgs...)
    463 	}
    464 
    465 	if !containsValue(allowedComparesResults, compareResult) {
    466 		return Fail(t, fmt.Sprintf(failMessage, e1, e2), msgAndArgs...)
    467 	}
    468 
    469 	return true
    470 }
    471 
    472 func containsValue(values []CompareType, value CompareType) bool {
    473 	for _, v := range values {
    474 		if v == value {
    475 			return true
    476 		}
    477 	}
    478 
    479 	return false
    480 }