github.com/gogf/gf/v2@v2.7.4/util/gvalid/gvalid_z_unit_feature_checkstruct_test.go (about) 1 // Copyright GoFrame Author(https://goframe.org). All Rights Reserved. 2 // 3 // This Source Code Form is subject to the terms of the MIT License. 4 // If a copy of the MIT was not distributed with this file, 5 // You can obtain one at https://github.com/gogf/gf. 6 7 package gvalid_test 8 9 import ( 10 "context" 11 "testing" 12 13 "github.com/gogf/gf/v2/container/gvar" 14 "github.com/gogf/gf/v2/frame/g" 15 "github.com/gogf/gf/v2/os/gtime" 16 "github.com/gogf/gf/v2/test/gtest" 17 "github.com/gogf/gf/v2/util/gconv" 18 ) 19 20 func Test_CheckStruct(t *testing.T) { 21 gtest.C(t, func(t *gtest.T) { 22 type Object struct { 23 Name string 24 Age int 25 } 26 rules := []string{ 27 "@required|length:6,16", 28 "@between:18,30", 29 } 30 msgs := map[string]interface{}{ 31 "Name": map[string]string{ 32 "required": "名称不能为空", 33 "length": "名称长度为{min}到{max}个字符", 34 }, 35 "Age": "年龄为18到30周岁", 36 } 37 obj := &Object{"john", 16} 38 err := g.Validator().Data(obj).Rules(rules).Messages(msgs).Run(context.TODO()) 39 t.AssertNil(err) 40 }) 41 42 gtest.C(t, func(t *gtest.T) { 43 type Object struct { 44 Name string 45 Age int 46 } 47 rules := []string{ 48 "Name@required|length:6,16#名称不能为空", 49 "Age@between:18,30", 50 } 51 msgs := map[string]interface{}{ 52 "Name": map[string]string{ 53 "required": "名称不能为空", 54 "length": "名称长度为{min}到{max}个字符", 55 }, 56 "Age": "年龄为18到30周岁", 57 } 58 obj := &Object{"john", 16} 59 err := g.Validator().Data(obj).Rules(rules).Messages(msgs).Run(context.TODO()) 60 t.AssertNE(err, nil) 61 t.Assert(len(err.Maps()), 2) 62 t.Assert(err.Maps()["Name"]["required"], "") 63 t.Assert(err.Maps()["Name"]["length"], "名称长度为6到16个字符") 64 t.Assert(err.Maps()["Age"]["between"], "年龄为18到30周岁") 65 }) 66 67 gtest.C(t, func(t *gtest.T) { 68 type Object struct { 69 Name string 70 Age int 71 } 72 rules := []string{ 73 "Name@required|length:6,16#名称不能为空|", 74 "Age@between:18,30", 75 } 76 msgs := map[string]interface{}{ 77 "Name": map[string]string{ 78 "required": "名称不能为空", 79 "length": "名称长度为{min}到{max}个字符", 80 }, 81 "Age": "年龄为18到30周岁", 82 } 83 obj := &Object{"john", 16} 84 err := g.Validator().Data(obj).Rules(rules).Messages(msgs).Run(context.TODO()) 85 t.AssertNE(err, nil) 86 t.Assert(len(err.Maps()), 2) 87 t.Assert(err.Maps()["Name"]["required"], "") 88 t.Assert(err.Maps()["Name"]["length"], "名称长度为6到16个字符") 89 t.Assert(err.Maps()["Age"]["between"], "年龄为18到30周岁") 90 }) 91 92 gtest.C(t, func(t *gtest.T) { 93 type Object struct { 94 Name string 95 Age int 96 } 97 rules := map[string]string{ 98 "Name": "required|length:6,16", 99 "Age": "between:18,30", 100 } 101 msgs := map[string]interface{}{ 102 "Name": map[string]string{ 103 "required": "名称不能为空", 104 "length": "名称长度为{min}到{max}个字符", 105 }, 106 "Age": "年龄为18到30周岁", 107 } 108 obj := &Object{"john", 16} 109 err := g.Validator().Data(obj).Rules(rules).Messages(msgs).Run(context.TODO()) 110 t.AssertNE(err, nil) 111 t.Assert(len(err.Maps()), 2) 112 t.Assert(err.Maps()["Name"]["required"], "") 113 t.Assert(err.Maps()["Name"]["length"], "名称长度为6到16个字符") 114 t.Assert(err.Maps()["Age"]["between"], "年龄为18到30周岁") 115 }) 116 117 gtest.C(t, func(t *gtest.T) { 118 type LoginRequest struct { 119 Username string `json:"username" valid:"username@required#用户名不能为空"` 120 Password string `json:"password" valid:"password@required#登录密码不能为空"` 121 } 122 var login LoginRequest 123 err := g.Validator().Data(login).Run(context.TODO()) 124 t.AssertNE(err, nil) 125 t.Assert(len(err.Maps()), 2) 126 t.Assert(err.Maps()["username"]["required"], "用户名不能为空") 127 t.Assert(err.Maps()["password"]["required"], "登录密码不能为空") 128 }) 129 130 gtest.C(t, func(t *gtest.T) { 131 type LoginRequest struct { 132 Username string `json:"username" valid:"@required#用户名不能为空"` 133 Password string `json:"password" valid:"@required#登录密码不能为空"` 134 } 135 var login LoginRequest 136 err := g.Validator().Data(login).Run(context.TODO()) 137 t.AssertNil(err) 138 }) 139 140 gtest.C(t, func(t *gtest.T) { 141 type LoginRequest struct { 142 username string `json:"username" valid:"username@required#用户名不能为空"` 143 Password string `json:"password" valid:"password@required#登录密码不能为空"` 144 } 145 var login LoginRequest 146 err := g.Validator().Data(login).Run(context.TODO()) 147 t.AssertNE(err, nil) 148 t.Assert(err.Maps()["password"]["required"], "登录密码不能为空") 149 }) 150 151 // gvalid tag 152 gtest.C(t, func(t *gtest.T) { 153 type User struct { 154 Id int `valid:"uid@required|min:10#|ID不能为空"` 155 Age int `valid:"age@required#年龄不能为空"` 156 Username string `json:"username" valid:"username@required#用户名不能为空"` 157 Password string `json:"password" valid:"password@required#登录密码不能为空"` 158 } 159 user := &User{ 160 Id: 1, 161 Username: "john", 162 Password: "123456", 163 } 164 err := g.Validator().Data(user).Run(context.TODO()) 165 t.AssertNE(err, nil) 166 t.Assert(len(err.Maps()), 1) 167 t.Assert(err.Maps()["uid"]["min"], "ID不能为空") 168 }) 169 170 gtest.C(t, func(t *gtest.T) { 171 type User struct { 172 Id int `valid:"uid@required|min:10#|ID不能为空"` 173 Age int `valid:"age@required#年龄不能为空"` 174 Username string `json:"username" valid:"username@required#用户名不能为空"` 175 Password string `json:"password" valid:"password@required#登录密码不能为空"` 176 } 177 user := &User{ 178 Id: 1, 179 Username: "john", 180 Password: "123456", 181 } 182 183 rules := []string{ 184 "username@required#用户名不能为空", 185 } 186 187 err := g.Validator().Data(user).Rules(rules).Run(context.TODO()) 188 t.AssertNE(err, nil) 189 t.Assert(len(err.Maps()), 1) 190 t.Assert(err.Maps()["uid"]["min"], "ID不能为空") 191 }) 192 193 gtest.C(t, func(t *gtest.T) { 194 type User struct { 195 Id int `valid:"uid@required|min:10#ID不能为空"` 196 Age int `valid:"age@required#年龄不能为空"` 197 Username string `json:"username" valid:"username@required#用户名不能为空"` 198 Password string `json:"password" valid:"password@required#登录密码不能为空"` 199 } 200 user := &User{ 201 Id: 1, 202 Username: "john", 203 Password: "123456", 204 } 205 err := g.Validator().Data(user).Run(context.TODO()) 206 t.AssertNE(err, nil) 207 t.Assert(len(err.Maps()), 1) 208 }) 209 210 // valid tag 211 gtest.C(t, func(t *gtest.T) { 212 type User struct { 213 Id int `valid:"uid@required|min:10#|ID不能为空"` 214 Age int `valid:"age@required#年龄不能为空"` 215 Username string `json:"username" valid:"username@required#用户名不能为空"` 216 Password string `json:"password" valid:"password@required#登录密码不能为空"` 217 } 218 user := &User{ 219 Id: 1, 220 Username: "john", 221 Password: "123456", 222 } 223 err := g.Validator().Data(user).Run(context.TODO()) 224 t.AssertNE(err, nil) 225 t.Assert(len(err.Maps()), 1) 226 t.Assert(err.Maps()["uid"]["min"], "ID不能为空") 227 }) 228 } 229 230 func Test_CheckStruct_EmbeddedObject_Attribute(t *testing.T) { 231 gtest.C(t, func(t *gtest.T) { 232 type Base struct { 233 Time *gtime.Time 234 } 235 type Object struct { 236 Base 237 Name string 238 Type int 239 } 240 rules := map[string]string{ 241 "Name": "required", 242 "Type": "required", 243 } 244 ruleMsg := map[string]interface{}{ 245 "Name": "名称必填", 246 "Type": "类型必填", 247 } 248 obj := &Object{} 249 obj.Type = 1 250 obj.Name = "john" 251 obj.Time = gtime.Now() 252 err := g.Validator().Data(obj).Rules(rules).Messages(ruleMsg).Run(context.TODO()) 253 t.AssertNil(err) 254 }) 255 gtest.C(t, func(t *gtest.T) { 256 type Base struct { 257 Name string 258 Type int 259 } 260 type Object struct { 261 Base Base 262 Name string 263 Type int 264 } 265 rules := map[string]string{ 266 "Name": "required", 267 "Type": "required", 268 } 269 ruleMsg := map[string]interface{}{ 270 "Name": "名称必填", 271 "Type": "类型必填", 272 } 273 obj := &Object{} 274 obj.Type = 1 275 obj.Name = "john" 276 err := g.Validator().Data(obj).Rules(rules).Messages(ruleMsg).Run(context.TODO()) 277 t.AssertNil(err) 278 }) 279 } 280 281 func Test_CheckStruct_With_EmbeddedObject(t *testing.T) { 282 gtest.C(t, func(t *gtest.T) { 283 type Pass struct { 284 Pass1 string `valid:"password1@required|same:password2#请输入您的密码|您两次输入的密码不一致"` 285 Pass2 string `valid:"password2@required|same:password1#请再次输入您的密码|您两次输入的密码不一致"` 286 } 287 type User struct { 288 Id int 289 Name string `valid:"name@required#请输入您的姓名"` 290 Pass 291 } 292 user := &User{ 293 Name: "", 294 Pass: Pass{ 295 Pass1: "1", 296 Pass2: "2", 297 }, 298 } 299 err := g.Validator().Data(user).Run(context.TODO()) 300 t.AssertNE(err, nil) 301 t.Assert(err.Maps()["name"], g.Map{"required": "请输入您的姓名"}) 302 t.Assert(err.Maps()["password1"], g.Map{"same": "您两次输入的密码不一致"}) 303 t.Assert(err.Maps()["password2"], g.Map{"same": "您两次输入的密码不一致"}) 304 }) 305 } 306 307 func Test_CheckStruct_With_StructAttribute(t *testing.T) { 308 gtest.C(t, func(t *gtest.T) { 309 type Pass struct { 310 Pass1 string `valid:"password1@required|same:password2#请输入您的密码|您两次输入的密码不一致"` 311 Pass2 string `valid:"password2@required|same:password1#请再次输入您的密码|您两次输入的密码不一致"` 312 } 313 type User struct { 314 Pass 315 Id int 316 Name string `valid:"name@required#请输入您的姓名"` 317 } 318 user := &User{ 319 Name: "", 320 Pass: Pass{ 321 Pass1: "1", 322 Pass2: "2", 323 }, 324 } 325 err := g.Validator().Data(user).Run(context.TODO()) 326 t.AssertNE(err, nil) 327 t.Assert(err.Maps()["name"], g.Map{"required": "请输入您的姓名"}) 328 t.Assert(err.Maps()["password1"], g.Map{"same": "您两次输入的密码不一致"}) 329 t.Assert(err.Maps()["password2"], g.Map{"same": "您两次输入的密码不一致"}) 330 }) 331 } 332 333 func Test_CheckStruct_Optional(t *testing.T) { 334 gtest.C(t, func(t *gtest.T) { 335 type Params struct { 336 Page int `v:"required|min:1 # page is required"` 337 Size int `v:"required|between:1,100 # size is required"` 338 ProjectId string `v:"between:1,10000 # project id must between {min}, {max}"` 339 } 340 obj := &Params{ 341 Page: 1, 342 Size: 10, 343 } 344 err := g.Validator().Data(obj).Run(context.TODO()) 345 t.AssertNil(err) 346 }) 347 gtest.C(t, func(t *gtest.T) { 348 type Params struct { 349 Page int `v:"required|min:1 # page is required"` 350 Size int `v:"required|between:1,100 # size is required"` 351 ProjectId *gvar.Var `v:"between:1,10000 # project id must between {min}, {max}"` 352 } 353 obj := &Params{ 354 Page: 1, 355 Size: 10, 356 } 357 err := g.Validator().Data(obj).Run(context.TODO()) 358 t.AssertNil(err) 359 }) 360 gtest.C(t, func(t *gtest.T) { 361 type Params struct { 362 Page int `v:"required|min:1 # page is required"` 363 Size int `v:"required|between:1,100 # size is required"` 364 ProjectId int `v:"between:1,10000 # project id must between {min}, {max}"` 365 } 366 obj := &Params{ 367 Page: 1, 368 Size: 10, 369 } 370 err := g.Validator().Data(obj).Run(context.TODO()) 371 t.Assert(err.String(), "project id must between 1, 10000") 372 }) 373 } 374 375 func Test_CheckStruct_NoTag(t *testing.T) { 376 gtest.C(t, func(t *gtest.T) { 377 type Params struct { 378 Page int 379 Size int 380 ProjectId string 381 } 382 obj := &Params{ 383 Page: 1, 384 Size: 10, 385 } 386 err := g.Validator().Data(obj).Run(context.TODO()) 387 t.AssertNil(err) 388 }) 389 } 390 391 func Test_CheckStruct_InvalidRule(t *testing.T) { 392 gtest.C(t, func(t *gtest.T) { 393 type Params struct { 394 Name string 395 Age uint 396 Phone string `v:"mobile"` 397 } 398 obj := &Params{ 399 Name: "john", 400 Age: 18, 401 Phone: "123", 402 } 403 err := g.Validator().Data(obj).Run(context.TODO()) 404 t.AssertNE(err, nil) 405 }) 406 } 407 408 func TestValidator_CheckStructWithData(t *testing.T) { 409 gtest.C(t, func(t *gtest.T) { 410 type UserApiSearch struct { 411 Uid int64 `v:"required"` 412 Nickname string `v:"required-with:uid"` 413 } 414 data := UserApiSearch{ 415 Uid: 1, 416 Nickname: "john", 417 } 418 t.Assert( 419 g.Validator().Data(data).Assoc( 420 g.Map{"uid": 1, "nickname": "john"}, 421 ).Run(context.TODO()), 422 nil, 423 ) 424 }) 425 gtest.C(t, func(t *gtest.T) { 426 type UserApiSearch struct { 427 Uid int64 `v:"required"` 428 Nickname string `v:"required-with:uid"` 429 } 430 data := UserApiSearch{} 431 t.AssertNE(g.Validator().Data(data).Assoc(g.Map{}).Run(context.TODO()), nil) 432 }) 433 gtest.C(t, func(t *gtest.T) { 434 type UserApiSearch struct { 435 Uid int64 `json:"uid" v:"required"` 436 Nickname string `json:"nickname" v:"required-with:Uid"` 437 } 438 data := UserApiSearch{ 439 Uid: 1, 440 } 441 t.AssertNE(g.Validator().Data(data).Assoc(g.Map{}).Run(context.TODO()), nil) 442 }) 443 444 gtest.C(t, func(t *gtest.T) { 445 type UserApiSearch struct { 446 Uid int64 `json:"uid"` 447 Nickname string `json:"nickname" v:"required-with:Uid"` 448 StartTime *gtime.Time `json:"start_time" v:"required-with:EndTime"` 449 EndTime *gtime.Time `json:"end_time" v:"required-with:StartTime"` 450 } 451 data := UserApiSearch{ 452 StartTime: nil, 453 EndTime: nil, 454 } 455 t.Assert(g.Validator().Data(data).Assoc(g.Map{}).Run(context.TODO()), nil) 456 }) 457 gtest.C(t, func(t *gtest.T) { 458 type UserApiSearch struct { 459 Uid int64 `json:"uid"` 460 Nickname string `json:"nickname" v:"required-with:Uid"` 461 StartTime *gtime.Time `json:"start_time" v:"required-with:EndTime"` 462 EndTime *gtime.Time `json:"end_time" v:"required-with:StartTime"` 463 } 464 data := UserApiSearch{ 465 StartTime: gtime.Now(), 466 EndTime: nil, 467 } 468 t.AssertNE(g.Validator().Data(data).Assoc(g.Map{"start_time": gtime.Now()}).Run(context.TODO()), nil) 469 }) 470 } 471 472 func Test_CheckStruct_PointerAttribute(t *testing.T) { 473 gtest.C(t, func(t *gtest.T) { 474 type Req struct { 475 Name string 476 Age *uint `v:"min:18"` 477 } 478 req := &Req{ 479 Name: "john", 480 Age: gconv.PtrUint(0), 481 } 482 err := g.Validator().Data(req).Run(context.TODO()) 483 t.Assert(err.String(), "The Age value `0` must be equal or greater than 18") 484 }) 485 gtest.C(t, func(t *gtest.T) { 486 type Req struct { 487 Name string `v:"min-length:3"` 488 Age *uint `v:"min:18"` 489 } 490 req := &Req{ 491 Name: "j", 492 Age: gconv.PtrUint(19), 493 } 494 err := g.Validator().Data(req).Run(context.TODO()) 495 t.Assert(err.String(), "The Name value `j` length must be equal or greater than 3") 496 }) 497 gtest.C(t, func(t *gtest.T) { 498 type Params struct { 499 Age *uint `v:"min:18"` 500 } 501 type Req struct { 502 Name string 503 Params *Params 504 } 505 req := &Req{ 506 Name: "john", 507 Params: &Params{ 508 Age: gconv.PtrUint(0), 509 }, 510 } 511 err := g.Validator().Data(req).Run(context.TODO()) 512 t.Assert(err.String(), "The Age value `0` must be equal or greater than 18") 513 }) 514 }