Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(decoder-configs): add flag to force decoding nil input in decoder config #42

Merged
merged 27 commits into from
Sep 20, 2024
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
0c945d4
Add ForceDecoding Flag To Decoder Config
mahadzaryab1 Aug 24, 2024
045a4ff
Add Test Cases
mahadzaryab1 Aug 24, 2024
31e4de7
Fix Documentation
mahadzaryab1 Aug 24, 2024
6381ebf
Remove Extra Check
mahadzaryab1 Aug 24, 2024
f841385
Do Not Override Zero Fields Check
mahadzaryab1 Aug 24, 2024
7a6796a
Use Map As Input For Tests
mahadzaryab1 Aug 24, 2024
9ffa15f
Rename Flag And Simplify godoc
mahadzaryab1 Aug 24, 2024
57a5bba
Fix Test Name
mahadzaryab1 Aug 24, 2024
022e0dc
Fix Wording of godoc
mahadzaryab1 Aug 24, 2024
d0b44fb
Use interface{} Instead of map[string]interface{}
mahadzaryab1 Aug 24, 2024
ebd5641
Fix Test Case
mahadzaryab1 Aug 24, 2024
3a956c9
Fix Variable Name
mahadzaryab1 Aug 24, 2024
c20b1ab
Fix godoc
mahadzaryab1 Aug 24, 2024
04189fe
Address Feedback From PR Review
mahadzaryab1 Aug 26, 2024
8078296
Change Logic To Set InputVal And Not Erase OutputVal
mahadzaryab1 Aug 27, 2024
5a595df
Add Additional Test With Type Hook
mahadzaryab1 Aug 27, 2024
7072f97
Add Extra Test Case And Extract Bool Expression Into Variable
mahadzaryab1 Aug 27, 2024
1253cd5
Fix Typo
mahadzaryab1 Aug 27, 2024
5d56b9c
Add More Test Cases
mahadzaryab1 Aug 27, 2024
72963fc
Rename Variable
mahadzaryab1 Aug 27, 2024
b0357fa
Fix Test Case
mahadzaryab1 Aug 27, 2024
30f2b22
Address Feedback From PR Review
mahadzaryab1 Aug 27, 2024
817e61e
Simplify Test Strings
mahadzaryab1 Aug 27, 2024
40f8be1
Use More Descriptive Test Name
mahadzaryab1 Aug 27, 2024
39ae1f1
Add Test Cases For Append Hook
mahadzaryab1 Sep 15, 2024
2ff30a1
Run Linter
mahadzaryab1 Sep 19, 2024
d1548f8
Remove Debug Statement
mahadzaryab1 Sep 19, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion mapstructure.go
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,10 @@ type DecoderConfig struct {
// field name or tag. Defaults to `strings.EqualFold`. This can be used
// to implement case-sensitive tag values, support snake casing, etc.
MatchName func(mapKey, fieldName string) bool

// DecodeNil, if set to true, will try to perform decoding on the input even
// if the input is nil.
mahadzaryab1 marked this conversation as resolved.
Show resolved Hide resolved
DecodeNil bool
}

// A Decoder takes a raw interface value and turns it into structured
Expand Down Expand Up @@ -461,7 +465,10 @@ func (d *Decoder) decode(name string, input interface{}, outVal reflect.Value) e
d.config.Metadata.Keys = append(d.config.Metadata.Keys, name)
}
}
return nil

if !d.config.DecodeNil || d.config.DecodeHook == nil {
mahadzaryab1 marked this conversation as resolved.
Show resolved Hide resolved
return nil
}
mahadzaryab1 marked this conversation as resolved.
Show resolved Hide resolved
}

if !inputVal.IsValid() {
Expand Down
105 changes: 105 additions & 0 deletions mapstructure_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3083,6 +3083,111 @@ func TestDecoder_IgnoreUntaggedFieldsWithStruct(t *testing.T) {
}
}

func TestDecoder_DecodeNil(t *testing.T) {
t.Parallel()

type Transformed struct {
Message string
}

var nilInput *Transformed

tests := []struct {
name string
decodeNil bool
input interface{}
expectedResult Transformed
decodeHook DecodeHookFunc
}{
{
name: "decodeNil=true for nil input with hook",
decodeNil: true,
input: nilInput,
mahadzaryab1 marked this conversation as resolved.
Show resolved Hide resolved
decodeHook: func(f, t reflect.Type, v interface{}) (interface{}, error) {
return Transformed{Message: "hello world!"}, nil
},
expectedResult: Transformed{Message: "hello world!"},
},
{
name: "decodeNil=true for nil input without hook",
decodeNil: true,
input: nilInput,
expectedResult: Transformed{Message: ""},
},
{
name: "decodeNil=false for nil input with hook",
decodeNil: false,
input: nilInput,
decodeHook: func(f, t reflect.Type, v interface{}) (interface{}, error) {
return Transformed{Message: "hello world!"}, nil
},
expectedResult: Transformed{Message: ""},
},
{
name: "decodeNil=false for nil input without hook",
decodeNil: false,
input: nilInput,
expectedResult: Transformed{Message: ""},
},
{
name: "decodeNil=true for non-nil input without hook",
decodeNil: true,
input: map[string]interface{}{"message": "this is a message"},
expectedResult: Transformed{Message: "this is a message"},
},
{
name: "decodeNil=true for non-nil input with hook",
decodeNil: true,
input: map[string]interface{}{"message": "this is a message"},
decodeHook: func(f, t reflect.Type, v interface{}) (interface{}, error) {
return Transformed{Message: "this is another message"}, nil
},
expectedResult: Transformed{Message: "this is another message"},
},
{
name: "decodeNil=false for non-nil input without hook",
decodeNil: false,
input: map[string]interface{}{"message": "this is a message"},
expectedResult: Transformed{Message: "this is a message"},
},
{
name: "decodeNil=false for non-nil input with hook",
decodeNil: false,
input: map[string]interface{}{"message": "this is a message"},
decodeHook: func(f, t reflect.Type, v interface{}) (interface{}, error) {
return Transformed{Message: "this is another message"}, nil
},
expectedResult: Transformed{Message: "this is another message"},
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {

var result Transformed
mahadzaryab1 marked this conversation as resolved.
Show resolved Hide resolved
config := &DecoderConfig{
Result: &result,
DecodeNil: test.decodeNil,
DecodeHook: test.decodeHook,
}

decoder, err := NewDecoder(config)
if err != nil {
t.Fatalf("err: %s", err)
}

err = decoder.Decode(test.input)
if err != nil {
mahadzaryab1 marked this conversation as resolved.
Show resolved Hide resolved
t.Fatalf("got an err: %s", err)
}

if result != test.expectedResult {
t.Errorf("result should be: %#v, got %#v", test.expectedResult, result)
}
})
}
}

func testSliceInput(t *testing.T, input map[string]interface{}, expected *Slice) {
var result Slice
err := Decode(input, &result)
Expand Down