Skip to content

Commit c3d1092

Browse files
1911860538huangzw
andauthored
fix(binding): improve empty slice/array handling in form binding (#4380)
Co-authored-by: huangzw <[email protected]>
1 parent 9968c4b commit c3d1092

File tree

2 files changed

+90
-4
lines changed

2 files changed

+90
-4
lines changed

binding/form_mapping.go

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -231,9 +231,12 @@ func setByForm(value reflect.Value, field reflect.StructField, form map[string][
231231

232232
switch value.Kind() {
233233
case reflect.Slice:
234-
if !ok {
235-
vs = []string{opt.defaultValue}
234+
if len(vs) == 0 {
235+
if !opt.isDefaultExists {
236+
return false, nil
237+
}
236238

239+
vs = []string{opt.defaultValue}
237240
// pre-process the default value for multi if present
238241
cfTag := field.Tag.Get("collection_format")
239242
if cfTag == "" || cfTag == "multi" {
@@ -251,9 +254,12 @@ func setByForm(value reflect.Value, field reflect.StructField, form map[string][
251254

252255
return true, setSlice(vs, value, field)
253256
case reflect.Array:
254-
if !ok {
255-
vs = []string{opt.defaultValue}
257+
if len(vs) == 0 {
258+
if !opt.isDefaultExists {
259+
return false, nil
260+
}
256261

262+
vs = []string{opt.defaultValue}
257263
// pre-process the default value for multi if present
258264
cfTag := field.Tag.Get("collection_format")
259265
if cfTag == "" || cfTag == "multi" {

binding/form_mapping_test.go

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -635,3 +635,83 @@ func TestMappingCustomArrayForm(t *testing.T) {
635635
expected, _ := convertTo(val)
636636
assert.Equal(t, expected, s.FileData)
637637
}
638+
639+
func TestMappingEmptyValues(t *testing.T) {
640+
t.Run("slice with default", func(t *testing.T) {
641+
var s struct {
642+
Slice []int `form:"slice,default=5"`
643+
}
644+
645+
// field not present
646+
err := mappingByPtr(&s, formSource{}, "form")
647+
require.NoError(t, err)
648+
assert.Equal(t, []int{5}, s.Slice)
649+
650+
// field present but empty
651+
err = mappingByPtr(&s, formSource{"slice": {}}, "form")
652+
require.NoError(t, err)
653+
assert.Equal(t, []int{5}, s.Slice)
654+
655+
// field present with values
656+
err = mappingByPtr(&s, formSource{"slice": {"1", "2", "3"}}, "form")
657+
require.NoError(t, err)
658+
assert.Equal(t, []int{1, 2, 3}, s.Slice)
659+
})
660+
661+
t.Run("array with default", func(t *testing.T) {
662+
var s struct {
663+
Array [1]int `form:"array,default=5"`
664+
}
665+
666+
// field not present
667+
err := mappingByPtr(&s, formSource{}, "form")
668+
require.NoError(t, err)
669+
assert.Equal(t, [1]int{5}, s.Array)
670+
671+
// field present but empty
672+
err = mappingByPtr(&s, formSource{"array": {}}, "form")
673+
require.NoError(t, err)
674+
assert.Equal(t, [1]int{5}, s.Array)
675+
})
676+
677+
t.Run("slice without default", func(t *testing.T) {
678+
var s struct {
679+
Slice []int `form:"slice"`
680+
}
681+
682+
// field present but empty
683+
err := mappingByPtr(&s, formSource{"slice": {}}, "form")
684+
require.NoError(t, err)
685+
assert.Equal(t, []int(nil), s.Slice)
686+
})
687+
688+
t.Run("array without default", func(t *testing.T) {
689+
var s struct {
690+
Array [1]int `form:"array"`
691+
}
692+
693+
// field present but empty
694+
err := mappingByPtr(&s, formSource{"array": {}}, "form")
695+
require.NoError(t, err)
696+
assert.Equal(t, [1]int{0}, s.Array)
697+
})
698+
699+
t.Run("slice with collection format", func(t *testing.T) {
700+
var s struct {
701+
SliceMulti []int `form:"slice_multi,default=1;2;3" collection_format:"multi"`
702+
SliceCsv []int `form:"slice_csv,default=1;2;3" collection_format:"csv"`
703+
}
704+
705+
// field not present
706+
err := mappingByPtr(&s, formSource{}, "form")
707+
require.NoError(t, err)
708+
assert.Equal(t, []int{1, 2, 3}, s.SliceMulti)
709+
assert.Equal(t, []int{1, 2, 3}, s.SliceCsv)
710+
711+
// field present but empty
712+
err = mappingByPtr(&s, formSource{"slice_multi": {}, "slice_csv": {}}, "form")
713+
require.NoError(t, err)
714+
assert.Equal(t, []int{1, 2, 3}, s.SliceMulti)
715+
assert.Equal(t, []int{1, 2, 3}, s.SliceCsv)
716+
})
717+
}

0 commit comments

Comments
 (0)