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 }