github.com/codingeasygo/util@v0.0.0-20231206062002-1ce2f004b7d9/xmap/should.go (about) 1 package xmap 2 3 import ( 4 "fmt" 5 "log" 6 "os" 7 "reflect" 8 "strings" 9 "testing" 10 11 "github.com/codingeasygo/util/converter" 12 ) 13 14 const ShouldIsNil ShouldAction = "IsNil" 15 const ShouldIsNoNil ShouldAction = "IsNoNil" 16 const ShouldIsZero ShouldAction = "IsZero" 17 const ShouldIsNoZero ShouldAction = "IsNoZero" 18 const ShouldIsEmpty ShouldAction = "IsEmpty" 19 const ShouldIsNoEmpty ShouldAction = "IsNoEmpty" 20 const ShouldIsInt ShouldAction = "IsInt" 21 const ShouldIsUint ShouldAction = "IsUint" 22 const ShouldIsFloat ShouldAction = "IsFloat" 23 const ShouldEQ ShouldAction = "EQ" 24 const ShouldGT ShouldAction = "GT" 25 const ShouldGTE ShouldAction = "GTE" 26 const ShouldLT ShouldAction = "LT" 27 const ShouldLTE ShouldAction = "LTE" 28 29 type ShouldAction string 30 31 func (s ShouldAction) isEmpty(val reflect.Value) bool { 32 return (val.Kind() == reflect.Map || val.Kind() == reflect.Slice || val.Kind() == reflect.Array || val.Kind() == reflect.String) && val.Len() == 0 33 } 34 35 func (s ShouldAction) Compare(x, y interface{}) bool { 36 a, b := reflect.ValueOf(x), reflect.ValueOf(y) 37 if a.CanInt() && b.CanInt() { 38 av := a.Convert(reflect.TypeOf(int64(0))).Interface().(int64) 39 bv := b.Convert(reflect.TypeOf(int64(0))).Interface().(int64) 40 if s == ShouldEQ && av != bv { 41 return false 42 } 43 if s == ShouldGT && av <= bv { 44 return false 45 } 46 if s == ShouldGTE && av < bv { 47 return false 48 } 49 if s == ShouldLT && av >= bv { 50 return false 51 } 52 if s == ShouldLTE && av > bv { 53 return false 54 } 55 return true 56 } 57 if a.CanUint() && b.CanUint() { 58 av := a.Convert(reflect.TypeOf(uint64(0))).Interface().(uint64) 59 bv := b.Convert(reflect.TypeOf(uint64(0))).Interface().(uint64) 60 if s == ShouldEQ && av != bv { 61 return false 62 } 63 if s == ShouldGT && av <= bv { 64 return false 65 } 66 if s == ShouldGTE && av < bv { 67 return false 68 } 69 if s == ShouldLT && av >= bv { 70 return false 71 } 72 if s == ShouldLTE && av > bv { 73 return false 74 } 75 return true 76 } 77 if a.CanFloat() && b.CanFloat() { 78 av := a.Convert(reflect.TypeOf(float64(0))).Interface().(float64) 79 bv := b.Convert(reflect.TypeOf(float64(0))).Interface().(float64) 80 if s == ShouldEQ && av != bv { 81 return false 82 } 83 if s == ShouldGT && av <= bv { 84 return false 85 } 86 if s == ShouldGTE && av < bv { 87 return false 88 } 89 if s == ShouldLT && av >= bv { 90 return false 91 } 92 if s == ShouldLTE && av > bv { 93 return false 94 } 95 return true 96 } 97 return ValueEqual(x, y) 98 } 99 100 func (s ShouldAction) Check(v interface{}) bool { 101 val := reflect.ValueOf(v) 102 if !val.IsValid() { 103 return s == ShouldIsNil || s == ShouldIsZero 104 } 105 if s == ShouldIsNil && (val.Kind() != reflect.Ptr || (val.Kind() == reflect.Ptr && !val.IsNil())) { 106 return false 107 } 108 if s == ShouldIsNoNil && val.Kind() == reflect.Ptr && val.IsNil() { 109 return false 110 } 111 if s == ShouldIsZero && !val.IsZero() { 112 return false 113 } 114 if s == ShouldIsNoZero && val.IsZero() { 115 return false 116 } 117 if s == ShouldIsEmpty && !s.isEmpty(val) { 118 return false 119 } 120 if s == ShouldIsNoEmpty && s.isEmpty(val) { 121 return false 122 } 123 if s == ShouldIsInt && !val.CanInt() { 124 return false 125 } 126 if s == ShouldIsUint && !val.CanUint() { 127 return false 128 } 129 if s == ShouldIsFloat && !val.CanFloat() { 130 return false 131 } 132 return true 133 } 134 135 func (m M) Should(args ...interface{}) (err error) { 136 n := len(args) 137 for i := 0; i < n; { 138 if i+1 >= n { 139 err = fmt.Errorf("args[%v] action is not setted", i) 140 break 141 } 142 key, ok := args[i].(string) 143 if !ok { 144 err = fmt.Errorf("args[%v] key is not string", i) 145 break 146 } 147 val := m.Value(key) 148 action, ok := args[i+1].(ShouldAction) 149 if !ok { 150 if !ValueEqual(val, args[i+1]) { 151 err = fmt.Errorf("m.%v(%v,%v)!=args[%v](%v,%v)", key, reflect.TypeOf(val), val, i+1, reflect.TypeOf(args[i+1]), args[i+1]) 152 break 153 } 154 i += 2 155 continue 156 } 157 if strings.HasPrefix(string(action), "Is") { 158 if !action.Check(val) { 159 err = fmt.Errorf("m.%v(%v,%v)!=%v", key, reflect.TypeOf(val), val, action) 160 break 161 } 162 i += 2 163 continue 164 } 165 if i+2 >= n { 166 err = fmt.Errorf("args[%v] compare value is not setted", i) 167 break 168 } 169 if !action.Compare(val, args[i+2]) { 170 err = fmt.Errorf("m.%v(%v,%v) %v args[%v](%v,%v)", key, reflect.TypeOf(val), val, action, i+2, reflect.TypeOf(args[i+2]), args[i+2]) 171 break 172 } 173 i += 3 174 } 175 return 176 } 177 178 type Shoulder struct { 179 Log *log.Logger 180 testerFail func() 181 testerSkip func() 182 shouldErr bool 183 shouldArgs []interface{} 184 onlyLog bool 185 } 186 187 func (s *Shoulder) Should(t *testing.T, args ...interface{}) *Shoulder { 188 if t != nil { 189 s.testerFail, s.testerSkip, s.shouldArgs = t.Fail, t.SkipNow, args 190 } 191 s.shouldArgs = append(s.shouldArgs, args...) 192 return s 193 } 194 195 func (s *Shoulder) ShouldError(t *testing.T) *Shoulder { 196 if t != nil { 197 s.testerFail, s.testerSkip = t.Fail, t.SkipNow 198 } 199 s.shouldErr = true 200 return s 201 } 202 203 func (s *Shoulder) OnlyLog(only bool) *Shoulder { 204 s.onlyLog = only 205 return s 206 } 207 208 func (s *Shoulder) callError(depth int, err error) { 209 if s.testerFail == nil { 210 panic(err) 211 } 212 if s.Log == nil { 213 s.Log = log.New(os.Stderr, " ", log.Llongfile) 214 } 215 s.Log.Output(depth, err.Error()) 216 if !s.onlyLog { 217 s.testerFail() 218 s.testerSkip() 219 } 220 } 221 222 func (s *Shoulder) validError(depth int, res M, err error) bool { 223 if err != nil { 224 s.callError(depth+1, fmt.Errorf("%v, res is %v", err, converter.JSON(res))) 225 return false 226 } 227 return true 228 } 229 230 func (s *Shoulder) validShould(depth int, res M, err error) bool { 231 if len(s.shouldArgs) < 1 { 232 return true 233 } 234 xerr := res.Should(s.shouldArgs...) 235 if xerr != nil { 236 s.callError(depth+1, fmt.Errorf("%v, res is %v", xerr, converter.JSON(res))) 237 return false 238 } 239 return true 240 } 241 242 func (s *Shoulder) Valid(depth int, res M, err error) bool { 243 if s.shouldErr { 244 if err == nil { 245 s.callError(depth+1, fmt.Errorf("err is nil, res is %v", converter.JSON(res))) 246 return false 247 } 248 } else { 249 if !s.validError(depth+1, res, err) { 250 return false 251 } 252 if !s.validShould(depth+1, res, err) { 253 return false 254 } 255 } 256 return true 257 }