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