Skip to content

Commit

Permalink
fix and test merges with MapSlice
Browse files Browse the repository at this point in the history
  • Loading branch information
hjdr4 committed Feb 16, 2018
1 parent d670f94 commit cae0c5c
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 8 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
debug.test
54 changes: 49 additions & 5 deletions decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -579,23 +579,41 @@ func (d *decoder) mappingSlice(n *node, out reflect.Value) (good bool) {
mapType := d.mapType
d.mapType = outt

var slice []MapItem
var l = len(n.children)
for i := 0; i < l; i += 2 {
var keys []interface{}
kv := make(map[interface{}]interface{})

for i := 0; i < len(n.children); i += 2 {
if isMerge(n.children[i]) {
d.merge(n.children[i+1], out)
for i := 0; i < out.Len(); i++ {
item := out.Index(i).Interface().(MapItem)
_, ok := kv[item.Key]
kv[item.Key] = item.Value
if !ok {
keys = append(keys, item.Key)
}
}

continue
}
item := MapItem{}
k := reflect.ValueOf(&item.Key).Elem()
if d.unmarshal(n.children[i], k) {
v := reflect.ValueOf(&item.Value).Elem()
if d.unmarshal(n.children[i+1], v) {
slice = append(slice, item)
_, ok := kv[item.Key]
kv[item.Key] = item.Value
if !ok {
keys = append(keys, item.Key)
}
}
}
}
out.Set(reflect.ValueOf(slice))
var output []MapItem
for _, key := range keys {
output = append(output, MapItem{key, kv[key]})
}
out.Set(reflect.ValueOf(output))
d.mapType = mapType
return true
}
Expand Down Expand Up @@ -662,6 +680,30 @@ func (d *decoder) merge(n *node, out reflect.Value) {
}
d.unmarshal(n, out)
case sequenceNode:
if out.Kind() == reflect.Slice {
kv := make(map[interface{}]interface{})
var keys []interface{}
for i := len(n.children) - 1; i >= 0; i-- {
d.unmarshal(n.children[i], out)
var subitems []interface{}
for j := 0; j < out.Len(); j++ {
item := out.Index(j).Interface().(MapItem)
_, ok := kv[item.Key]
kv[item.Key] = item.Value
if !ok {
subitems = append(subitems, item.Key)
}
}
keys = append(subitems, keys...)
}
var output []MapItem
for _, key := range keys {
output = append(output, MapItem{key, kv[key]})
}
out.Set(reflect.ValueOf(output))
return
}

// Step backwards as earlier nodes take precedence.
for i := len(n.children) - 1; i >= 0; i-- {
ni := n.children[i]
Expand All @@ -675,9 +717,11 @@ func (d *decoder) merge(n *node, out reflect.Value) {
}
d.unmarshal(ni, out)
}

default:
failWantMap()
}

}

func isMerge(n *node) bool {
Expand Down
28 changes: 26 additions & 2 deletions decode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ package yaml_test

import (
"errors"
. "gopkg.in/check.v1"
"gopkg.in/yaml.v2"
"math"
"net"
"reflect"
"strings"
"time"

. "gopkg.in/check.v1"
"gopkg.in/yaml.v2"
)

var unmarshalIntTest = 123
Expand Down Expand Up @@ -1002,6 +1003,29 @@ func (s *S) TestUnmarshalStrict(c *C) {
c.Check(err, ErrorMatches, "yaml: unmarshal errors:\n line 3: field c not found in struct struct { A int; B int }")
}

//It is interesting for users to have an alias to implement custom interface methods
type TestCustomMapSlice yaml.MapSlice

func (s *S) TestMergeCustomMapSlice(c *C) {
container := TestCustomMapSlice{}
err := yaml.Unmarshal([]byte(mergeTests), &container)
c.Check(err, IsNil)

var want = TestCustomMapSlice{
yaml.MapItem{Key: "x", Value: 1},
yaml.MapItem{Key: "y", Value: 2},
yaml.MapItem{Key: "r", Value: 10},
yaml.MapItem{Key: "label", Value: "center/big"},
}

for _, test := range container {
if test.Key == "anchors" {
continue
}
c.Assert(test.Value, DeepEquals, want, Commentf("test %q failed", test))
}
}

//var data []byte
//func init() {
// var err error
Expand Down
3 changes: 2 additions & 1 deletion suite_test.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package yaml_test

import (
. "gopkg.in/check.v1"
"testing"

. "gopkg.in/check.v1"
)

func Test(t *testing.T) { TestingT(t) }
Expand Down

0 comments on commit cae0c5c

Please sign in to comment.