gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

assertion_compare.go (11632B)


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