github.com/onsi/gomega@v1.32.0/matchers/be_numerically_matcher.go (about) 1 // untested sections: 4 2 3 package matchers 4 5 import ( 6 "fmt" 7 "math" 8 9 "github.com/onsi/gomega/format" 10 ) 11 12 type BeNumericallyMatcher struct { 13 Comparator string 14 CompareTo []interface{} 15 } 16 17 func (matcher *BeNumericallyMatcher) FailureMessage(actual interface{}) (message string) { 18 return matcher.FormatFailureMessage(actual, false) 19 } 20 21 func (matcher *BeNumericallyMatcher) NegatedFailureMessage(actual interface{}) (message string) { 22 return matcher.FormatFailureMessage(actual, true) 23 } 24 25 func (matcher *BeNumericallyMatcher) FormatFailureMessage(actual interface{}, negated bool) (message string) { 26 if len(matcher.CompareTo) == 1 { 27 message = fmt.Sprintf("to be %s", matcher.Comparator) 28 } else { 29 message = fmt.Sprintf("to be within %v of %s", matcher.CompareTo[1], matcher.Comparator) 30 } 31 if negated { 32 message = "not " + message 33 } 34 return format.Message(actual, message, matcher.CompareTo[0]) 35 } 36 37 func (matcher *BeNumericallyMatcher) Match(actual interface{}) (success bool, err error) { 38 if len(matcher.CompareTo) == 0 || len(matcher.CompareTo) > 2 { 39 return false, fmt.Errorf("BeNumerically requires 1 or 2 CompareTo arguments. Got:\n%s", format.Object(matcher.CompareTo, 1)) 40 } 41 if !isNumber(actual) { 42 return false, fmt.Errorf("Expected a number. Got:\n%s", format.Object(actual, 1)) 43 } 44 if !isNumber(matcher.CompareTo[0]) { 45 return false, fmt.Errorf("Expected a number. Got:\n%s", format.Object(matcher.CompareTo[0], 1)) 46 } 47 if len(matcher.CompareTo) == 2 && !isNumber(matcher.CompareTo[1]) { 48 return false, fmt.Errorf("Expected a number. Got:\n%s", format.Object(matcher.CompareTo[1], 1)) 49 } 50 51 switch matcher.Comparator { 52 case "==", "~", ">", ">=", "<", "<=": 53 default: 54 return false, fmt.Errorf("Unknown comparator: %s", matcher.Comparator) 55 } 56 57 if isFloat(actual) || isFloat(matcher.CompareTo[0]) { 58 var secondOperand float64 = 1e-8 59 if len(matcher.CompareTo) == 2 { 60 secondOperand = toFloat(matcher.CompareTo[1]) 61 } 62 success = matcher.matchFloats(toFloat(actual), toFloat(matcher.CompareTo[0]), secondOperand) 63 } else if isInteger(actual) { 64 var secondOperand int64 = 0 65 if len(matcher.CompareTo) == 2 { 66 secondOperand = toInteger(matcher.CompareTo[1]) 67 } 68 success = matcher.matchIntegers(toInteger(actual), toInteger(matcher.CompareTo[0]), secondOperand) 69 } else if isUnsignedInteger(actual) { 70 var secondOperand uint64 = 0 71 if len(matcher.CompareTo) == 2 { 72 secondOperand = toUnsignedInteger(matcher.CompareTo[1]) 73 } 74 success = matcher.matchUnsignedIntegers(toUnsignedInteger(actual), toUnsignedInteger(matcher.CompareTo[0]), secondOperand) 75 } else { 76 return false, fmt.Errorf("Failed to compare:\n%s\n%s:\n%s", format.Object(actual, 1), matcher.Comparator, format.Object(matcher.CompareTo[0], 1)) 77 } 78 79 return success, nil 80 } 81 82 func (matcher *BeNumericallyMatcher) matchIntegers(actual, compareTo, threshold int64) (success bool) { 83 switch matcher.Comparator { 84 case "==", "~": 85 diff := actual - compareTo 86 return -threshold <= diff && diff <= threshold 87 case ">": 88 return (actual > compareTo) 89 case ">=": 90 return (actual >= compareTo) 91 case "<": 92 return (actual < compareTo) 93 case "<=": 94 return (actual <= compareTo) 95 } 96 return false 97 } 98 99 func (matcher *BeNumericallyMatcher) matchUnsignedIntegers(actual, compareTo, threshold uint64) (success bool) { 100 switch matcher.Comparator { 101 case "==", "~": 102 if actual < compareTo { 103 actual, compareTo = compareTo, actual 104 } 105 return actual-compareTo <= threshold 106 case ">": 107 return (actual > compareTo) 108 case ">=": 109 return (actual >= compareTo) 110 case "<": 111 return (actual < compareTo) 112 case "<=": 113 return (actual <= compareTo) 114 } 115 return false 116 } 117 118 func (matcher *BeNumericallyMatcher) matchFloats(actual, compareTo, threshold float64) (success bool) { 119 switch matcher.Comparator { 120 case "~": 121 return math.Abs(actual-compareTo) <= threshold 122 case "==": 123 return (actual == compareTo) 124 case ">": 125 return (actual > compareTo) 126 case ">=": 127 return (actual >= compareTo) 128 case "<": 129 return (actual < compareTo) 130 case "<=": 131 return (actual <= compareTo) 132 } 133 return false 134 }