implementing a weak decode wrapper called UnmarshalExact that errors on non existant fields in the destination struct

This commit is contained in:
dsp 2015-12-29 23:11:39 -07:00
parent dd66c894de
commit c975dc1b4e
2 changed files with 57 additions and 6 deletions

View File

@ -623,6 +623,37 @@ func (v *Viper) Unmarshal(rawVal interface{}) error {
return nil return nil
} }
// A wrapper around mapstructure.Decode that mimics the WeakDecode functionality
// while erroring on non existing vals in the destination struct
func weakDecodeExact(input, output interface{}) error {
config := &mapstructure.DecoderConfig{
ErrorUnused: true,
Metadata: nil,
Result: output,
WeaklyTypedInput: true,
}
decoder, err := mapstructure.NewDecoder(config)
if err != nil {
return err
}
return decoder.Decode(input)
}
// Unmarshals the config into a Struct, erroring if a field is non-existant
// in the destination struct
func (v *Viper) UnmarshalExact(rawVal interface{}) error {
err := weakDecodeExact(v.AllSettings(), rawVal)
if err != nil {
return err
}
v.insensitiviseMaps()
return nil
}
// Bind a full flag set to the configuration, using each flag's long // Bind a full flag set to the configuration, using each flag's long
// name as the config key. // name as the config key.
func BindPFlags(flags *pflag.FlagSet) (err error) { return v.BindPFlags(flags) } func BindPFlags(flags *pflag.FlagSet) (err error) { return v.BindPFlags(flags) }

View File

@ -37,6 +37,14 @@ eyes : brown
beard: true beard: true
`) `)
var yamlExampleWithExtras = []byte(`Existing: true
Bogus: true
`)
type testUnmarshalExtra struct {
Existing bool
}
var tomlExample = []byte(` var tomlExample = []byte(`
title = "TOML Example" title = "TOML Example"
@ -255,6 +263,18 @@ func TestUnmarshalling(t *testing.T) {
assert.Equal(t, 35, Get("age")) assert.Equal(t, 35, Get("age"))
} }
func TestUnmarshalExact(t *testing.T) {
vip := New()
target := &testUnmarshalExtra{}
vip.SetConfigType("yaml")
r := bytes.NewReader(yamlExampleWithExtras)
vip.ReadConfig(r)
err := vip.UnmarshalExact(target)
if err == nil {
t.Fatal("UnmarshalExact should error when populating a struct from a conf that contains unused fields")
}
}
func TestOverrides(t *testing.T) { func TestOverrides(t *testing.T) {
Set("age", 40) Set("age", 40)
assert.Equal(t, 40, Get("age")) assert.Equal(t, 40, Get("age"))
@ -844,14 +864,14 @@ func TestUnmarshalingWithAliases(t *testing.T) {
Set("name", "Steve") Set("name", "Steve")
Set("lastname", "Owen") Set("lastname", "Owen")
RegisterAlias("UserID","Id") RegisterAlias("UserID", "Id")
RegisterAlias("Firstname","name") RegisterAlias("Firstname", "name")
RegisterAlias("Surname","lastname") RegisterAlias("Surname", "lastname")
type config struct { type config struct {
Id int Id int
FirstName string FirstName string
Surname string Surname string
} }
var C config var C config
@ -862,4 +882,4 @@ func TestUnmarshalingWithAliases(t *testing.T) {
} }
assert.Equal(t, &C, &config{Id: 1, FirstName: "Steve", Surname: "Owen"}) assert.Equal(t, &C, &config{Id: 1, FirstName: "Steve", Surname: "Owen"})
} }