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