less_than.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. // Copyright 2011 Aaron Jacobs. All Rights Reserved.
  2. // Author: aaronjjacobs@gmail.com (Aaron Jacobs)
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License");
  5. // you may not use this file except in compliance with the License.
  6. // You may obtain a copy of the License at
  7. //
  8. // http://www.apache.org/licenses/LICENSE-2.0
  9. //
  10. // Unless required by applicable law or agreed to in writing, software
  11. // distributed under the License is distributed on an "AS IS" BASIS,
  12. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. // See the License for the specific language governing permissions and
  14. // limitations under the License.
  15. package oglematchers
  16. import (
  17. "errors"
  18. "fmt"
  19. "math"
  20. "reflect"
  21. )
  22. // LessThan returns a matcher that matches integer, floating point, or strings
  23. // values v such that v < x. Comparison is not defined between numeric and
  24. // string types, but is defined between all integer and floating point types.
  25. //
  26. // x must itself be an integer, floating point, or string type; otherwise,
  27. // LessThan will panic.
  28. func LessThan(x interface{}) Matcher {
  29. v := reflect.ValueOf(x)
  30. kind := v.Kind()
  31. switch {
  32. case isInteger(v):
  33. case isFloat(v):
  34. case kind == reflect.String:
  35. default:
  36. panic(fmt.Sprintf("LessThan: unexpected kind %v", kind))
  37. }
  38. return &lessThanMatcher{v}
  39. }
  40. type lessThanMatcher struct {
  41. limit reflect.Value
  42. }
  43. func (m *lessThanMatcher) Description() string {
  44. // Special case: make it clear that strings are strings.
  45. if m.limit.Kind() == reflect.String {
  46. return fmt.Sprintf("less than \"%s\"", m.limit.String())
  47. }
  48. return fmt.Sprintf("less than %v", m.limit.Interface())
  49. }
  50. func compareIntegers(v1, v2 reflect.Value) (err error) {
  51. err = errors.New("")
  52. switch {
  53. case isSignedInteger(v1) && isSignedInteger(v2):
  54. if v1.Int() < v2.Int() {
  55. err = nil
  56. }
  57. return
  58. case isSignedInteger(v1) && isUnsignedInteger(v2):
  59. if v1.Int() < 0 || uint64(v1.Int()) < v2.Uint() {
  60. err = nil
  61. }
  62. return
  63. case isUnsignedInteger(v1) && isSignedInteger(v2):
  64. if v1.Uint() <= math.MaxInt64 && int64(v1.Uint()) < v2.Int() {
  65. err = nil
  66. }
  67. return
  68. case isUnsignedInteger(v1) && isUnsignedInteger(v2):
  69. if v1.Uint() < v2.Uint() {
  70. err = nil
  71. }
  72. return
  73. }
  74. panic(fmt.Sprintf("compareIntegers: %v %v", v1, v2))
  75. }
  76. func getFloat(v reflect.Value) float64 {
  77. switch {
  78. case isSignedInteger(v):
  79. return float64(v.Int())
  80. case isUnsignedInteger(v):
  81. return float64(v.Uint())
  82. case isFloat(v):
  83. return v.Float()
  84. }
  85. panic(fmt.Sprintf("getFloat: %v", v))
  86. }
  87. func (m *lessThanMatcher) Matches(c interface{}) (err error) {
  88. v1 := reflect.ValueOf(c)
  89. v2 := m.limit
  90. err = errors.New("")
  91. // Handle strings as a special case.
  92. if v1.Kind() == reflect.String && v2.Kind() == reflect.String {
  93. if v1.String() < v2.String() {
  94. err = nil
  95. }
  96. return
  97. }
  98. // If we get here, we require that we are dealing with integers or floats.
  99. v1Legal := isInteger(v1) || isFloat(v1)
  100. v2Legal := isInteger(v2) || isFloat(v2)
  101. if !v1Legal || !v2Legal {
  102. err = NewFatalError("which is not comparable")
  103. return
  104. }
  105. // Handle the various comparison cases.
  106. switch {
  107. // Both integers
  108. case isInteger(v1) && isInteger(v2):
  109. return compareIntegers(v1, v2)
  110. // At least one float32
  111. case v1.Kind() == reflect.Float32 || v2.Kind() == reflect.Float32:
  112. if float32(getFloat(v1)) < float32(getFloat(v2)) {
  113. err = nil
  114. }
  115. return
  116. // At least one float64
  117. case v1.Kind() == reflect.Float64 || v2.Kind() == reflect.Float64:
  118. if getFloat(v1) < getFloat(v2) {
  119. err = nil
  120. }
  121. return
  122. }
  123. // We shouldn't get here.
  124. panic(fmt.Sprintf("lessThanMatcher.Matches: Shouldn't get here: %v %v", v1, v2))
  125. }