From e33e70c1de6a4fd9bb5e79251dbb344b2695f4cf Mon Sep 17 00:00:00 2001 From: Carlo Ruiz Date: Sun, 9 Oct 2022 14:44:44 -0400 Subject: [PATCH] slices: update Int.Scan() to parse empty slices Previously, Int.Scan() returned the slice '[0]' when reading an empty slice of ints from the database. This is a bug, as the output should also be empty. This patch fixes the bug and adds regression tests. Additionally, the code is updated to percolate up the errors from integer to string conversion, which was previously swallowed. --- slices/int.go | 25 +++++++++++++++++++------ slices/int_test.go | 30 ++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 6 deletions(-) create mode 100644 slices/int_test.go diff --git a/slices/int.go b/slices/int.go index cf72719c..e800fcbd 100644 --- a/slices/int.go +++ b/slices/int.go @@ -27,8 +27,10 @@ func (i *Int) Scan(src interface{}) error { default: return fmt.Errorf("scan source was not []byte nor string but %T", src) } - *i = strToInt(str) - return nil + + v, err := strToInt(str) + *i = v + return err } // Value implements the driver.Valuer interface. @@ -56,12 +58,23 @@ func (i *Int) UnmarshalText(text []byte) error { return nil } -func strToInt(s string) []int { +func strToInt(s string) ([]int, error) { r := strings.Trim(s, "{}") a := make([]int, 0, 10) - for _, t := range strings.Split(r, ",") { - i, _ := strconv.Atoi(t) + + split := strings.Split(r, ",") + // Split returns [""] when splitting the empty string. + if len(split) == 1 && split[0] == "" { + return a, nil + } + + for _, t := range split { + i, err := strconv.Atoi(t) + if err != nil { + return nil, err + } a = append(a, i) } - return a + + return a, nil } diff --git a/slices/int_test.go b/slices/int_test.go new file mode 100644 index 00000000..4218c6b4 --- /dev/null +++ b/slices/int_test.go @@ -0,0 +1,30 @@ +package slices + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func Test_Int_Scan(t *testing.T) { + r := require.New(t) + t.Run("empty slice", func(t *testing.T) { + in := "{}" + v := &Int{} + r.NoError(v.Scan(in)) + r.Len(*v, 0) + }) + + t.Run("non-empty slice", func(t *testing.T) { + in := "{44,55}" + v := &Int{} + r.NoError(v.Scan(in)) + r.Equal([]int(*v), []int{44, 55}) + }) + + t.Run("invalid entry", func(t *testing.T) { + in := "{44,word}" + v := &Int{} + r.Error(v.Scan(in)) + }) +}