Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Backport of Fix panic caused by parsing json.Number values for TypeCommaStringSlice fields into release/1.8.x #14741

Merged
merged 3 commits into from Mar 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions changelog/14522.txt
@@ -0,0 +1,3 @@
```release-note:bug
core: Fix panic caused by parsing JSON integers for fields defined as comma-delimited strings
```
13 changes: 13 additions & 0 deletions sdk/framework/field_data_test.go
@@ -1,6 +1,7 @@
package framework

import (
"encoding/json"
"net/http"
"reflect"
"testing"
Expand Down Expand Up @@ -855,6 +856,18 @@ func TestFieldDataGet(t *testing.T) {
false,
},

"comma string slice type, single JSON number value": {
map[string]*FieldSchema{
"foo": {Type: TypeCommaStringSlice},
},
map[string]interface{}{
"foo": json.Number("123"),
},
"foo",
[]string{"123"},
false,
},

"type kv pair, not supplied": {
map[string]*FieldSchema{
"foo": {Type: TypeKVPairs},
Expand Down
5 changes: 5 additions & 0 deletions sdk/helper/parseutil/parseutil.go
Expand Up @@ -248,6 +248,11 @@ func ParseString(in interface{}) (string, error) {
}

func ParseCommaStringSlice(in interface{}) ([]string, error) {
jsonIn, ok := in.(json.Number)
if ok {
in = jsonIn.String()
}

rawString, ok := in.(string)
if ok && rawString == "" {
return []string{}, nil
Expand Down
180 changes: 180 additions & 0 deletions sdk/helper/parseutil/parseutil_test.go
Expand Up @@ -2,6 +2,7 @@ package parseutil

import (
"encoding/json"
"math/cmplx"
"testing"
"time"
)
Expand Down Expand Up @@ -282,3 +283,182 @@ func Test_ParseBool(t *testing.T) {
t.Fatal("wrong output")
}
}

func equalStringSlice(a, b []string) bool {
if len(a) != len(b) {
return false
}

for i := range a {
if a[i] != b[i] {
return false
}
}

return true
}

func Test_ParseCommaStringSlice(t *testing.T) {
cases := []struct {
name string
inp interface{}
expected []string
valid bool
}{
{
"nil",
nil,
[]string{},
true,
},
{
"empty string",
"",
[]string{},
true,
},
{
"string without commas",
"foo",
[]string{"foo"},
true,
},
{
"comma-separated string",
"foo,bar,baz",
[]string{"foo", "bar", "baz"},
true,
},
{
"comma-separated string with trim",
" foo , bar ,baz ",
[]string{"foo", "bar", "baz"},
true,
},
{
"json number",
json.Number("123"),
[]string{"123"},
true,
},
{
"int",
1,
[]string{"1"},
true,
},
{
"float",
5.5,
[]string{"5.5"},
true,
},
{
"rune",
'a',
[]string{"97"},
true,
},
{
"bool",
true,
[]string{"1"},
true,
},
{
"byte",
byte(10),
[]string{"10"},
true,
},
{
"complex",
cmplx.Sqrt(-1),
nil,
false,
},
{
"time",
time.Now(),
nil,
false,
},
{
"string slice",
[]string{"foo", "bar", "baz"},
[]string{"foo", "bar", "baz"},
true,
},
{
"json number slice",
[]json.Number{json.Number("1"), json.Number("2")},
[]string{"1", "2"},
true,
},
{
"int slice",
[]int{1, 2, 3},
[]string{"1", "2", "3"},
true,
},
{
"float slice",
[]float64{1.1, 1.2, 1.3},
[]string{"1.1", "1.2", "1.3"},
true,
},
{
"rune slice",
[]rune{'a', 'b', 'c'},
[]string{"97", "98", "99"},
true,
},
{
"bool slice",
[]bool{true, false, true},
[]string{"1", "0", "1"},
true,
},
{
"complex slice",
[]complex128{cmplx.Sqrt(-1)},
nil,
false,
},
{
"map",
map[string]interface{}{"foo": "bar"},
nil,
false,
},
{
"struct",
struct{ name string }{"foo"},
nil,
false,
},
}

for _, tc := range cases {

tc := tc

t.Run(tc.name, func(t *testing.T) {
t.Parallel()

outp, err := ParseCommaStringSlice(tc.inp)

if tc.valid && err != nil {
t.Errorf("failed to parse: %v. err: %v", tc.inp, err)
}

if !tc.valid && err == nil {
t.Errorf("no error for: %v", tc.inp)
}

if !equalStringSlice(outp, tc.expected) {
t.Errorf("input %v parsed as %v, expected %v", tc.inp, outp, tc.expected)
}
})
}
}