github.com/artisanhe/tools@v1.0.1-0.20210607022958-19a8fef2eb04/courier/transport_http/transform/scanner_test.go (about) 1 package transform 2 3 import ( 4 "fmt" 5 "reflect" 6 "strconv" 7 "testing" 8 9 "github.com/go-courier/ptr" 10 "github.com/stretchr/testify/assert" 11 12 "github.com/artisanhe/tools/timelib" 13 ) 14 15 type Gender int 16 17 const ( 18 GenderMale Gender = iota + 1 19 GenderFemale 20 ) 21 22 func (g Gender) String() string { 23 switch g { 24 case GenderMale: 25 return "male" 26 case GenderFemale: 27 return "female" 28 } 29 return "" 30 } 31 32 func (g Gender) MarshalJSON() ([]byte, error) { 33 return []byte(g.String()), nil 34 } 35 36 func (g *Gender) UnmarshalJSON(data []byte) error { 37 s, _ := strconv.Unquote(string(data)) 38 switch s { 39 case "male": 40 *g = GenderMale 41 case "female": 42 *g = GenderMale 43 default: 44 return fmt.Errorf("unknown gender") 45 } 46 return nil 47 } 48 49 func TestScanner(t *testing.T) { 50 tt := assert.New(t) 51 52 type Sub struct { 53 Name string `json:"name,omitempty"` 54 } 55 56 type TestModel struct { 57 Gender Gender `json:"gender" default:""` 58 Slice []string `json:"slice"` 59 PtrString *string `json:"ptrString" default:""` 60 PtrStringUseInput *string `json:"ptrStringUseInput" default:"2"` 61 PtrStringUseDefault *string `json:"ptrStringUseDefault" default:"2"` 62 RequiredString *string `json:"requiredString"` 63 Struct Sub `json:"struct"` 64 PtrStruct *Sub `json:"ptrStruct,omitempty"` 65 } 66 67 cases := []struct { 68 desc string 69 model TestModel 70 finalModel TestModel 71 valid bool 72 msgMap ErrMsgMap 73 }{ 74 { 75 desc: "normal", 76 valid: true, 77 model: TestModel{ 78 PtrStringUseInput: ptr.String(""), 79 RequiredString: ptr.String(""), 80 }, 81 finalModel: TestModel{ 82 PtrStringUseInput: ptr.String(""), 83 PtrStringUseDefault: ptr.String("2"), 84 RequiredString: ptr.String(""), 85 }, 86 }, 87 } 88 89 for _, tc := range cases { 90 tpe := reflect.TypeOf(tc.model) 91 rv := reflect.Indirect(reflect.ValueOf(&tc.model)) 92 93 valid, msgMap := NewScanner().Validate(rv, tpe) 94 95 tt.Equal(tc.valid, valid, tc.desc) 96 tt.Equal(tc.msgMap, msgMap, tc.desc) 97 tt.Equal(tc.finalModel, tc.model, tc.desc) 98 } 99 } 100 101 type TestSubModel1 struct { 102 String string `json:"string" default:"" validate:"@string[1,]"` 103 Slice []TestSubModel2 `json:"slice"` 104 } 105 106 type TestSubModel2 struct { 107 String string `json:"string" default:"" validate:"@string[1,]"` 108 } 109 110 type TestModel2 struct { 111 a string 112 Gender Gender `json:"gender" default:"trans"` 113 SliceLen []string `json:"slice_len" validate:"@array[1,]"` 114 Slice []string `json:"slice" validate:"@array[1,]:@string[1,]"` 115 Hook string `json:"hook"` 116 Object TestSubModel1 `json:"object"` 117 Time timelib.MySQLTimestamp `json:"time"` 118 } 119 120 func (v TestModel2) ValidateHook() string { 121 return "hook failed" 122 } 123 124 func TestScannerWithValidateErrors(t *testing.T) { 125 tt := assert.New(t) 126 127 cases := []struct { 128 desc string 129 model TestModel2 130 finalModel TestModel2 131 valid bool 132 msgMap ErrMsgMap 133 }{ 134 { 135 desc: "default set failed", 136 valid: false, 137 model: TestModel2{ 138 Slice: []string{"", ""}, 139 Object: TestSubModel1{ 140 Slice: []TestSubModel2{ 141 { 142 String: "", 143 }, 144 }, 145 }, 146 }, 147 finalModel: TestModel2{ 148 Slice: []string{"", ""}, 149 Object: TestSubModel1{ 150 Slice: []TestSubModel2{ 151 { 152 String: "", 153 }, 154 }, 155 }, 156 }, 157 msgMap: ErrMsgMap{ 158 "gender": "Gender can't set wrong default value trans", 159 "slice_len": "切片元素个数不在[1, 0]范围内,当前个数:0", 160 "slice": "切片元素不满足校验[字符串长度不在[1, 1024]范围内,当前长度:0]", 161 "hook": "hook failed", 162 "time": "缺失必填字段", 163 "object.string": "字符串长度不在[1, 1024]范围内,当前长度:0", 164 "object.slice[0].string": "字符串长度不在[1, 1024]范围内,当前长度:0", 165 }, 166 }, 167 } 168 169 for _, tc := range cases { 170 tpe := reflect.TypeOf(tc.model) 171 rv := reflect.Indirect(reflect.ValueOf(&tc.model)) 172 173 valid, msgMap := NewScanner().Validate(rv, tpe) 174 175 tt.Equal(tc.valid, valid, tc.desc) 176 tt.Equal(tc.msgMap, msgMap, tc.desc) 177 tt.Equal(tc.finalModel, tc.model, tc.desc) 178 } 179 } 180 181 func TestMarshalAndValidate(t *testing.T) { 182 tt := assert.New(t) 183 184 { 185 cases := []struct { 186 desc string 187 v int 188 defaultValue string 189 required bool 190 tagValidate string 191 tagErrMsg string 192 errMsg string 193 needToSetDefault bool 194 }{ 195 { 196 desc: "int required", 197 required: true, 198 errMsg: ErrMsgForRequired, 199 }, 200 { 201 desc: "set int with default value", 202 defaultValue: "1", 203 needToSetDefault: true, 204 }, 205 { 206 desc: "set int with default value failed", 207 defaultValue: "str", 208 errMsg: fmt.Sprintf("%s can't set wrong default value %s", "int", "str"), 209 }, 210 } 211 212 for _, tc := range cases { 213 tpe := reflect.TypeOf(tc.v) 214 rv := reflect.Indirect(reflect.ValueOf(&tc.v)) 215 216 tt.Equal(tc.errMsg, MarshalAndValidate(rv, tpe, tc.defaultValue, tc.required, tc.tagValidate, tc.tagErrMsg), tc.desc) 217 if tc.needToSetDefault { 218 tt.Equal(tc.defaultValue, fmt.Sprintf("%v", tc.v)) 219 } 220 } 221 } 222 223 { 224 cases := []struct { 225 desc string 226 V *string 227 defaultValue string 228 required bool 229 tagValidate string 230 tagErrMsg string 231 errMsg string 232 needToSetDefault bool 233 }{ 234 { 235 desc: "nil string skip", 236 }, 237 { 238 desc: "nil string required", 239 required: true, 240 errMsg: ErrMsgForRequired, 241 }, 242 { 243 desc: "nil string should set default", 244 defaultValue: "1", 245 needToSetDefault: true, 246 }, 247 { 248 desc: "nil string should set default", 249 defaultValue: "1", 250 needToSetDefault: true, 251 }, 252 { 253 desc: "ptr string should key value", 254 V: ptr.String(""), 255 defaultValue: "1", 256 needToSetDefault: false, 257 }, 258 } 259 260 for _, tc := range cases { 261 tpe := reflect.TypeOf(tc.V) 262 rv := reflect.Indirect(reflect.ValueOf(&tc)).FieldByName("V") 263 264 tt.Equal(tc.errMsg, MarshalAndValidate(rv, tpe, tc.defaultValue, tc.required, tc.tagValidate, tc.tagErrMsg), tc.desc) 265 266 if tc.needToSetDefault { 267 tt.Equal(&tc.defaultValue, tc.V, tc.desc) 268 } 269 } 270 } 271 272 }