Last active
October 11, 2022 15:48
-
-
Save romsar/d7c31d2b6aacc0be8cb4ba69e7fea109 to your computer and use it in GitHub Desktop.
Golang sucessJSON (slice modifier helper for tests using dot notation)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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