From e87ec33070058ccef4396f6ba5e6ab7c42a80e38 Mon Sep 17 00:00:00 2001 From: x0Lazarus <113273587+x0Lazarus@users.noreply.github.com> Date: Sat, 26 Sep 2026 13:27:26 -0700 Subject: [PATCH 1/2] Preserve null values when converting nil containers to JSON --- conversions.go | 15 +++++++++++ conversions_nil_test.go | 60 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 conversions_nil_test.go diff --git a/conversions.go b/conversions.go index 01c63d7..7ba478e 100644 --- a/conversions.go +++ b/conversions.go @@ -60,6 +60,9 @@ func (m Map) JSON() (string, error) { } func cleanUpInterfaceArray(in []interface{}) []interface{} { + if in == nil { + return nil + } result := make([]interface{}, len(in)) for i, v := range in { result[i] = cleanUp(v) @@ -68,6 +71,9 @@ func cleanUpInterfaceArray(in []interface{}) []interface{} { } func cleanUpInterfaceMap(in map[interface{}]interface{}) Map { + if in == nil { + return nil + } result := Map{} for k, v := range in { result[fmt.Sprintf("%v", k)] = cleanUp(v) @@ -76,6 +82,9 @@ func cleanUpInterfaceMap(in map[interface{}]interface{}) Map { } func cleanUpStringMap(in map[string]interface{}) Map { + if in == nil { + return nil + } result := Map{} for k, v := range in { result[k] = cleanUp(v) @@ -84,6 +93,9 @@ func cleanUpStringMap(in map[string]interface{}) Map { } func cleanUpMSIArray(in []map[string]interface{}) []Map { + if in == nil { + return nil + } result := make([]Map, len(in)) for i, v := range in { result[i] = cleanUpStringMap(v) @@ -92,6 +104,9 @@ func cleanUpMSIArray(in []map[string]interface{}) []Map { } func cleanUpMapArray(in []Map) []Map { + if in == nil { + return nil + } result := make([]Map, len(in)) for i, v := range in { result[i] = cleanUpStringMap(v) diff --git a/conversions_nil_test.go b/conversions_nil_test.go new file mode 100644 index 0000000..2ab8868 --- /dev/null +++ b/conversions_nil_test.go @@ -0,0 +1,60 @@ +package objx_test + +import ( + "encoding/base64" + "testing" + + "github.com/stretchr/objx" +) + +func TestConversionJSONPreservesNilContainers(t *testing.T) { + tests := []struct { + name string + value interface{} + json string + }{ + {"nil interface slice", []interface{}(nil), "null"}, + {"nil map slice", []objx.Map(nil), "null"}, + {"nil string map slice", []map[string]interface{}(nil), "null"}, + {"nil map", objx.Map(nil), "null"}, + {"nil interface map", map[interface{}]interface{}(nil), "null"}, + {"nil string map", map[string]interface{}(nil), "null"}, + {"nil string slice", []string(nil), "null"}, + {"nil interface", nil, "null"}, + {"empty interface slice", []interface{}{}, "[]"}, + {"empty map slice", []objx.Map{}, "[]"}, + {"empty string map slice", []map[string]interface{}{}, "[]"}, + {"empty map", objx.Map{}, "{}"}, + {"empty interface map", map[interface{}]interface{}{}, "{}"}, + {"populated interface slice", []interface{}{1}, "[1]"}, + {"populated map slice", []objx.Map{{"key": "value"}}, `[{"key":"value"}]`}, + {"populated string map slice", []map[string]interface{}{{"key": "value"}}, `[{"key":"value"}]`}, + {"populated map", objx.Map{"key": "value"}, `{"key":"value"}`}, + {"populated interface map", map[interface{}]interface{}{1: "value"}, `{"1":"value"}`}, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + for _, context := range []struct { + name string + input objx.Map + want string + }{ + {"direct", objx.Map{"value": test.value}, `{"value":` + test.json + `}`}, + {"in slice", objx.Map{"value": []interface{}{test.value}}, `{"value":[` + test.json + `]}`}, + {"in map", objx.Map{"value": objx.Map{"nested": test.value}}, `{"value":{"nested":` + test.json + `}}`}, + } { + t.Run(context.name, func(t *testing.T) { + got, err := context.input.JSON() + require.NoError(t, err) + assert.Equal(t, context.want, got) + assert.Equal(t, context.want, context.input.MustJSON()) + encoded, err := context.input.Base64() + require.NoError(t, err) + decoded, err := base64.StdEncoding.DecodeString(encoded) + require.NoError(t, err) + assert.Equal(t, context.want, string(decoded)) + }) + } + }) + } +} From cd81ef546a7be2b43c691ace168164eb6c5f5fa0 Mon Sep 17 00:00:00 2001 From: x0Lazarus <113273587+x0Lazarus@users.noreply.github.com> Date: Mon, 28 Sep 2026 12:50:44 -0700 Subject: [PATCH 2/2] test: run JSON container cases in parallel --- conversions_nil_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/conversions_nil_test.go b/conversions_nil_test.go index 2ab8868..6ef72f8 100644 --- a/conversions_nil_test.go +++ b/conversions_nil_test.go @@ -33,7 +33,9 @@ func TestConversionJSONPreservesNilContainers(t *testing.T) { {"populated interface map", map[interface{}]interface{}{1: "value"}, `{"1":"value"}`}, } for _, test := range tests { + test := test t.Run(test.name, func(t *testing.T) { + t.Parallel() for _, context := range []struct { name string input objx.Map