From 2899bb19b8ff274f1056f19efe2bb3cfe59d0709 Mon Sep 17 00:00:00 2001 From: Martin Helmich Date: Fri, 5 Jan 2024 11:37:10 +0100 Subject: [PATCH] Fix panic when a nil *uuid.UUID is provided --- go.mod | 1 + go.sum | 2 ++ internal/valueutil/string.go | 19 ++++++++++++++++++- internal/valueutil/string_test.go | 31 +++++++++++++++++++++++++++++++ 4 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 internal/valueutil/string_test.go diff --git a/go.mod b/go.mod index 30daa14..4f2a151 100644 --- a/go.mod +++ b/go.mod @@ -65,6 +65,7 @@ require ( github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect github.com/oklog/run v1.0.0 // indirect + github.com/onsi/gomega v1.30.0 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect github.com/posener/complete v1.2.3 // indirect github.com/russross/blackfriday v1.6.0 // indirect diff --git a/go.sum b/go.sum index b1a37fb..7af9296 100644 --- a/go.sum +++ b/go.sum @@ -192,6 +192,8 @@ github.com/oapi-codegen/runtime v1.1.0 h1:rJpoNUawn5XTvekgfkvSZr0RqEnoYpFkyvrzfW github.com/oapi-codegen/runtime v1.1.0/go.mod h1:BeSfBkWWWnAnGdyS+S/GnlbmHKzf8/hwkvelJZDeKA8= github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= +github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8= +github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s= github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw= github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4= diff --git a/internal/valueutil/string.go b/internal/valueutil/string.go index 324a485..e14a850 100644 --- a/internal/valueutil/string.go +++ b/internal/valueutil/string.go @@ -3,6 +3,7 @@ package valueutil import ( "fmt" "github.com/hashicorp/terraform-plugin-framework/types" + "reflect" ) func StringOrNull[T string](s T) types.String { @@ -20,8 +21,24 @@ func StringPtrOrNull[T ~string](s *T) types.String { } func StringerOrNull(s fmt.Stringer) types.String { - if s == nil { + if isReallyNil(s) { return types.StringNull() } return types.StringValue(s.String()) } + +func isReallyNil(v any) bool { + if v == nil { + return true + } + + rv := reflect.ValueOf(v) + switch rv.Kind() { + case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice: + return rv.IsNil() + case reflect.Array: + return rv.Len() == 0 + default: + return false + } +} diff --git a/internal/valueutil/string_test.go b/internal/valueutil/string_test.go new file mode 100644 index 0000000..03d9399 --- /dev/null +++ b/internal/valueutil/string_test.go @@ -0,0 +1,31 @@ +package valueutil + +import ( + "github.com/google/uuid" + . "github.com/onsi/gomega" + "testing" +) + +func TestStringerOrNullAcceptsStringer(t *testing.T) { + g := NewWithT(t) + u := uuid.New() + s := StringerOrNull(u) + + g.Expect(s.IsNull()).To(BeFalse()) + g.Expect(s.ValueString()).To(Equal(u.String())) +} + +func TestStringerOrNullAcceptsNil(t *testing.T) { + g := NewWithT(t) + s := StringerOrNull(nil) + + g.Expect(s.IsNull()).To(BeTrue()) +} + +func TestStringerOrNullAcceptsNilInterface(t *testing.T) { + g := NewWithT(t) + u := (*uuid.UUID)(nil) + s := StringerOrNull(u) + + g.Expect(s.IsNull()).To(BeTrue()) +}