...

Source file src/github.com/stretchr/testify/assert/assertion_compare.go

Documentation: github.com/stretchr/testify/assert

     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  }
   481  

View as plain text