From 79f39c5bb52bc338f563df7fc9198ba14c3e6b1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=80=97=E5=AD=90?= Date: Fri, 6 Feb 2026 20:59:08 +0800 Subject: [PATCH 1/2] =?UTF-8?q?fix:=20=E9=80=9A=E9=85=8D=E7=AC=A6=E8=A7=84?= =?UTF-8?q?=E5=88=99=E9=AA=8C=E8=AF=81=20JSON=20=E5=8F=8D=E5=BA=8F?= =?UTF-8?q?=E5=88=97=E5=8C=96=E7=9A=84=20slice=20=E6=97=B6=E8=AF=AF?= =?UTF-8?q?=E5=88=A4=E5=A4=B1=E8=B4=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- issues_test.go | 35 +++++++++++++++++++++++++++++++++++ validating.go | 8 ++++---- 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/issues_test.go b/issues_test.go index bd867f9..8a8b917 100644 --- a/issues_test.go +++ b/issues_test.go @@ -1915,3 +1915,38 @@ func TestIssue_302(t *testing.T) { assert.True(t, v.Validate()) assert.Empty(t, v.Errors.One()) } + +func TestIssue_328(t *testing.T) { + type Test struct { + Domains []string `form:"domains" json:"domains" validate:"required|isSlice"` + Index []string `form:"index" json:"index" validate:"required|isSlice"` + } + + t.Run("success", func(t *testing.T) { + df, err := validate.FromStruct(&Test{ + Domains: []string{"example.com", "test.com", "a.com"}, + Index: []string{"index.php"}, + }) + assert.NoError(t, err) + v := df.Create() + v.StringRule("Domains.*", "required") + v.StringRule("Index.*", "required") + + assert.True(t, v.Validate()) + }) + + t.Run("error", func(t *testing.T) { + data := `{"domains":["example.com","test.com","a.com"],"index":["index.php"]}` + req := new(Test) + err := jsonutil.DecodeString(data, req) + assert.NoError(t, err) + + df, err := validate.FromStruct(req) + assert.NoError(t, err) + v := df.Create() + v.StringRule("Domains.*", "required") + v.StringRule("Index.*", "required") + + assert.True(t, v.Validate()) + }) +} diff --git a/validating.go b/validating.go index c3257d7..622d1d5 100644 --- a/validating.go +++ b/validating.go @@ -299,17 +299,17 @@ func (r *Rule) valueValidate(field, name string, val any, v *Validation) (ok boo valKind := rftVal.Kind() if valKind == reflect.Slice && dotStarNum > 0 { - sliceLen, sliceCap := rftVal.Len(), rftVal.Cap() + sliceLen := rftVal.Len() // if dotStarNum > 1, need flatten multi level slice with depth=dotStarNum. if dotStarNum > 1 { rftVal = flatSlice(rftVal, dotStarNum-1) - sliceLen, sliceCap = rftVal.Len(), rftVal.Cap() + sliceLen = rftVal.Len() } // check requiredXX validate - flatten multi level slice, count ".*" number. - // TIP: if len < cap: not enough elements in the slice. use empty val call validator. - if !r.nameNotRequired && sliceLen < sliceCap { + // TIP: if len == 0: no elements in the slice. use empty val call validator. + if !r.nameNotRequired && sliceLen == 0 { return callValidator(v, fm, field, nil, r.arguments, addNum) } From 26dfc60977ce5715f0375bcfb9a0991ba1b38061 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=80=97=E5=AD=90?= Date: Fri, 6 Feb 2026 21:02:45 +0800 Subject: [PATCH 2/2] fix: lint --- issues_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/issues_test.go b/issues_test.go index 8a8b917..4eebb75 100644 --- a/issues_test.go +++ b/issues_test.go @@ -1922,7 +1922,7 @@ func TestIssue_328(t *testing.T) { Index []string `form:"index" json:"index" validate:"required|isSlice"` } - t.Run("success", func(t *testing.T) { + t.Run("success_with_struct", func(t *testing.T) { df, err := validate.FromStruct(&Test{ Domains: []string{"example.com", "test.com", "a.com"}, Index: []string{"index.php"}, @@ -1935,7 +1935,7 @@ func TestIssue_328(t *testing.T) { assert.True(t, v.Validate()) }) - t.Run("error", func(t *testing.T) { + t.Run("success_with_json", func(t *testing.T) { data := `{"domains":["example.com","test.com","a.com"],"index":["index.php"]}` req := new(Test) err := jsonutil.DecodeString(data, req)