From ca55de97859c0ebfcfe3b63172f3e47809bf7b4d Mon Sep 17 00:00:00 2001 From: Mark Sagi-Kazar Date: Fri, 8 Dec 2023 18:59:35 +0100 Subject: [PATCH] fix: Unmarshal struct decoding when passing in a pointer to a pointer Signed-off-by: Mark Sagi-Kazar --- viper.go | 7 +++++++ viper_test.go | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/viper.go b/viper.go index 122280b..11edded 100644 --- a/viper.go +++ b/viper.go @@ -1127,6 +1127,13 @@ func (v *Viper) Unmarshal(rawVal any, opts ...DecoderConfigOption) error { func (v *Viper) decodeStructKeys(input any, opts ...DecoderConfigOption) ([]string, error) { var structKeyMap map[string]any + rv := reflect.ValueOf(input) + for rv.Kind() == reflect.Ptr { + rv = reflect.Indirect(rv) + } + + input = rv.Interface() + err := decode(input, defaultDecoderConfig(&structKeyMap, opts...)) if err != nil { return nil, err diff --git a/viper_test.go b/viper_test.go index 4dc52ac..f0d1474 100644 --- a/viper_test.go +++ b/viper_test.go @@ -1080,6 +1080,48 @@ func TestUnmarshalWithAutomaticEnv(t *testing.T) { }) } +func TestUnmarshalIndirection(t *testing.T) { + v := New() + + v.Set("foo", "bar") + + type config struct { + Foo string + } + + var C config + + CC := &C + CCC := &CC + + err := v.Unmarshal(&CCC) + require.NoError(t, err) + + assert.Equal(t, config{"bar"}, C) +} + +func TestUnmarshalInterface(t *testing.T) { + v := New() + + v.Set("foo", "bar") + + type someInterface interface { + Foo() string + } + + type config struct { + Foo string + Fooer someInterface + } + + var C config + + err := v.Unmarshal(&C) + require.NoError(t, err) + + assert.Equal(t, config{Foo: "bar"}, C) +} + func TestBindPFlags(t *testing.T) { v := New() // create independent Viper object flagSet := pflag.NewFlagSet("test", pflag.ContinueOnError)