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

Add a function to disable unique keys #752

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
70 changes: 70 additions & 0 deletions decode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1644,6 +1644,76 @@ func (s *S) TestFuzzCrashers(c *C) {
}
}

var unmarshalDisableUniqueKeys = []struct {
known bool
unique bool
data string
value interface{}
error string
}{{
unique: true,
data: "a: 1\nb: 2\na: 3\n",
value: struct{ A, B int }{A: 3, B: 2},
error: `yaml: unmarshal errors:\n line 3: mapping key "a" already defined at line 1`,
}, {
unique: false,
data: "a: 1\nb: 2\na: 3\n",
value: struct{ A, B int }{A: 3, B: 2},
error: "",
}, {
unique: true,
data: "c: 3\na: 1\nb: 2\nc: 4\n",
value: struct {
A int
inlineB `yaml:",inline"`
}{
A: 1,
inlineB: inlineB{
B: 2,
inlineC: inlineC{
C: 4,
},
},
},
error: `yaml: unmarshal errors:\n line 4: mapping key "c" already defined at line 1`,
}, {
unique: false,
data: "c: 3\na: 1\nb: 2\nc: 4\n",
value: struct {
A int
inlineB `yaml:",inline"`
}{
A: 1,
inlineB: inlineB{
B: 2,
inlineC: inlineC{
C: 4,
},
},
},
error: "",
}}

func (s *S) TestDisableUniqueKeys(c *C) {
for i, item := range unmarshalDisableUniqueKeys {
c.Logf("test %d: %q", i, item.data)
t := reflect.ValueOf(item.value).Type()
value := reflect.New(t)
dec := yaml.NewDecoder(bytes.NewBuffer([]byte(item.data)))
dec.KnownFields(item.known)
if !item.unique {
dec.DisableUniqueKeys(true)
}
err := dec.Decode(value.Interface())
if !item.unique {
c.Assert(err, Equals, nil)
c.Assert(value.Elem().Interface(), DeepEquals, item.value)
} else {
c.Assert(err, ErrorMatches, item.error)
}
}
}

//var data []byte
//func init() {
// var err error
Expand Down
12 changes: 10 additions & 2 deletions yaml.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,9 @@ func Unmarshal(in []byte, out interface{}) (err error) {

// A Decoder reads and decodes YAML values from an input stream.
type Decoder struct {
parser *parser
knownFields bool
parser *parser
knownFields bool
disableUniqueKeys bool
}

// NewDecoder returns a new decoder that reads from r.
Expand All @@ -111,6 +112,12 @@ func (dec *Decoder) KnownFields(enable bool) {
dec.knownFields = enable
}

// DisableUniqueKeys ensure function Decode not to return errors when keys exist
// more than once inside the given mapping.
func (dec *Decoder) DisableUniqueKeys(enable bool) {
dec.disableUniqueKeys = enable
}

// Decode reads the next YAML-encoded value from its input
// and stores it in the value pointed to by v.
//
Expand All @@ -119,6 +126,7 @@ func (dec *Decoder) KnownFields(enable bool) {
func (dec *Decoder) Decode(v interface{}) (err error) {
d := newDecoder()
d.knownFields = dec.knownFields
d.uniqueKeys = !dec.disableUniqueKeys
defer handleErr(&err)
node := dec.parser.parse()
if node == nil {
Expand Down