Skip to content

Commit 0b8c27e

Browse files
andy-miraclvdemeester
authored andcommitted
Slices should append not overwrite
1 parent 7fe0c75 commit 0b8c27e

File tree

2 files changed

+70
-15
lines changed

2 files changed

+70
-15
lines changed

merge.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,18 @@ func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, ov
8787
if err = deepMerge(dstElement, srcElement, visited, depth+1, overwrite); err != nil {
8888
return
8989
}
90+
case reflect.Slice:
91+
srcSlice := reflect.ValueOf(srcElement.Interface())
92+
93+
var dstSlice reflect.Value
94+
if !dstElement.IsValid() || dstElement.IsNil() {
95+
dstSlice = reflect.MakeSlice(srcSlice.Type(), 0, srcSlice.Len())
96+
} else {
97+
dstSlice = reflect.ValueOf(dstElement.Interface())
98+
}
99+
100+
dstSlice = reflect.AppendSlice(dstSlice, srcSlice)
101+
dst.SetMapIndex(key, dstSlice)
90102
}
91103
}
92104
if dstElement.IsValid() && reflect.TypeOf(srcElement.Interface()).Kind() == reflect.Map {
@@ -100,6 +112,8 @@ func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, ov
100112
dst.SetMapIndex(key, srcElement)
101113
}
102114
}
115+
case reflect.Slice:
116+
dst.Set(reflect.AppendSlice(dst, src))
103117
case reflect.Ptr:
104118
fallthrough
105119
case reflect.Interface:

mergo_test.go

Lines changed: 56 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -225,30 +225,71 @@ func TestPointerStructNil(t *testing.T) {
225225
}
226226
}
227227

228-
func TestSliceStruct(t *testing.T) {
229-
a := sliceTest{}
230-
b := sliceTest{[]int{1, 2, 3}}
231-
if err := Merge(&a, b); err != nil {
228+
func testSlice(t *testing.T, a []int, b []int) {
229+
bc := b
230+
e := append(a, b...)
231+
232+
sa := sliceTest{a}
233+
sb := sliceTest{b}
234+
if err := Merge(&sa, sb); err != nil {
232235
t.FailNow()
233236
}
234-
if len(b.S) != 3 {
235-
t.FailNow()
237+
if !reflect.DeepEqual(sb.S, bc) {
238+
t.Fatalf("Source slice was modified %d != %d", sb.S, bc)
236239
}
237-
if len(a.S) != len(b.S) {
238-
t.Fatalf("b not merged in a proper way %d != %d", len(a.S), len(b.S))
240+
if !reflect.DeepEqual(sa.S, e) {
241+
t.Fatalf("b not merged in a proper way %d != %d", sa.S, e)
239242
}
240243

241-
a = sliceTest{[]int{1}}
242-
b = sliceTest{[]int{1, 2, 3}}
243-
if err := Merge(&a, b); err != nil {
244+
ma := map[string][]int{"S": a}
245+
mb := map[string][]int{"S": b}
246+
if err := Merge(&ma, mb); err != nil {
244247
t.FailNow()
245248
}
246-
if len(a.S) != 1 {
247-
t.FailNow()
249+
if !reflect.DeepEqual(mb["S"], bc) {
250+
t.Fatalf("Source slice was modified %d != %d", mb["S"], bc)
248251
}
249-
if len(a.S) == len(b.S) {
250-
t.Fatalf("b merged unexpectedly %d != %d", len(a.S), len(b.S))
252+
if !reflect.DeepEqual(ma["S"], e) {
253+
t.Fatalf("b not merged in a proper way %d != %d", ma["S"], e)
251254
}
255+
256+
if a == nil {
257+
// test case with missing dst key
258+
ma := map[string][]int{}
259+
mb := map[string][]int{"S": b}
260+
if err := Merge(&ma, mb); err != nil {
261+
t.FailNow()
262+
}
263+
if !reflect.DeepEqual(mb["S"], bc) {
264+
t.Fatalf("Source slice was modified %d != %d", mb["S"], bc)
265+
}
266+
if !reflect.DeepEqual(ma["S"], e) {
267+
t.Fatalf("b not merged in a proper way %d != %d", ma["S"], e)
268+
}
269+
}
270+
271+
if b == nil {
272+
// test case with missing src key
273+
ma := map[string][]int{"S": a}
274+
mb := map[string][]int{}
275+
if err := Merge(&ma, mb); err != nil {
276+
t.FailNow()
277+
}
278+
if !reflect.DeepEqual(mb["S"], bc) {
279+
t.Fatalf("Source slice was modified %d != %d", mb["S"], bc)
280+
}
281+
if !reflect.DeepEqual(ma["S"], e) {
282+
t.Fatalf("b not merged in a proper way %d != %d", ma["S"], e)
283+
}
284+
}
285+
}
286+
287+
func TestSlice(t *testing.T) {
288+
testSlice(t, nil, []int{1, 2, 3})
289+
testSlice(t, []int{}, []int{1, 2, 3})
290+
testSlice(t, []int{1}, []int{2, 3})
291+
testSlice(t, []int{1}, []int{})
292+
testSlice(t, []int{1}, nil)
252293
}
253294

254295
func TestEmptyMaps(t *testing.T) {

0 commit comments

Comments
 (0)