github.com/wangyougui/gf/v2@v2.6.5/util/gvalid/gvalid_z_unit_feature_recursive_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/wangyougui/gf. 6 7 package gvalid_test 8 9 import ( 10 "testing" 11 12 "github.com/wangyougui/gf/v2/frame/g" 13 "github.com/wangyougui/gf/v2/test/gtest" 14 ) 15 16 func Test_CheckStruct_Recursive_Struct(t *testing.T) { 17 gtest.C(t, func(t *gtest.T) { 18 type Pass struct { 19 Pass1 string `v:"required|same:Pass2"` 20 Pass2 string `v:"required|same:Pass1"` 21 } 22 type User struct { 23 Id int 24 Name string `v:"required"` 25 Pass Pass 26 } 27 user := &User{ 28 Name: "", 29 Pass: Pass{ 30 Pass1: "1", 31 Pass2: "2", 32 }, 33 } 34 err := g.Validator().Data(user).Run(ctx) 35 t.AssertNE(err, nil) 36 t.Assert(err.Maps()["Name"], g.Map{"required": "The Name field is required"}) 37 t.Assert(err.Maps()["Pass1"], g.Map{"same": "The Pass1 value `1` must be the same as field Pass2 value `2`"}) 38 t.Assert(err.Maps()["Pass2"], g.Map{"same": "The Pass2 value `2` must be the same as field Pass1 value `1`"}) 39 }) 40 } 41 42 func Test_CheckStruct_Recursive_Struct_WithData(t *testing.T) { 43 gtest.C(t, func(t *gtest.T) { 44 type Pass struct { 45 Pass1 string `v:"required|same:Pass2"` 46 Pass2 string `v:"required|same:Pass1"` 47 } 48 type User struct { 49 Id int 50 Name string `v:"required"` 51 Pass Pass 52 } 53 user := &User{} 54 data := g.Map{ 55 "Name": "john", 56 "Pass": g.Map{ 57 "Pass1": 100, 58 "Pass2": 200, 59 }, 60 } 61 err := g.Validator().Data(user).Assoc(data).Run(ctx) 62 t.AssertNE(err, nil) 63 t.Assert(err.Maps()["Name"], nil) 64 t.Assert(err.Maps()["Pass1"], g.Map{"same": "The Pass1 value `100` must be the same as field Pass2 value `200`"}) 65 t.Assert(err.Maps()["Pass2"], g.Map{"same": "The Pass2 value `200` must be the same as field Pass1 value `100`"}) 66 }) 67 } 68 69 func Test_CheckStruct_Recursive_SliceStruct(t *testing.T) { 70 gtest.C(t, func(t *gtest.T) { 71 type Pass struct { 72 Pass1 string `v:"required|same:Pass2"` 73 Pass2 string `v:"required|same:Pass1"` 74 } 75 type User struct { 76 Id int 77 Name string `v:"required"` 78 Passes []Pass 79 } 80 user := &User{ 81 Name: "", 82 Passes: []Pass{ 83 { 84 Pass1: "1", 85 Pass2: "2", 86 }, 87 { 88 Pass1: "3", 89 Pass2: "4", 90 }, 91 }, 92 } 93 err := g.Validator().Data(user).Run(ctx) 94 g.Dump(err.Items()) 95 t.AssertNE(err, nil) 96 t.Assert(err.Maps()["Name"], g.Map{"required": "The Name field is required"}) 97 t.Assert(err.Maps()["Pass1"], g.Map{"same": "The Pass1 value `3` must be the same as field Pass2 value `4`"}) 98 t.Assert(err.Maps()["Pass2"], g.Map{"same": "The Pass2 value `4` must be the same as field Pass1 value `3`"}) 99 }) 100 } 101 102 func Test_CheckStruct_Recursive_SliceStruct_Bail(t *testing.T) { 103 gtest.C(t, func(t *gtest.T) { 104 type Pass struct { 105 Pass1 string `v:"required|same:Pass2"` 106 Pass2 string `v:"required|same:Pass1"` 107 } 108 type User struct { 109 Id int 110 Name string `v:"required"` 111 Passes []Pass 112 } 113 user := &User{ 114 Name: "", 115 Passes: []Pass{ 116 { 117 Pass1: "1", 118 Pass2: "2", 119 }, 120 { 121 Pass1: "3", 122 Pass2: "4", 123 }, 124 }, 125 } 126 err := g.Validator().Bail().Data(user).Run(ctx) 127 g.Dump(err.Items()) 128 t.AssertNE(err, nil) 129 t.Assert(err.Maps()["Name"], nil) 130 t.Assert(err.Maps()["Pass1"], g.Map{"same": "The Pass1 value `1` must be the same as field Pass2 value `2`"}) 131 t.Assert(err.Maps()["Pass2"], nil) 132 }) 133 } 134 135 func Test_CheckStruct_Recursive_SliceStruct_Required(t *testing.T) { 136 gtest.C(t, func(t *gtest.T) { 137 type Pass struct { 138 Pass1 string `v:"required|same:Pass2"` 139 Pass2 string `v:"required|same:Pass1"` 140 } 141 type User struct { 142 Id int 143 Name string `v:"required"` 144 Passes []Pass 145 } 146 user := &User{} 147 err := g.Validator().Data(user).Run(ctx) 148 g.Dump(err.Items()) 149 t.AssertNE(err, nil) 150 t.Assert(err.Maps()["Name"], g.Map{"required": "The Name field is required"}) 151 t.Assert(err.Maps()["Pass1"], nil) 152 t.Assert(err.Maps()["Pass2"], nil) 153 }) 154 } 155 156 func Test_CheckStruct_Recursive_MapStruct(t *testing.T) { 157 gtest.C(t, func(t *gtest.T) { 158 type Pass struct { 159 Pass1 string `v:"required|same:Pass2"` 160 Pass2 string `v:"required|same:Pass1"` 161 } 162 type User struct { 163 Id int 164 Name string `v:"required"` 165 Passes map[string]Pass 166 } 167 user := &User{ 168 Name: "", 169 Passes: map[string]Pass{ 170 "test1": { 171 Pass1: "1", 172 Pass2: "2", 173 }, 174 "test2": { 175 Pass1: "3", 176 Pass2: "4", 177 }, 178 }, 179 } 180 err := g.Validator().Data(user).Run(ctx) 181 g.Dump(err.Items()) 182 t.AssertNE(err, nil) 183 t.Assert(err.Maps()["Name"], g.Map{"required": "The Name field is required"}) 184 t.AssertNE(err.Maps()["Pass1"], nil) 185 t.AssertNE(err.Maps()["Pass2"], nil) 186 }) 187 } 188 189 func Test_CheckMap_Recursive_SliceStruct(t *testing.T) { 190 gtest.C(t, func(t *gtest.T) { 191 type Pass struct { 192 Pass1 string `v:"required|same:Pass2"` 193 Pass2 string `v:"required|same:Pass1"` 194 } 195 user := g.Map{ 196 "Name": "", 197 "Pass": []Pass{ 198 { 199 Pass1: "1", 200 Pass2: "2", 201 }, 202 { 203 Pass1: "3", 204 Pass2: "4", 205 }, 206 }, 207 } 208 err := g.Validator().Data(user).Run(ctx) 209 g.Dump(err.Items()) 210 t.AssertNE(err, nil) 211 t.Assert(err.Maps()["Name"], nil) 212 t.Assert(err.Maps()["Pass1"], g.Map{"same": "The Pass1 value `3` must be the same as field Pass2 value `4`"}) 213 t.Assert(err.Maps()["Pass2"], g.Map{"same": "The Pass2 value `4` must be the same as field Pass1 value `3`"}) 214 }) 215 } 216 217 func Test_CheckStruct_Recursively_SliceAttribute(t *testing.T) { 218 gtest.C(t, func(t *gtest.T) { 219 type Student struct { 220 Name string `v:"required#Student Name is required"` 221 Age int `v:"required"` 222 } 223 type Teacher struct { 224 Name string `v:"required#Teacher Name is required"` 225 Students []Student `v:"required"` 226 } 227 var ( 228 teacher = Teacher{} 229 data = g.Map{ 230 "name": "john", 231 "students": `[]`, 232 } 233 ) 234 err := g.Validator().Assoc(data).Data(teacher).Run(ctx) 235 t.Assert(err, `The Students field is required`) 236 }) 237 238 gtest.C(t, func(t *gtest.T) { 239 type Student struct { 240 Name string `v:"required#Student Name is required"` 241 Age int `v:"required"` 242 } 243 type Teacher struct { 244 Name string `v:"required#Teacher Name is required"` 245 Students []Student 246 } 247 var ( 248 teacher = Teacher{} 249 data = g.Map{ 250 "name": "john", 251 } 252 ) 253 err := g.Validator().Assoc(data).Data(teacher).Run(ctx) 254 t.Assert(err, ``) 255 }) 256 257 gtest.C(t, func(t *gtest.T) { 258 type Student struct { 259 Name string `v:"required#Student Name is required"` 260 Age int `v:"required"` 261 } 262 type Teacher struct { 263 Name string `v:"required#Teacher Name is required"` 264 Students []Student `v:"required"` 265 } 266 var ( 267 teacher = Teacher{} 268 data = g.Map{ 269 "name": "john", 270 "students": `[{"age":2}, {"name":"jack", "age":4}]`, 271 } 272 ) 273 err := g.Validator().Assoc(data).Data(teacher).Run(ctx) 274 t.Assert(err, `Student Name is required`) 275 }) 276 277 // https://github.com/wangyougui/gf/issues/1864 278 gtest.C(t, func(t *gtest.T) { 279 type Student struct { 280 Name string `v:"required"` 281 Age int 282 } 283 type Teacher struct { 284 Name string 285 Students []*Student 286 } 287 var ( 288 teacher = Teacher{} 289 data = g.Map{ 290 "name": "john", 291 "students": `[{"age":2},{"name":"jack", "age":4}]`, 292 } 293 ) 294 err := g.Validator().Assoc(data).Data(teacher).Run(ctx) 295 t.Assert(err, `The Name field is required`) 296 }) 297 } 298 299 func Test_CheckStruct_Recursively_SliceAttribute_WithTypeAlias(t *testing.T) { 300 gtest.C(t, func(t *gtest.T) { 301 type ParamsItemBase struct { 302 Component string `v:"required" dc:"组件名称"` 303 Params string `v:"required" dc:"配置参数(一般是JSON)"` 304 Version uint64 `v:"required" dc:"参数版本"` 305 } 306 type ParamsItem = ParamsItemBase 307 type ParamsModifyReq struct { 308 Revision uint64 `v:"required"` 309 BizParams []ParamsItem `v:"required"` 310 } 311 var ( 312 req = ParamsModifyReq{} 313 data = g.Map{ 314 "Revision": "1", 315 "BizParams": `[{}]`, 316 } 317 ) 318 err := g.Validator().Assoc(data).Data(req).Run(ctx) 319 t.Assert(err, `The Component field is required; The Params field is required; The Version field is required`) 320 }) 321 } 322 323 func Test_CheckStruct_Recursively_MapAttribute(t *testing.T) { 324 gtest.C(t, func(t *gtest.T) { 325 type Student struct { 326 Name string `v:"required#Student Name is required"` 327 Age int `v:"required"` 328 } 329 type Teacher struct { 330 Name string `v:"required#Teacher Name is required"` 331 Students map[string]Student `v:"required"` 332 } 333 var ( 334 teacher = Teacher{} 335 data = g.Map{ 336 "name": "john", 337 "students": `{"john":{"age":18}}`, 338 } 339 ) 340 err := g.Validator().Assoc(data).Data(teacher).Run(ctx) 341 t.Assert(err, `Student Name is required`) 342 }) 343 } 344 345 // https://github.com/wangyougui/gf/issues/1983 346 func Test_Issue1983(t *testing.T) { 347 // Error as the attribute Student in Teacher is an initialized struct, which has default value. 348 gtest.C(t, func(t *gtest.T) { 349 type Student struct { 350 Name string `v:"required"` 351 Age int 352 } 353 type Teacher struct { 354 Students Student 355 } 356 var ( 357 teacher = Teacher{} 358 data = g.Map{ 359 "students": nil, 360 } 361 ) 362 err := g.Validator().Assoc(data).Data(teacher).Run(ctx) 363 t.Assert(err, `The Name field is required`) 364 }) 365 // The same as upper, it is not affected by association values. 366 gtest.C(t, func(t *gtest.T) { 367 type Student struct { 368 Name string `v:"required"` 369 Age int 370 } 371 type Teacher struct { 372 Students Student 373 } 374 var ( 375 teacher = Teacher{} 376 data = g.Map{ 377 "name": "john", 378 "students": nil, 379 } 380 ) 381 err := g.Validator().Assoc(data).Data(teacher).Run(ctx) 382 t.Assert(err, `The Name field is required`) 383 }) 384 gtest.C(t, func(t *gtest.T) { 385 type Student struct { 386 Name string `v:"required"` 387 Age int 388 } 389 type Teacher struct { 390 Students *Student 391 } 392 var ( 393 teacher = Teacher{} 394 data = g.Map{ 395 "students": nil, 396 } 397 ) 398 err := g.Validator().Assoc(data).Data(teacher).Run(ctx) 399 t.AssertNil(err) 400 }) 401 } 402 403 // https://github.com/wangyougui/gf/issues/1921 404 func Test_Issue1921(t *testing.T) { 405 gtest.C(t, func(t *gtest.T) { 406 type SearchOption struct { 407 Size int `v:"max:100"` 408 } 409 type SearchReq struct { 410 Option *SearchOption `json:"option,omitempty"` 411 } 412 413 var ( 414 req = SearchReq{ 415 Option: &SearchOption{ 416 Size: 10000, 417 }, 418 } 419 ) 420 err := g.Validator().Data(req).Run(ctx) 421 t.Assert(err, "The Size value `10000` must be equal or lesser than 100") 422 }) 423 } 424 425 // https://github.com/wangyougui/gf/issues/2011 426 func Test_Issue2011(t *testing.T) { 427 gtest.C(t, func(t *gtest.T) { 428 type Student struct { 429 Name string `v:"required|min-length:6"` 430 Age int 431 } 432 type Teacher struct { 433 Student *Student 434 } 435 var ( 436 teacher = Teacher{} 437 data = g.Map{ 438 "student": g.Map{ 439 "name": "john", 440 }, 441 } 442 ) 443 err := g.Validator().Assoc(data).Data(teacher).Run(ctx) 444 t.Assert(err, "The Name value `john` length must be equal or greater than 6") 445 }) 446 }