1// Copyright 2013 Dario Castañé. All rights reserved.
2// Copyright 2009 The Go Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style
4// license that can be found in the LICENSE file.
5
6package mergo
7
8import (
9	"io/ioutil"
10	"reflect"
11	"testing"
12	"time"
13
14	"gopkg.in/yaml.v2"
15)
16
17type simpleTest struct {
18	Value int
19}
20
21type complexTest struct {
22	St simpleTest
23	sz int
24	ID string
25}
26
27type mapTest struct {
28	M map[int]int
29}
30
31type ifcTest struct {
32	I interface{}
33}
34
35type moreComplextText struct {
36	Ct complexTest
37	St simpleTest
38	Nt simpleTest
39}
40
41type pointerTest struct {
42	C *simpleTest
43}
44
45type sliceTest struct {
46	S []int
47}
48
49func TestKb(t *testing.T) {
50	type testStruct struct {
51		Name     string
52		KeyValue map[string]interface{}
53	}
54
55	akv := make(map[string]interface{})
56	akv["Key1"] = "not value 1"
57	akv["Key2"] = "value2"
58	a := testStruct{}
59	a.Name = "A"
60	a.KeyValue = akv
61
62	bkv := make(map[string]interface{})
63	bkv["Key1"] = "value1"
64	bkv["Key3"] = "value3"
65	b := testStruct{}
66	b.Name = "B"
67	b.KeyValue = bkv
68
69	ekv := make(map[string]interface{})
70	ekv["Key1"] = "value1"
71	ekv["Key2"] = "value2"
72	ekv["Key3"] = "value3"
73	expected := testStruct{}
74	expected.Name = "B"
75	expected.KeyValue = ekv
76
77	Merge(&b, a)
78
79	if !reflect.DeepEqual(b, expected) {
80		t.Errorf("Actual: %#v did not match \nExpected: %#v", b, expected)
81	}
82}
83
84func TestNil(t *testing.T) {
85	if err := Merge(nil, nil); err != ErrNilArguments {
86		t.Fail()
87	}
88}
89
90func TestDifferentTypes(t *testing.T) {
91	a := simpleTest{42}
92	b := 42
93	if err := Merge(&a, b); err != ErrDifferentArgumentsTypes {
94		t.Fail()
95	}
96}
97
98func TestSimpleStruct(t *testing.T) {
99	a := simpleTest{}
100	b := simpleTest{42}
101	if err := Merge(&a, b); err != nil {
102		t.FailNow()
103	}
104	if a.Value != 42 {
105		t.Fatalf("b not merged in properly: a.Value(%d) != b.Value(%d)", a.Value, b.Value)
106	}
107	if !reflect.DeepEqual(a, b) {
108		t.FailNow()
109	}
110}
111
112func TestComplexStruct(t *testing.T) {
113	a := complexTest{}
114	a.ID = "athing"
115	b := complexTest{simpleTest{42}, 1, "bthing"}
116	if err := Merge(&a, b); err != nil {
117		t.FailNow()
118	}
119	if a.St.Value != 42 {
120		t.Fatalf("b not merged in properly: a.St.Value(%d) != b.St.Value(%d)", a.St.Value, b.St.Value)
121	}
122	if a.sz == 1 {
123		t.Fatalf("a's private field sz not preserved from merge: a.sz(%d) == b.sz(%d)", a.sz, b.sz)
124	}
125	if a.ID == b.ID {
126		t.Fatalf("a's field ID merged unexpectedly: a.ID(%s) == b.ID(%s)", a.ID, b.ID)
127	}
128}
129
130func TestComplexStructWithOverwrite(t *testing.T) {
131	a := complexTest{simpleTest{1}, 1, "do-not-overwrite-with-empty-value"}
132	b := complexTest{simpleTest{42}, 2, ""}
133
134	expect := complexTest{simpleTest{42}, 1, "do-not-overwrite-with-empty-value"}
135	if err := MergeWithOverwrite(&a, b); err != nil {
136		t.FailNow()
137	}
138
139	if !reflect.DeepEqual(a, expect) {
140		t.Fatalf("Test failed:\ngot  :\n%#v\n\nwant :\n%#v\n\n", a, expect)
141	}
142}
143
144func TestPointerStruct(t *testing.T) {
145	s1 := simpleTest{}
146	s2 := simpleTest{19}
147	a := pointerTest{&s1}
148	b := pointerTest{&s2}
149	if err := Merge(&a, b); err != nil {
150		t.FailNow()
151	}
152	if a.C.Value != b.C.Value {
153		t.Fatalf("b not merged in properly: a.C.Value(%d) != b.C.Value(%d)", a.C.Value, b.C.Value)
154	}
155}
156
157type embeddingStruct struct {
158	embeddedStruct
159}
160
161type embeddedStruct struct {
162	A string
163}
164
165func TestEmbeddedStruct(t *testing.T) {
166	tests := []struct {
167		src      embeddingStruct
168		dst      embeddingStruct
169		expected embeddingStruct
170	}{
171		{
172			src: embeddingStruct{
173				embeddedStruct{"foo"},
174			},
175			dst: embeddingStruct{
176				embeddedStruct{""},
177			},
178			expected: embeddingStruct{
179				embeddedStruct{"foo"},
180			},
181		},
182		{
183			src: embeddingStruct{
184				embeddedStruct{""},
185			},
186			dst: embeddingStruct{
187				embeddedStruct{"bar"},
188			},
189			expected: embeddingStruct{
190				embeddedStruct{"bar"},
191			},
192		},
193		{
194			src: embeddingStruct{
195				embeddedStruct{"foo"},
196			},
197			dst: embeddingStruct{
198				embeddedStruct{"bar"},
199			},
200			expected: embeddingStruct{
201				embeddedStruct{"bar"},
202			},
203		},
204	}
205
206	for _, test := range tests {
207		err := Merge(&test.dst, test.src)
208		if err != nil {
209			t.Errorf("unexpected error: %v", err)
210			continue
211		}
212		if !reflect.DeepEqual(test.dst, test.expected) {
213			t.Errorf("unexpected output\nexpected:\n%+v\nsaw:\n%+v\n", test.expected, test.dst)
214		}
215	}
216}
217
218func TestPointerStructNil(t *testing.T) {
219	a := pointerTest{nil}
220	b := pointerTest{&simpleTest{19}}
221	if err := Merge(&a, b); err != nil {
222		t.FailNow()
223	}
224	if a.C.Value != b.C.Value {
225		t.Fatalf("b not merged in a properly: a.C.Value(%d) != b.C.Value(%d)", a.C.Value, b.C.Value)
226	}
227}
228
229func testSlice(t *testing.T, a []int, b []int, e []int, opts ...func(*Config)) {
230	t.Helper()
231	bc := b
232
233	sa := sliceTest{a}
234	sb := sliceTest{b}
235	if err := Merge(&sa, sb, opts...); err != nil {
236		t.FailNow()
237	}
238	if !reflect.DeepEqual(sb.S, bc) {
239		t.Fatalf("Source slice was modified %d != %d", sb.S, bc)
240	}
241	if !reflect.DeepEqual(sa.S, e) {
242		t.Fatalf("b not merged in a proper way %d != %d", sa.S, e)
243	}
244
245	ma := map[string][]int{"S": a}
246	mb := map[string][]int{"S": b}
247	if err := Merge(&ma, mb, opts...); err != nil {
248		t.FailNow()
249	}
250	if !reflect.DeepEqual(mb["S"], bc) {
251		t.Fatalf("map value: Source slice was modified %d != %d", mb["S"], bc)
252	}
253	if !reflect.DeepEqual(ma["S"], e) {
254		t.Fatalf("map value: b not merged in a proper way %d != %d", ma["S"], e)
255	}
256
257	if a == nil {
258		// test case with missing dst key
259		ma := map[string][]int{}
260		mb := map[string][]int{"S": b}
261		if err := Merge(&ma, mb); err != nil {
262			t.FailNow()
263		}
264		if !reflect.DeepEqual(mb["S"], bc) {
265			t.Fatalf("missing dst key: Source slice was modified %d != %d", mb["S"], bc)
266		}
267		if !reflect.DeepEqual(ma["S"], e) {
268			t.Fatalf("missing dst key: b not merged in a proper way %d != %d", ma["S"], e)
269		}
270	}
271
272	if b == nil {
273		// test case with missing src key
274		ma := map[string][]int{"S": a}
275		mb := map[string][]int{}
276		if err := Merge(&ma, mb); err != nil {
277			t.FailNow()
278		}
279		if !reflect.DeepEqual(mb["S"], bc) {
280			t.Fatalf("missing src key: Source slice was modified %d != %d", mb["S"], bc)
281		}
282		if !reflect.DeepEqual(ma["S"], e) {
283			t.Fatalf("missing src key: b not merged in a proper way %d != %d", ma["S"], e)
284		}
285	}
286}
287
288func TestSlice(t *testing.T) {
289	testSlice(t, nil, []int{1, 2, 3}, []int{1, 2, 3})
290	testSlice(t, []int{}, []int{1, 2, 3}, []int{1, 2, 3})
291	testSlice(t, []int{1}, []int{2, 3}, []int{1})
292	testSlice(t, []int{1}, []int{}, []int{1})
293	testSlice(t, []int{1}, nil, []int{1})
294	testSlice(t, nil, []int{1, 2, 3}, []int{1, 2, 3}, WithAppendSlice)
295	testSlice(t, []int{}, []int{1, 2, 3}, []int{1, 2, 3}, WithAppendSlice)
296	testSlice(t, []int{1}, []int{2, 3}, []int{1, 2, 3}, WithAppendSlice)
297	testSlice(t, []int{1}, []int{}, []int{1}, WithAppendSlice)
298	testSlice(t, []int{1}, nil, []int{1}, WithAppendSlice)
299}
300
301func TestEmptyMaps(t *testing.T) {
302	a := mapTest{}
303	b := mapTest{
304		map[int]int{},
305	}
306	if err := Merge(&a, b); err != nil {
307		t.Fail()
308	}
309	if !reflect.DeepEqual(a, b) {
310		t.FailNow()
311	}
312}
313
314func TestEmptyToEmptyMaps(t *testing.T) {
315	a := mapTest{}
316	b := mapTest{}
317	if err := Merge(&a, b); err != nil {
318		t.Fail()
319	}
320	if !reflect.DeepEqual(a, b) {
321		t.FailNow()
322	}
323}
324
325func TestEmptyToNotEmptyMaps(t *testing.T) {
326	a := mapTest{map[int]int{
327		1: 2,
328		3: 4,
329	}}
330	aa := mapTest{map[int]int{
331		1: 2,
332		3: 4,
333	}}
334	b := mapTest{
335		map[int]int{},
336	}
337	if err := Merge(&a, b); err != nil {
338		t.Fail()
339	}
340	if !reflect.DeepEqual(a, aa) {
341		t.FailNow()
342	}
343}
344
345func TestMapsWithOverwrite(t *testing.T) {
346	m := map[string]simpleTest{
347		"a": {},   // overwritten by 16
348		"b": {42}, // not overwritten by empty value
349		"c": {13}, // overwritten by 12
350		"d": {61},
351	}
352	n := map[string]simpleTest{
353		"a": {16},
354		"b": {},
355		"c": {12},
356		"e": {14},
357	}
358	expect := map[string]simpleTest{
359		"a": {16},
360		"b": {},
361		"c": {12},
362		"d": {61},
363		"e": {14},
364	}
365
366	if err := MergeWithOverwrite(&m, n); err != nil {
367		t.Fatalf(err.Error())
368	}
369
370	if !reflect.DeepEqual(m, expect) {
371		t.Fatalf("Test failed:\ngot  :\n%#v\n\nwant :\n%#v\n\n", m, expect)
372	}
373}
374
375func TestMaps(t *testing.T) {
376	m := map[string]simpleTest{
377		"a": {},
378		"b": {42},
379		"c": {13},
380		"d": {61},
381	}
382	n := map[string]simpleTest{
383		"a": {16},
384		"b": {},
385		"c": {12},
386		"e": {14},
387	}
388	expect := map[string]simpleTest{
389		"a": {0},
390		"b": {42},
391		"c": {13},
392		"d": {61},
393		"e": {14},
394	}
395
396	if err := Merge(&m, n); err != nil {
397		t.Fatalf(err.Error())
398	}
399
400	if !reflect.DeepEqual(m, expect) {
401		t.Fatalf("Test failed:\ngot  :\n%#v\n\nwant :\n%#v\n\n", m, expect)
402	}
403	if m["a"].Value != 0 {
404		t.Fatalf(`n merged in m because I solved non-addressable map values TODO: m["a"].Value(%d) != n["a"].Value(%d)`, m["a"].Value, n["a"].Value)
405	}
406	if m["b"].Value != 42 {
407		t.Fatalf(`n wrongly merged in m: m["b"].Value(%d) != n["b"].Value(%d)`, m["b"].Value, n["b"].Value)
408	}
409	if m["c"].Value != 13 {
410		t.Fatalf(`n overwritten in m: m["c"].Value(%d) != n["c"].Value(%d)`, m["c"].Value, n["c"].Value)
411	}
412}
413
414func TestMapsWithNilPointer(t *testing.T) {
415	m := map[string]*simpleTest{
416		"a": nil,
417		"b": nil,
418	}
419	n := map[string]*simpleTest{
420		"b": nil,
421		"c": nil,
422	}
423	expect := map[string]*simpleTest{
424		"a": nil,
425		"b": nil,
426		"c": nil,
427	}
428
429	if err := Merge(&m, n, WithOverride); err != nil {
430		t.Fatalf(err.Error())
431	}
432
433	if !reflect.DeepEqual(m, expect) {
434		t.Fatalf("Test failed:\ngot   :\n%#v\n\nwant :\n%#v\n\n", m, expect)
435	}
436}
437
438func TestYAMLMaps(t *testing.T) {
439	thing := loadYAML("testdata/thing.yml")
440	license := loadYAML("testdata/license.yml")
441	ft := thing["fields"].(map[interface{}]interface{})
442	fl := license["fields"].(map[interface{}]interface{})
443	// license has one extra field (site) and another already existing in thing (author) that Mergo won't override.
444	expectedLength := len(ft) + len(fl) - 1
445	if err := Merge(&license, thing); err != nil {
446		t.Fatal(err.Error())
447	}
448	currentLength := len(license["fields"].(map[interface{}]interface{}))
449	if currentLength != expectedLength {
450		t.Fatalf(`thing not merged in license properly, license must have %d elements instead of %d`, expectedLength, currentLength)
451	}
452	fields := license["fields"].(map[interface{}]interface{})
453	if _, ok := fields["id"]; !ok {
454		t.Fatalf(`thing not merged in license properly, license must have a new id field from thing`)
455	}
456}
457
458func TestTwoPointerValues(t *testing.T) {
459	a := &simpleTest{}
460	b := &simpleTest{42}
461	if err := Merge(a, b); err != nil {
462		t.Fatalf(`Boom. You crossed the streams: %s`, err)
463	}
464}
465
466func TestMap(t *testing.T) {
467	a := complexTest{}
468	a.ID = "athing"
469	c := moreComplextText{a, simpleTest{}, simpleTest{}}
470	b := map[string]interface{}{
471		"ct": map[string]interface{}{
472			"st": map[string]interface{}{
473				"value": 42,
474			},
475			"sz": 1,
476			"id": "bthing",
477		},
478		"st": &simpleTest{144}, // Mapping a reference
479		"zt": simpleTest{299},  // Mapping a missing field (zt doesn't exist)
480		"nt": simpleTest{3},
481	}
482	if err := Map(&c, b); err != nil {
483		t.FailNow()
484	}
485	m := b["ct"].(map[string]interface{})
486	n := m["st"].(map[string]interface{})
487	o := b["st"].(*simpleTest)
488	p := b["nt"].(simpleTest)
489	if c.Ct.St.Value != 42 {
490		t.Fatalf("b not merged in properly: c.Ct.St.Value(%d) != b.Ct.St.Value(%d)", c.Ct.St.Value, n["value"])
491	}
492	if c.St.Value != 144 {
493		t.Fatalf("b not merged in properly: c.St.Value(%d) != b.St.Value(%d)", c.St.Value, o.Value)
494	}
495	if c.Nt.Value != 3 {
496		t.Fatalf("b not merged in properly: c.Nt.Value(%d) != b.Nt.Value(%d)", c.St.Value, p.Value)
497	}
498	if c.Ct.sz == 1 {
499		t.Fatalf("a's private field sz not preserved from merge: c.Ct.sz(%d) == b.Ct.sz(%d)", c.Ct.sz, m["sz"])
500	}
501	if c.Ct.ID == m["id"] {
502		t.Fatalf("a's field ID merged unexpectedly: c.Ct.ID(%s) == b.Ct.ID(%s)", c.Ct.ID, m["id"])
503	}
504}
505
506func TestSimpleMap(t *testing.T) {
507	a := simpleTest{}
508	b := map[string]interface{}{
509		"value": 42,
510	}
511	if err := Map(&a, b); err != nil {
512		t.FailNow()
513	}
514	if a.Value != 42 {
515		t.Fatalf("b not merged in properly: a.Value(%d) != b.Value(%v)", a.Value, b["value"])
516	}
517}
518
519func TestIfcMap(t *testing.T) {
520	a := ifcTest{}
521	b := ifcTest{42}
522	if err := Map(&a, b); err != nil {
523		t.FailNow()
524	}
525	if a.I != 42 {
526		t.Fatalf("b not merged in properly: a.I(%d) != b.I(%d)", a.I, b.I)
527	}
528	if !reflect.DeepEqual(a, b) {
529		t.FailNow()
530	}
531}
532
533func TestIfcMapNoOverwrite(t *testing.T) {
534	a := ifcTest{13}
535	b := ifcTest{42}
536	if err := Map(&a, b); err != nil {
537		t.FailNow()
538	}
539	if a.I != 13 {
540		t.Fatalf("a not left alone: a.I(%d) == b.I(%d)", a.I, b.I)
541	}
542}
543
544func TestIfcMapWithOverwrite(t *testing.T) {
545	a := ifcTest{13}
546	b := ifcTest{42}
547	if err := MapWithOverwrite(&a, b); err != nil {
548		t.FailNow()
549	}
550	if a.I != 42 {
551		t.Fatalf("b not merged in properly: a.I(%d) != b.I(%d)", a.I, b.I)
552	}
553	if !reflect.DeepEqual(a, b) {
554		t.FailNow()
555	}
556}
557
558type pointerMapTest struct {
559	A      int
560	hidden int
561	B      *simpleTest
562}
563
564func TestBackAndForth(t *testing.T) {
565	pt := pointerMapTest{42, 1, &simpleTest{66}}
566	m := make(map[string]interface{})
567	if err := Map(&m, pt); err != nil {
568		t.FailNow()
569	}
570	var (
571		v  interface{}
572		ok bool
573	)
574	if v, ok = m["a"]; v.(int) != pt.A || !ok {
575		t.Fatalf("pt not merged in properly: m[`a`](%d) != pt.A(%d)", v, pt.A)
576	}
577	if v, ok = m["b"]; !ok {
578		t.Fatalf("pt not merged in properly: B is missing in m")
579	}
580	var st *simpleTest
581	if st = v.(*simpleTest); st.Value != 66 {
582		t.Fatalf("something went wrong while mapping pt on m, B wasn't copied")
583	}
584	bpt := pointerMapTest{}
585	if err := Map(&bpt, m); err != nil {
586		t.Fatal(err)
587	}
588	if bpt.A != pt.A {
589		t.Fatalf("pt not merged in properly: bpt.A(%d) != pt.A(%d)", bpt.A, pt.A)
590	}
591	if bpt.hidden == pt.hidden {
592		t.Fatalf("pt unexpectedly merged: bpt.hidden(%d) == pt.hidden(%d)", bpt.hidden, pt.hidden)
593	}
594	if bpt.B.Value != pt.B.Value {
595		t.Fatalf("pt not merged in properly: bpt.B.Value(%d) != pt.B.Value(%d)", bpt.B.Value, pt.B.Value)
596	}
597}
598
599func TestEmbeddedPointerUnpacking(t *testing.T) {
600	tests := []struct{ input pointerMapTest }{
601		{pointerMapTest{42, 1, nil}},
602		{pointerMapTest{42, 1, &simpleTest{66}}},
603	}
604	newValue := 77
605	m := map[string]interface{}{
606		"b": map[string]interface{}{
607			"value": newValue,
608		},
609	}
610	for _, test := range tests {
611		pt := test.input
612		if err := MapWithOverwrite(&pt, m); err != nil {
613			t.FailNow()
614		}
615		if pt.B.Value != newValue {
616			t.Fatalf("pt not mapped properly: pt.A.Value(%d) != m[`b`][`value`](%d)", pt.B.Value, newValue)
617		}
618
619	}
620}
621
622type structWithTimePointer struct {
623	Birth *time.Time
624}
625
626func TestTime(t *testing.T) {
627	now := time.Now()
628	dataStruct := structWithTimePointer{
629		Birth: &now,
630	}
631	dataMap := map[string]interface{}{
632		"Birth": &now,
633	}
634	b := structWithTimePointer{}
635	if err := Merge(&b, dataStruct); err != nil {
636		t.FailNow()
637	}
638	if b.Birth.IsZero() {
639		t.Fatalf("time.Time not merged in properly: b.Birth(%v) != dataStruct['Birth'](%v)", b.Birth, dataStruct.Birth)
640	}
641	if b.Birth != dataStruct.Birth {
642		t.Fatalf("time.Time not merged in properly: b.Birth(%v) != dataStruct['Birth'](%v)", b.Birth, dataStruct.Birth)
643	}
644	b = structWithTimePointer{}
645	if err := Map(&b, dataMap); err != nil {
646		t.FailNow()
647	}
648	if b.Birth.IsZero() {
649		t.Fatalf("time.Time not merged in properly: b.Birth(%v) != dataMap['Birth'](%v)", b.Birth, dataMap["Birth"])
650	}
651}
652
653type simpleNested struct {
654	A int
655}
656
657type structWithNestedPtrValueMap struct {
658	NestedPtrValue map[string]*simpleNested
659}
660
661func TestNestedPtrValueInMap(t *testing.T) {
662	src := &structWithNestedPtrValueMap{
663		NestedPtrValue: map[string]*simpleNested{
664			"x": {
665				A: 1,
666			},
667		},
668	}
669	dst := &structWithNestedPtrValueMap{
670		NestedPtrValue: map[string]*simpleNested{
671			"x": {},
672		},
673	}
674	if err := Map(dst, src); err != nil {
675		t.FailNow()
676	}
677	if dst.NestedPtrValue["x"].A == 0 {
678		t.Fatalf("Nested Ptr value not merged in properly: dst.NestedPtrValue[\"x\"].A(%v) != src.NestedPtrValue[\"x\"].A(%v)", dst.NestedPtrValue["x"].A, src.NestedPtrValue["x"].A)
679	}
680}
681
682func loadYAML(path string) (m map[string]interface{}) {
683	m = make(map[string]interface{})
684	raw, _ := ioutil.ReadFile(path)
685	_ = yaml.Unmarshal(raw, &m)
686	return
687}
688
689type structWithMap struct {
690	m map[string]structWithUnexportedProperty
691}
692
693type structWithUnexportedProperty struct {
694	s string
695}
696
697func TestUnexportedProperty(t *testing.T) {
698	a := structWithMap{map[string]structWithUnexportedProperty{
699		"key": {"hello"},
700	}}
701	b := structWithMap{map[string]structWithUnexportedProperty{
702		"key": {"hi"},
703	}}
704	defer func() {
705		if r := recover(); r != nil {
706			t.Errorf("Should not have panicked")
707		}
708	}()
709	Merge(&a, b)
710}
711
712type structWithBoolPointer struct {
713	C *bool
714}
715
716func TestBooleanPointer(t *testing.T) {
717	bt, bf := true, false
718	src := structWithBoolPointer{
719		&bt,
720	}
721	dst := structWithBoolPointer{
722		&bf,
723	}
724	if err := Merge(&dst, src); err != nil {
725		t.FailNow()
726	}
727	if dst.C == src.C {
728		t.Fatalf("dst.C should be a different pointer than src.C")
729	}
730	if *dst.C != *src.C {
731		t.Fatalf("dst.C should be true")
732	}
733}
734