Zero destination struct in `convert.ToTyped` (#1178)

## Changes

Not doing this means that the output struct is not a true representation
of the `dyn.Value` and unrepresentable state (e.g. unexported fields)
can be carried over across `convert.ToTyped` calls.

## Tests

Unit tests.
This commit is contained in:
Pieter Noordhuis 2024-02-07 10:25:53 +01:00 committed by GitHub
parent dcb9c85201
commit 0b5fdcc346
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 25 additions and 0 deletions

View File

@ -53,6 +53,10 @@ func ToTyped(dst any, src dyn.Value) error {
func toTypedStruct(dst reflect.Value, src dyn.Value) error { func toTypedStruct(dst reflect.Value, src dyn.Value) error {
switch src.Kind() { switch src.Kind() {
case dyn.KindMap: case dyn.KindMap:
// Zero the destination struct such that fields
// that aren't present in [src] are cleared.
dst.SetZero()
info := getStructInfo(dst.Type()) info := getStructInfo(dst.Type())
for k, v := range src.MustMap() { for k, v := range src.MustMap() {
index, ok := info.Fields[k] index, ok := info.Fields[k]

View File

@ -59,6 +59,27 @@ func TestToTypedStructOverwrite(t *testing.T) {
assert.Equal(t, "baz", out.Bar) assert.Equal(t, "baz", out.Bar)
} }
func TestToTypedStructClearFields(t *testing.T) {
type Tmp struct {
Foo string `json:"foo"`
Bar string `json:"bar,omitempty"`
}
// Struct value with non-empty fields.
var out = Tmp{
Foo: "baz",
Bar: "qux",
}
// Value is an empty map.
v := dyn.V(map[string]dyn.Value{})
// The previously set fields should be cleared.
err := ToTyped(&out, v)
require.NoError(t, err)
assert.Equal(t, Tmp{}, out)
}
func TestToTypedStructAnonymousByValue(t *testing.T) { func TestToTypedStructAnonymousByValue(t *testing.T) {
type Bar struct { type Bar struct {
Bar string `json:"bar"` Bar string `json:"bar"`