github.com/wangyougui/gf/v2@v2.6.5/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/wangyougui/gf.
     6  
     7  package gvalid_test
     8  
     9  import (
    10  	"context"
    11  	"testing"
    12  
    13  	"github.com/wangyougui/gf/v2/container/gvar"
    14  	"github.com/wangyougui/gf/v2/frame/g"
    15  	"github.com/wangyougui/gf/v2/os/gtime"
    16  	"github.com/wangyougui/gf/v2/test/gtest"
    17  	"github.com/wangyougui/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  }