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