fleet/pkg/optjson/stringor_test.go

255 lines
7.2 KiB
Go
Raw Normal View History

package optjson
import (
"encoding/json"
"testing"
"github.com/stretchr/testify/require"
)
func TestStringOr(t *testing.T) {
type child struct {
Name string `json:"name"`
}
type target struct {
Field StringOr[[]string] `json:"field"`
Array []StringOr[*child] `json:"array"`
}
type nested struct {
Inception StringOr[*target] `json:"inception"`
}
cases := []struct {
name string
getVar func() any
src string // json source to unmarshal into the value returned by getVar
marshalAs string // how the value should marshal back to json
unmarshalErr string // if non-empty, unmarshal should fail with this error
}{
{
name: "simple string",
getVar: func() any { var s StringOr[int]; return &s },
src: `"abc"`,
marshalAs: `"abc"`,
},
{
name: "simple integer",
getVar: func() any { var s StringOr[int]; return &s },
src: `123`,
marshalAs: `123`,
},
{
name: "invalid bool",
getVar: func() any { var s StringOr[int]; return &s },
src: `true`,
unmarshalErr: "cannot unmarshal bool into Go value of type int",
},
{
name: "field string",
getVar: func() any { var s target; return &s },
src: `{"field":"abc"}`,
marshalAs: `{"field":"abc", "array": null}`,
},
{
name: "field strings",
getVar: func() any { var s target; return &s },
src: `{"field":["a", "b", "c"]}`,
marshalAs: `{"field":["a", "b", "c"], "array": null}`,
},
{
name: "field empty array",
getVar: func() any { var s target; return &s },
src: `{"field":[]}`,
marshalAs: `{"field":[], "array": null}`,
},
{
name: "field invalid object",
getVar: func() any { var s target; return &s },
src: `{"field":{}}`,
unmarshalErr: "cannot unmarshal object into Go struct field target.field of type []string",
},
{
name: "array field null",
getVar: func() any { var s target; return &s },
src: `{"array":null}`,
marshalAs: `{"array":null, "field": ""}`,
},
{
name: "array field empty",
getVar: func() any { var s target; return &s },
src: `{"array":[]}`,
marshalAs: `{"array":[], "field": ""}`,
},
{
name: "array field single",
getVar: func() any { var s target; return &s },
src: `{"array":["a"]}`,
marshalAs: `{"array":["a"], "field": ""}`,
},
{
name: "array field empty child",
getVar: func() any { var s target; return &s },
src: `{"array":["a", {}]}`,
marshalAs: `{"array":["a", {"name":""}], "field": ""}`,
},
{
name: "array field set child",
getVar: func() any { var s target; return &s },
src: `{"array":["a", {"name": "x"}]}`,
marshalAs: `{"array":["a", {"name":"x"}], "field": ""}`,
},
{
name: "inception string",
getVar: func() any { var s nested; return &s },
src: `{"inception":"a"}`,
marshalAs: `{"inception":"a"}`,
},
{
name: "inception target field",
getVar: func() any { var s nested; return &s },
src: `{"inception":{"field":["a", "b"]}}`,
marshalAs: `{"inception":{"field":["a", "b"], "array": null}}`,
},
{
name: "inception target field and array",
getVar: func() any { var s nested; return &s },
src: `{"inception":{"field":["a", "b"], "array": ["c", {"name": "x"}]}}`,
marshalAs: `{"inception":{"field":["a", "b"], "array": ["c", {"name": "x"}]}}`,
},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
target := c.getVar()
err := json.Unmarshal([]byte(c.src), target)
if c.unmarshalErr != "" {
require.ErrorContains(t, err, c.unmarshalErr)
return
}
require.NoError(t, err)
data, err := json.Marshal(target)
require.NoError(t, err)
require.JSONEq(t, c.marshalAs, string(data))
})
}
}
func TestBoolOr(t *testing.T) {
type child struct {
Name string `json:"name"`
}
type target struct {
Field BoolOr[*child] `json:"field"`
Array []BoolOr[*child] `json:"array"`
}
type nested struct {
Inception BoolOr[*target] `json:"inception"`
}
cases := []struct {
name string
getVar func() any
src string // json source to unmarshal into the value returned by getVar
marshalAs string // how the value should marshal back to json
unmarshalErr string // if non-empty, unmarshal should fail with this error
}{
{
name: "simple bool",
getVar: func() any { var s BoolOr[int]; return &s },
src: `true`,
marshalAs: `true`,
},
{
name: "simple integer",
getVar: func() any { var s BoolOr[int]; return &s },
src: `123`,
marshalAs: `123`,
},
{
name: "field bool",
getVar: func() any { var s target; return &s },
src: `{"field":true}`,
marshalAs: `{"field":true, "array": null}`,
},
{
name: "field object",
getVar: func() any { var s target; return &s },
src: `{"field":{"name": "field object"}}`,
marshalAs: `{"field":{"name": "field object"}, "array": null}`,
},
{
name: "field empty object",
getVar: func() any { var s target; return &s },
src: `{"field":{}}`,
marshalAs: `{"field":{"name": ""}, "array": null}`,
},
{
name: "field invalid array",
getVar: func() any { var s target; return &s },
src: `{"field":[]}`,
unmarshalErr: "cannot unmarshal array into Go struct field target.field of type optjson.child",
},
{
name: "array field null",
getVar: func() any { var s target; return &s },
src: `{"array":null}`,
marshalAs: `{"array":null, "field": false}`,
},
{
name: "array field empty",
getVar: func() any { var s target; return &s },
src: `{"array":[]}`,
marshalAs: `{"array":[], "field": false}`,
},
{
name: "array field single",
getVar: func() any { var s target; return &s },
src: `{"array":[{"name": "array child"}]}`,
marshalAs: `{"array":[{"name": "array child"}], "field": false}`,
},
{
name: "array field empty child",
getVar: func() any { var s target; return &s },
src: `{"array":[{}]}`,
marshalAs: `{"array":[{"name":""}], "field": false}`,
},
{
name: "inception bool",
getVar: func() any { var s nested; return &s },
src: `{"inception":true}`,
marshalAs: `{"inception":true}`,
},
{
name: "inception target field",
getVar: func() any { var s nested; return &s },
src: `{"inception":{"field":{"name":""}}}`,
marshalAs: `{"inception":{"field":{"name": ""}, "array": null}}`,
},
{
name: "inception target field and array",
getVar: func() any { var s nested; return &s },
src: `{"inception":{"field":{"name":"inception field"}, "array": [{"name": "x"}]}}`,
marshalAs: `{"inception":{"field":{"name":"inception field"}, "array": [{"name": "x"}]}}`,
},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
target := c.getVar()
err := json.Unmarshal([]byte(c.src), target)
if c.unmarshalErr != "" {
require.ErrorContains(t, err, c.unmarshalErr)
return
}
require.NoError(t, err)
data, err := json.Marshal(target)
require.NoError(t, err)
require.JSONEq(t, c.marshalAs, string(data))
})
}
}