Skip to content

Instantly share code, notes, and snippets.

@romsar
Last active October 11, 2022 15:48
Show Gist options
  • Save romsar/d7c31d2b6aacc0be8cb4ba69e7fea109 to your computer and use it in GitHub Desktop.
Save romsar/d7c31d2b6aacc0be8cb4ba69e7fea109 to your computer and use it in GitHub Desktop.
Golang sucessJSON (slice modifier helper for tests using dot notation)
package successjson
func successJSON(body map[string]any) func(changes ...map[string]any) []byte {
return func(changes ...map[string]any) (bs []byte) {
defer func() {
if len(bs) == 0 {
bs = []byte("{}")
}
}()
if len(changes) != 0 {
newBody := make(map[string]any, len(changes))
for k, v := range body {
newBody[k] = v
}
var ptr = newBody
var last bool
for _, change := range changes {
for key, val := range change {
pathParts := strings.Split(key, ".")
for i, path := range pathParts {
last = len(pathParts[i:]) == 1
if last {
ptr[path] = val
ptr = newBody
break
}
if _, ok := ptr[path]; ok {
if _, ok := ptr[path].(map[string]any); !ok {
ptr[path] = map[string]any{}
}
ptr = ptr[path].(map[string]any)
continue
}
ptr[path] = map[string]any{}
ptr = ptr[path].(map[string]any)
}
}
}
body = newBody
}
j, err := json.Marshal(body)
if err != nil {
return
}
bs = j
return
}
}
package successjson
func Test_successJSON(t *testing.T) {
tests := []struct {
name string
body map[string]any
changes map[string]any
want map[string]any
}{
{
name: "body nil, changes nil",
body: nil,
changes: nil,
want: map[string]any{},
},
{
name: "body nil, changes empty",
body: nil,
changes: map[string]any{},
want: map[string]any{},
},
{
name: "body nil, changes not empty",
body: nil,
changes: map[string]any{
"foo": "bar",
},
want: map[string]any{
"foo": "bar",
},
},
{
name: "body nil, changes not empty (nested)",
body: nil,
changes: map[string]any{
"abc": map[string]any{
"foo": "bar",
},
},
want: map[string]any{
"abc": map[string]any{
"foo": "bar",
},
},
},
{
name: "body not empty, changes nil",
body: map[string]any{
"foo": "bar",
},
changes: map[string]any{},
want: map[string]any{
"foo": "bar",
},
},
{
name: "body not empty, changes empty",
body: map[string]any{
"foo": "bar",
},
changes: map[string]any{},
want: map[string]any{
"foo": "bar",
},
},
{
name: "body not empty, changes not empty, but different key",
body: map[string]any{
"foo": "bar",
},
changes: map[string]any{
"abc": "zzz",
},
want: map[string]any{
"foo": "bar",
"abc": "zzz",
},
},
{
name: "body not empty, changes not empty, same key",
body: map[string]any{
"foo": "bar",
},
changes: map[string]any{
"abc": "zzz",
"foo": "ooo",
},
want: map[string]any{
"foo": "ooo",
"abc": "zzz",
},
},
{
name: "body not empty, changes not empty (nested)",
body: map[string]any{
"foo": map[string]any{
"bar": "abc",
},
},
changes: map[string]any{
"foo.bar": 123,
},
want: map[string]any{
"foo": map[string]any{
"bar": 123,
},
},
},
{
name: "body not empty, changes not empty (diff type)",
body: map[string]any{
"foo": map[string]any{
"bar": "abc",
},
},
changes: map[string]any{
"foo.bar.abc": 123,
},
want: map[string]any{
"foo": map[string]any{
"bar": map[string]any{
"abc": 123,
},
},
},
},
{
name: "super nested",
body: map[string]any{
"foo": map[string]any{
"bar": map[string]any{
"aaa": map[string]any{
"bbb": "ccc",
},
},
},
},
changes: map[string]any{
"foo.bar.abc": 111,
"foo.bar.aaa": 222,
"foo.bar.bbb.ccc": 333,
"foo.bar.bbb.vvv.fff": 444,
},
want: map[string]any{
"foo": map[string]any{
"bar": map[string]any{
"abc": 111,
"aaa": 222,
"bbb": map[string]any{
"ccc": 333,
"vvv": map[string]any{
"fff": 444,
},
},
},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s := successJSON(tt.body)
wantJSONbs, err := json.Marshal(tt.want)
require.NoError(t, err)
gotJSONbs, err := s(tt.changes)
require.NoError(t, err)
wantJSON, gotJSON := string(wantJSONbs), string(gotJSONbs)
require.Equal(t, wantJSON, gotJSON)
})
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment