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  }