...

Source file src/dario.cat/mergo/mergo_test.go

Documentation: dario.cat/mergo

     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  
     6  package mergo_test
     7  
     8  import (
     9  	"io/ioutil"
    10  	"reflect"
    11  	"strings"
    12  	"testing"
    13  	"time"
    14  
    15  	"dario.cat/mergo"
    16  	"gopkg.in/yaml.v3"
    17  )
    18  
    19  type simpleTest struct {
    20  	Value int
    21  }
    22  
    23  type complexTest struct {
    24  	ID string
    25  	St simpleTest
    26  	sz int
    27  }
    28  
    29  type mapTest struct {
    30  	M map[int]int
    31  }
    32  
    33  type ifcTest struct {
    34  	I interface{}
    35  }
    36  
    37  type moreComplextText struct {
    38  	Ct complexTest
    39  	St simpleTest
    40  	Nt simpleTest
    41  }
    42  
    43  type pointerTest struct {
    44  	C *simpleTest
    45  }
    46  
    47  type sliceTest struct {
    48  	S []int
    49  }
    50  
    51  func TestKb(t *testing.T) {
    52  	type testStruct struct {
    53  		KeyValue map[string]interface{}
    54  		Name     string
    55  	}
    56  
    57  	akv := make(map[string]interface{})
    58  	akv["Key1"] = "not value 1"
    59  	akv["Key2"] = "value2"
    60  	a := testStruct{}
    61  	a.Name = "A"
    62  	a.KeyValue = akv
    63  
    64  	bkv := make(map[string]interface{})
    65  	bkv["Key1"] = "value1"
    66  	bkv["Key3"] = "value3"
    67  	b := testStruct{}
    68  	b.Name = "B"
    69  	b.KeyValue = bkv
    70  
    71  	ekv := make(map[string]interface{})
    72  	ekv["Key1"] = "value1"
    73  	ekv["Key2"] = "value2"
    74  	ekv["Key3"] = "value3"
    75  	expected := testStruct{}
    76  	expected.Name = "B"
    77  	expected.KeyValue = ekv
    78  
    79  	if err := mergo.Merge(&b, a); err != nil {
    80  		t.Error(err)
    81  	}
    82  
    83  	if !reflect.DeepEqual(b, expected) {
    84  		t.Errorf("Actual: %#v did not match \nExpected: %#v", b, expected)
    85  	}
    86  }
    87  
    88  func TestNil(t *testing.T) {
    89  	if err := mergo.Merge(nil, nil); err != mergo.ErrNilArguments {
    90  		t.Fail()
    91  	}
    92  }
    93  
    94  func TestDifferentTypes(t *testing.T) {
    95  	a := simpleTest{42}
    96  	b := 42
    97  	if err := mergo.Merge(&a, b); err != mergo.ErrDifferentArgumentsTypes {
    98  		t.Fail()
    99  	}
   100  }
   101  
   102  func TestSimpleStruct(t *testing.T) {
   103  	a := simpleTest{}
   104  	b := simpleTest{42}
   105  	if err := mergo.Merge(&a, b); err != nil {
   106  		t.FailNow()
   107  	}
   108  	if a.Value != 42 {
   109  		t.Errorf("b not merged in properly: a.Value(%d) != b.Value(%d)", a.Value, b.Value)
   110  	}
   111  	if !reflect.DeepEqual(a, b) {
   112  		t.FailNow()
   113  	}
   114  }
   115  
   116  func TestComplexStruct(t *testing.T) {
   117  	a := complexTest{}
   118  	a.ID = "athing"
   119  	b := complexTest{"bthing", simpleTest{42}, 1}
   120  	if err := mergo.Merge(&a, b); err != nil {
   121  		t.FailNow()
   122  	}
   123  	if a.St.Value != 42 {
   124  		t.Errorf("b not merged in properly: a.St.Value(%d) != b.St.Value(%d)", a.St.Value, b.St.Value)
   125  	}
   126  	if a.sz == 1 {
   127  		t.Errorf("a's private field sz not preserved from merge: a.sz(%d) == b.sz(%d)", a.sz, b.sz)
   128  	}
   129  	if a.ID == b.ID {
   130  		t.Errorf("a's field ID merged unexpectedly: a.ID(%s) == b.ID(%s)", a.ID, b.ID)
   131  	}
   132  }
   133  
   134  func TestComplexStructWithOverwrite(t *testing.T) {
   135  	a := complexTest{"do-not-overwrite-with-empty-value", simpleTest{1}, 1}
   136  	b := complexTest{"", simpleTest{42}, 2}
   137  
   138  	expect := complexTest{"do-not-overwrite-with-empty-value", simpleTest{42}, 1}
   139  	if err := mergo.MergeWithOverwrite(&a, b); err != nil {
   140  		t.FailNow()
   141  	}
   142  
   143  	if !reflect.DeepEqual(a, expect) {
   144  		t.Errorf("Test failed:\ngot  :\n%#v\n\nwant :\n%#v\n\n", a, expect)
   145  	}
   146  }
   147  
   148  func TestPointerStruct(t *testing.T) {
   149  	s1 := simpleTest{}
   150  	s2 := simpleTest{19}
   151  	a := pointerTest{&s1}
   152  	b := pointerTest{&s2}
   153  	if err := mergo.Merge(&a, b); err != nil {
   154  		t.FailNow()
   155  	}
   156  	if a.C.Value != b.C.Value {
   157  		t.Errorf("b not merged in properly: a.C.Value(%d) != b.C.Value(%d)", a.C.Value, b.C.Value)
   158  	}
   159  }
   160  
   161  type embeddingStruct struct {
   162  	embeddedStruct
   163  }
   164  
   165  type embeddedStruct struct {
   166  	A string
   167  }
   168  
   169  func TestEmbeddedStruct(t *testing.T) {
   170  	tests := []struct {
   171  		src      embeddingStruct
   172  		dst      embeddingStruct
   173  		expected embeddingStruct
   174  	}{
   175  		{
   176  			src: embeddingStruct{
   177  				embeddedStruct{"foo"},
   178  			},
   179  			dst: embeddingStruct{
   180  				embeddedStruct{""},
   181  			},
   182  			expected: embeddingStruct{
   183  				embeddedStruct{"foo"},
   184  			},
   185  		},
   186  		{
   187  			src: embeddingStruct{
   188  				embeddedStruct{""},
   189  			},
   190  			dst: embeddingStruct{
   191  				embeddedStruct{"bar"},
   192  			},
   193  			expected: embeddingStruct{
   194  				embeddedStruct{"bar"},
   195  			},
   196  		},
   197  		{
   198  			src: embeddingStruct{
   199  				embeddedStruct{"foo"},
   200  			},
   201  			dst: embeddingStruct{
   202  				embeddedStruct{"bar"},
   203  			},
   204  			expected: embeddingStruct{
   205  				embeddedStruct{"bar"},
   206  			},
   207  		},
   208  	}
   209  
   210  	for _, test := range tests {
   211  		err := mergo.Merge(&test.dst, test.src)
   212  		if err != nil {
   213  			t.Errorf("unexpected error: %v", err)
   214  			continue
   215  		}
   216  		if !reflect.DeepEqual(test.dst, test.expected) {
   217  			t.Errorf("unexpected output\nexpected:\n%+v\nsaw:\n%+v\n", test.expected, test.dst)
   218  		}
   219  	}
   220  }
   221  
   222  func TestPointerStructNil(t *testing.T) {
   223  	a := pointerTest{nil}
   224  	b := pointerTest{&simpleTest{19}}
   225  	if err := mergo.Merge(&a, b); err != nil {
   226  		t.FailNow()
   227  	}
   228  	if a.C.Value != b.C.Value {
   229  		t.Errorf("b not merged in a properly: a.C.Value(%d) != b.C.Value(%d)", a.C.Value, b.C.Value)
   230  	}
   231  }
   232  
   233  func testSlice(t *testing.T, a []int, b []int, e []int, opts ...func(*mergo.Config)) {
   234  	t.Helper()
   235  	bc := b
   236  
   237  	sa := sliceTest{a}
   238  	sb := sliceTest{b}
   239  	if err := mergo.Merge(&sa, sb, opts...); err != nil {
   240  		t.FailNow()
   241  	}
   242  	if !reflect.DeepEqual(sb.S, bc) {
   243  		t.Errorf("Source slice was modified %d != %d", sb.S, bc)
   244  	}
   245  	if !reflect.DeepEqual(sa.S, e) {
   246  		t.Errorf("b not merged in a proper way %d != %d", sa.S, e)
   247  	}
   248  
   249  	ma := map[string][]int{"S": a}
   250  	mb := map[string][]int{"S": b}
   251  	if err := mergo.Merge(&ma, mb, opts...); err != nil {
   252  		t.FailNow()
   253  	}
   254  	if !reflect.DeepEqual(mb["S"], bc) {
   255  		t.Errorf("map value: Source slice was modified %d != %d", mb["S"], bc)
   256  	}
   257  	if !reflect.DeepEqual(ma["S"], e) {
   258  		t.Errorf("map value: b not merged in a proper way %d != %d", ma["S"], e)
   259  	}
   260  
   261  	if a == nil {
   262  		// test case with missing dst key
   263  		ma := map[string][]int{}
   264  		mb := map[string][]int{"S": b}
   265  		if err := mergo.Merge(&ma, mb); err != nil {
   266  			t.FailNow()
   267  		}
   268  		if !reflect.DeepEqual(mb["S"], bc) {
   269  			t.Errorf("missing dst key: Source slice was modified %d != %d", mb["S"], bc)
   270  		}
   271  		if !reflect.DeepEqual(ma["S"], e) {
   272  			t.Errorf("missing dst key: b not merged in a proper way %d != %d", ma["S"], e)
   273  		}
   274  	}
   275  
   276  	if b == nil {
   277  		// test case with missing src key
   278  		ma := map[string][]int{"S": a}
   279  		mb := map[string][]int{}
   280  		if err := mergo.Merge(&ma, mb); err != nil {
   281  			t.FailNow()
   282  		}
   283  		if !reflect.DeepEqual(mb["S"], bc) {
   284  			t.Errorf("missing src key: Source slice was modified %d != %d", mb["S"], bc)
   285  		}
   286  		if !reflect.DeepEqual(ma["S"], e) {
   287  			t.Errorf("missing src key: b not merged in a proper way %d != %d", ma["S"], e)
   288  		}
   289  	}
   290  }
   291  
   292  func TestSlice(t *testing.T) {
   293  	testSlice(t, nil, []int{1, 2, 3}, []int{1, 2, 3})
   294  	testSlice(t, []int{}, []int{1, 2, 3}, []int{1, 2, 3})
   295  	testSlice(t, []int{1}, []int{2, 3}, []int{1})
   296  	testSlice(t, []int{1}, []int{}, []int{1})
   297  	testSlice(t, []int{1}, nil, []int{1})
   298  	testSlice(t, nil, []int{1, 2, 3}, []int{1, 2, 3}, mergo.WithAppendSlice)
   299  	testSlice(t, []int{}, []int{1, 2, 3}, []int{1, 2, 3}, mergo.WithAppendSlice)
   300  	testSlice(t, []int{1}, []int{2, 3}, []int{1, 2, 3}, mergo.WithAppendSlice)
   301  	testSlice(t, []int{1}, []int{2, 3}, []int{1, 2, 3}, mergo.WithAppendSlice, mergo.WithOverride)
   302  	testSlice(t, []int{1}, []int{}, []int{1}, mergo.WithAppendSlice)
   303  	testSlice(t, []int{1}, nil, []int{1}, mergo.WithAppendSlice)
   304  }
   305  
   306  func TestEmptyMaps(t *testing.T) {
   307  	a := mapTest{}
   308  	b := mapTest{
   309  		map[int]int{},
   310  	}
   311  	if err := mergo.Merge(&a, b); err != nil {
   312  		t.Fail()
   313  	}
   314  	if !reflect.DeepEqual(a, b) {
   315  		t.FailNow()
   316  	}
   317  }
   318  
   319  func TestEmptyToEmptyMaps(t *testing.T) {
   320  	a := mapTest{}
   321  	b := mapTest{}
   322  	if err := mergo.Merge(&a, b); err != nil {
   323  		t.Fail()
   324  	}
   325  	if !reflect.DeepEqual(a, b) {
   326  		t.FailNow()
   327  	}
   328  }
   329  
   330  func TestEmptyToNotEmptyMaps(t *testing.T) {
   331  	a := mapTest{map[int]int{
   332  		1: 2,
   333  		3: 4,
   334  	}}
   335  	aa := mapTest{map[int]int{
   336  		1: 2,
   337  		3: 4,
   338  	}}
   339  	b := mapTest{
   340  		map[int]int{},
   341  	}
   342  	if err := mergo.Merge(&a, b); err != nil {
   343  		t.Fail()
   344  	}
   345  	if !reflect.DeepEqual(a, aa) {
   346  		t.FailNow()
   347  	}
   348  }
   349  
   350  func TestMapsWithOverwrite(t *testing.T) {
   351  	m := map[string]simpleTest{
   352  		"a": {},   // overwritten by 16
   353  		"b": {42}, // overwritten by 0, as map Value is not addressable and it doesn't check for b is set or not set in `n`
   354  		"c": {13}, // overwritten by 12
   355  		"d": {61},
   356  	}
   357  	n := map[string]simpleTest{
   358  		"a": {16},
   359  		"b": {},
   360  		"c": {12},
   361  		"e": {14},
   362  	}
   363  	expect := map[string]simpleTest{
   364  		"a": {16},
   365  		"b": {},
   366  		"c": {12},
   367  		"d": {61},
   368  		"e": {14},
   369  	}
   370  
   371  	if err := mergo.MergeWithOverwrite(&m, n); err != nil {
   372  		t.Errorf(err.Error())
   373  	}
   374  
   375  	if !reflect.DeepEqual(m, expect) {
   376  		t.Errorf("Test failed:\ngot  :\n%#v\n\nwant :\n%#v\n\n", m, expect)
   377  	}
   378  }
   379  
   380  func TestMapWithEmbeddedStructPointer(t *testing.T) {
   381  	m := map[string]*simpleTest{
   382  		"a": {},   // overwritten by 16
   383  		"b": {42}, // not overwritten by empty value
   384  		"c": {13}, // overwritten by 12
   385  		"d": {61},
   386  	}
   387  	n := map[string]*simpleTest{
   388  		"a": {16},
   389  		"b": {},
   390  		"c": {12},
   391  		"e": {14},
   392  	}
   393  	expect := map[string]*simpleTest{
   394  		"a": {16},
   395  		"b": {42},
   396  		"c": {12},
   397  		"d": {61},
   398  		"e": {14},
   399  	}
   400  
   401  	if err := mergo.Merge(&m, n, mergo.WithOverride); err != nil {
   402  		t.Errorf(err.Error())
   403  	}
   404  
   405  	if !reflect.DeepEqual(m, expect) {
   406  		t.Errorf("Test failed:\ngot  :\n%#v\n\nwant :\n%#v\n\n", m, expect)
   407  	}
   408  }
   409  
   410  func TestMergeUsingStructAndMap(t *testing.T) {
   411  	type multiPtr struct {
   412  		Text   string
   413  		Number int
   414  	}
   415  	type final struct {
   416  		Msg1 string
   417  		Msg2 string
   418  	}
   419  	type params struct {
   420  		Multi *multiPtr
   421  		Final *final
   422  		Name  string
   423  	}
   424  	type config struct {
   425  		Params *params
   426  		Foo    string
   427  		Bar    string
   428  	}
   429  
   430  	cases := []struct {
   431  		changes   *config
   432  		target    *config
   433  		output    *config
   434  		name      string
   435  		overwrite bool
   436  	}{
   437  		{
   438  			name:      "Should overwrite values in target for non-nil values in source",
   439  			overwrite: true,
   440  			changes: &config{
   441  				Bar: "from changes",
   442  				Params: &params{
   443  					Final: &final{
   444  						Msg1: "from changes",
   445  						Msg2: "from changes",
   446  					},
   447  				},
   448  			},
   449  			target: &config{
   450  				Foo: "from target",
   451  				Params: &params{
   452  					Name: "from target",
   453  					Multi: &multiPtr{
   454  						Text:   "from target",
   455  						Number: 5,
   456  					},
   457  					Final: &final{
   458  						Msg1: "from target",
   459  						Msg2: "",
   460  					},
   461  				},
   462  			},
   463  			output: &config{
   464  				Foo: "from target",
   465  				Bar: "from changes",
   466  				Params: &params{
   467  					Name: "from target",
   468  					Multi: &multiPtr{
   469  						Text:   "from target",
   470  						Number: 5,
   471  					},
   472  					Final: &final{
   473  						Msg1: "from changes",
   474  						Msg2: "from changes",
   475  					},
   476  				},
   477  			},
   478  		},
   479  		{
   480  			name:      "Should not overwrite values in target for non-nil values in source",
   481  			overwrite: false,
   482  			changes: &config{
   483  				Bar: "from changes",
   484  				Params: &params{
   485  					Final: &final{
   486  						Msg1: "from changes",
   487  						Msg2: "from changes",
   488  					},
   489  				},
   490  			},
   491  			target: &config{
   492  				Foo: "from target",
   493  				Params: &params{
   494  					Name: "from target",
   495  					Multi: &multiPtr{
   496  						Text:   "from target",
   497  						Number: 5,
   498  					},
   499  					Final: &final{
   500  						Msg1: "from target",
   501  						Msg2: "",
   502  					},
   503  				},
   504  			},
   505  			output: &config{
   506  				Foo: "from target",
   507  				Bar: "from changes",
   508  				Params: &params{
   509  					Name: "from target",
   510  					Multi: &multiPtr{
   511  						Text:   "from target",
   512  						Number: 5,
   513  					},
   514  					Final: &final{
   515  						Msg1: "from target",
   516  						Msg2: "from changes",
   517  					},
   518  				},
   519  			},
   520  		},
   521  	}
   522  
   523  	for _, tc := range cases {
   524  		t.Run(tc.name, func(t *testing.T) {
   525  			var err error
   526  			if tc.overwrite {
   527  				err = mergo.Merge(tc.target, *tc.changes, mergo.WithOverride)
   528  			} else {
   529  				err = mergo.Merge(tc.target, *tc.changes)
   530  			}
   531  			if err != nil {
   532  				t.Error(err)
   533  			}
   534  			if !reflect.DeepEqual(tc.target, tc.output) {
   535  				t.Errorf("Test failed:\ngot  :\n%+v\n\nwant :\n%+v\n\n", tc.target.Params, tc.output.Params)
   536  			}
   537  		})
   538  	}
   539  }
   540  func TestMaps(t *testing.T) {
   541  	m := map[string]simpleTest{
   542  		"a": {},
   543  		"b": {42},
   544  		"c": {13},
   545  		"d": {61},
   546  	}
   547  	n := map[string]simpleTest{
   548  		"a": {16},
   549  		"b": {},
   550  		"c": {12},
   551  		"e": {14},
   552  	}
   553  	expect := map[string]simpleTest{
   554  		"a": {0},
   555  		"b": {42},
   556  		"c": {13},
   557  		"d": {61},
   558  		"e": {14},
   559  	}
   560  
   561  	if err := mergo.Merge(&m, n); err != nil {
   562  		t.Errorf(err.Error())
   563  	}
   564  
   565  	if !reflect.DeepEqual(m, expect) {
   566  		t.Errorf("Test failed:\ngot  :\n%#v\n\nwant :\n%#v\n\n", m, expect)
   567  	}
   568  	if m["a"].Value != 0 {
   569  		t.Errorf(`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)
   570  	}
   571  	if m["b"].Value != 42 {
   572  		t.Errorf(`n wrongly merged in m: m["b"].Value(%d) != n["b"].Value(%d)`, m["b"].Value, n["b"].Value)
   573  	}
   574  	if m["c"].Value != 13 {
   575  		t.Errorf(`n overwritten in m: m["c"].Value(%d) != n["c"].Value(%d)`, m["c"].Value, n["c"].Value)
   576  	}
   577  }
   578  
   579  func TestMapsWithNilPointer(t *testing.T) {
   580  	m := map[string]*simpleTest{
   581  		"a": nil,
   582  		"b": nil,
   583  	}
   584  	n := map[string]*simpleTest{
   585  		"b": nil,
   586  		"c": nil,
   587  	}
   588  	expect := map[string]*simpleTest{
   589  		"a": nil,
   590  		"b": nil,
   591  		"c": nil,
   592  	}
   593  
   594  	if err := mergo.Merge(&m, n, mergo.WithOverride); err != nil {
   595  		t.Errorf(err.Error())
   596  	}
   597  
   598  	if !reflect.DeepEqual(m, expect) {
   599  		t.Errorf("Test failed:\ngot   :\n%#v\n\nwant :\n%#v\n\n", m, expect)
   600  	}
   601  }
   602  
   603  func TestYAMLMaps(t *testing.T) {
   604  	thing := loadYAML("testdata/thing.yml")
   605  	license := loadYAML("testdata/license.yml")
   606  	ft := thing["fields"].(map[string]interface{})
   607  	fl := license["fields"].(map[string]interface{})
   608  	// license has one extra field (site) and another already existing in thing (author) that Mergo won't override.
   609  	expectedLength := len(ft) + len(fl) - 1
   610  	if err := mergo.Merge(&license, thing); err != nil {
   611  		t.Error(err.Error())
   612  	}
   613  	currentLength := len(license["fields"].(map[string]interface{}))
   614  	if currentLength != expectedLength {
   615  		t.Errorf(`thing not merged in license properly, license must have %d elements instead of %d`, expectedLength, currentLength)
   616  	}
   617  	fields := license["fields"].(map[string]interface{})
   618  	if _, ok := fields["id"]; !ok {
   619  		t.Errorf(`thing not merged in license properly, license must have a new id field from thing`)
   620  	}
   621  }
   622  
   623  func TestTwoPointerValues(t *testing.T) {
   624  	a := &simpleTest{}
   625  	b := &simpleTest{42}
   626  	if err := mergo.Merge(a, b); err != nil {
   627  		t.Errorf(`Boom. You crossed the streams: %s`, err)
   628  	}
   629  }
   630  
   631  func TestMap(t *testing.T) {
   632  	a := complexTest{}
   633  	a.ID = "athing"
   634  	c := moreComplextText{a, simpleTest{}, simpleTest{}}
   635  	b := map[string]interface{}{
   636  		"ct": map[string]interface{}{
   637  			"st": map[string]interface{}{
   638  				"value": 42,
   639  			},
   640  			"sz": 1,
   641  			"id": "bthing",
   642  		},
   643  		"st": &simpleTest{144}, // Mapping a reference
   644  		"zt": simpleTest{299},  // Mapping a missing field (zt doesn't exist)
   645  		"nt": simpleTest{3},
   646  	}
   647  	if err := mergo.Map(&c, b); err != nil {
   648  		t.FailNow()
   649  	}
   650  	m := b["ct"].(map[string]interface{})
   651  	n := m["st"].(map[string]interface{})
   652  	o := b["st"].(*simpleTest)
   653  	p := b["nt"].(simpleTest)
   654  	if c.Ct.St.Value != 42 {
   655  		t.Errorf("b not merged in properly: c.Ct.St.Value(%d) != b.Ct.St.Value(%d)", c.Ct.St.Value, n["value"])
   656  	}
   657  	if c.St.Value != 144 {
   658  		t.Errorf("b not merged in properly: c.St.Value(%d) != b.St.Value(%d)", c.St.Value, o.Value)
   659  	}
   660  	if c.Nt.Value != 3 {
   661  		t.Errorf("b not merged in properly: c.Nt.Value(%d) != b.Nt.Value(%d)", c.St.Value, p.Value)
   662  	}
   663  	if c.Ct.sz == 1 {
   664  		t.Errorf("a's private field sz not preserved from merge: c.Ct.sz(%d) == b.Ct.sz(%d)", c.Ct.sz, m["sz"])
   665  	}
   666  	if c.Ct.ID == m["id"] {
   667  		t.Errorf("a's field ID merged unexpectedly: c.Ct.ID(%s) == b.Ct.ID(%s)", c.Ct.ID, m["id"])
   668  	}
   669  }
   670  
   671  func TestSimpleMap(t *testing.T) {
   672  	a := simpleTest{}
   673  	b := map[string]interface{}{
   674  		"value": 42,
   675  	}
   676  	if err := mergo.Map(&a, b); err != nil {
   677  		t.FailNow()
   678  	}
   679  	if a.Value != 42 {
   680  		t.Errorf("b not merged in properly: a.Value(%d) != b.Value(%v)", a.Value, b["value"])
   681  	}
   682  }
   683  
   684  func TestIfcMap(t *testing.T) {
   685  	a := ifcTest{}
   686  	b := ifcTest{42}
   687  	if err := mergo.Map(&a, b); err != nil {
   688  		t.FailNow()
   689  	}
   690  	if a.I != 42 {
   691  		t.Errorf("b not merged in properly: a.I(%d) != b.I(%d)", a.I, b.I)
   692  	}
   693  	if !reflect.DeepEqual(a, b) {
   694  		t.FailNow()
   695  	}
   696  }
   697  
   698  func TestIfcMapNoOverwrite(t *testing.T) {
   699  	a := ifcTest{13}
   700  	b := ifcTest{42}
   701  	if err := mergo.Map(&a, b); err != nil {
   702  		t.FailNow()
   703  	}
   704  	if a.I != 13 {
   705  		t.Errorf("a not left alone: a.I(%d) == b.I(%d)", a.I, b.I)
   706  	}
   707  }
   708  
   709  func TestIfcMapWithOverwrite(t *testing.T) {
   710  	a := ifcTest{13}
   711  	b := ifcTest{42}
   712  	if err := mergo.MapWithOverwrite(&a, b); err != nil {
   713  		t.FailNow()
   714  	}
   715  	if a.I != 42 {
   716  		t.Errorf("b not merged in properly: a.I(%d) != b.I(%d)", a.I, b.I)
   717  	}
   718  	if !reflect.DeepEqual(a, b) {
   719  		t.FailNow()
   720  	}
   721  }
   722  
   723  type pointerMapTest struct {
   724  	B      *simpleTest
   725  	A      int
   726  	hidden int
   727  }
   728  
   729  func TestBackAndForth(t *testing.T) {
   730  	pt := pointerMapTest{&simpleTest{66}, 42, 1}
   731  	m := make(map[string]interface{})
   732  	if err := mergo.Map(&m, pt); err != nil {
   733  		t.FailNow()
   734  	}
   735  	var (
   736  		v  interface{}
   737  		ok bool
   738  	)
   739  	if v, ok = m["a"]; v.(int) != pt.A || !ok {
   740  		t.Errorf("pt not merged in properly: m[`a`](%d) != pt.A(%d)", v, pt.A)
   741  	}
   742  	if v, ok = m["b"]; !ok {
   743  		t.Errorf("pt not merged in properly: B is missing in m")
   744  	}
   745  	var st *simpleTest
   746  	if st = v.(*simpleTest); st.Value != 66 {
   747  		t.Errorf("something went wrong while mapping pt on m, B wasn't copied")
   748  	}
   749  	bpt := pointerMapTest{}
   750  	if err := mergo.Map(&bpt, m); err != nil {
   751  		t.Error(err)
   752  	}
   753  	if bpt.A != pt.A {
   754  		t.Errorf("pt not merged in properly: bpt.A(%d) != pt.A(%d)", bpt.A, pt.A)
   755  	}
   756  	if bpt.hidden == pt.hidden {
   757  		t.Errorf("pt unexpectedly merged: bpt.hidden(%d) == pt.hidden(%d)", bpt.hidden, pt.hidden)
   758  	}
   759  	if bpt.B.Value != pt.B.Value {
   760  		t.Errorf("pt not merged in properly: bpt.B.Value(%d) != pt.B.Value(%d)", bpt.B.Value, pt.B.Value)
   761  	}
   762  }
   763  
   764  func TestEmbeddedPointerUnpacking(t *testing.T) {
   765  	tests := []struct{ input pointerMapTest }{
   766  		{pointerMapTest{nil, 42, 1}},
   767  		{pointerMapTest{&simpleTest{66}, 42, 1}},
   768  	}
   769  	newValue := 77
   770  	m := map[string]interface{}{
   771  		"b": map[string]interface{}{
   772  			"value": newValue,
   773  		},
   774  	}
   775  	for _, test := range tests {
   776  		pt := test.input
   777  		if err := mergo.MapWithOverwrite(&pt, m); err != nil {
   778  			t.FailNow()
   779  		}
   780  		if pt.B.Value != newValue {
   781  			t.Errorf("pt not mapped properly: pt.A.Value(%d) != m[`b`][`value`](%d)", pt.B.Value, newValue)
   782  		}
   783  
   784  	}
   785  }
   786  
   787  type structWithTimePointer struct {
   788  	Birth *time.Time
   789  }
   790  
   791  func TestTime(t *testing.T) {
   792  	now := time.Now()
   793  	dataStruct := structWithTimePointer{
   794  		Birth: &now,
   795  	}
   796  	dataMap := map[string]interface{}{
   797  		"Birth": &now,
   798  	}
   799  	b := structWithTimePointer{}
   800  	if err := mergo.Merge(&b, dataStruct); err != nil {
   801  		t.FailNow()
   802  	}
   803  	if b.Birth.IsZero() {
   804  		t.Errorf("time.Time not merged in properly: b.Birth(%v) != dataStruct['Birth'](%v)", b.Birth, dataStruct.Birth)
   805  	}
   806  	if b.Birth != dataStruct.Birth {
   807  		t.Errorf("time.Time not merged in properly: b.Birth(%v) != dataStruct['Birth'](%v)", b.Birth, dataStruct.Birth)
   808  	}
   809  	b = structWithTimePointer{}
   810  	if err := mergo.Map(&b, dataMap); err != nil {
   811  		t.FailNow()
   812  	}
   813  	if b.Birth.IsZero() {
   814  		t.Errorf("time.Time not merged in properly: b.Birth(%v) != dataMap['Birth'](%v)", b.Birth, dataMap["Birth"])
   815  	}
   816  }
   817  
   818  type simpleNested struct {
   819  	A int
   820  }
   821  
   822  type structWithNestedPtrValueMap struct {
   823  	NestedPtrValue map[string]*simpleNested
   824  }
   825  
   826  func TestNestedPtrValueInMap(t *testing.T) {
   827  	src := &structWithNestedPtrValueMap{
   828  		NestedPtrValue: map[string]*simpleNested{
   829  			"x": {
   830  				A: 1,
   831  			},
   832  		},
   833  	}
   834  	dst := &structWithNestedPtrValueMap{
   835  		NestedPtrValue: map[string]*simpleNested{
   836  			"x": {},
   837  		},
   838  	}
   839  	if err := mergo.Map(dst, src); err != nil {
   840  		t.FailNow()
   841  	}
   842  	if dst.NestedPtrValue["x"].A == 0 {
   843  		t.Errorf("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)
   844  	}
   845  }
   846  
   847  func loadYAML(path string) (m map[string]interface{}) {
   848  	m = make(map[string]interface{})
   849  	raw, _ := ioutil.ReadFile(path)
   850  	_ = yaml.Unmarshal(raw, &m)
   851  	return
   852  }
   853  
   854  type structWithMap struct {
   855  	m map[string]structWithUnexportedProperty
   856  }
   857  
   858  type structWithUnexportedProperty struct {
   859  	s string
   860  }
   861  
   862  func TestUnexportedProperty(t *testing.T) {
   863  	a := structWithMap{map[string]structWithUnexportedProperty{
   864  		"key": {"hello"},
   865  	}}
   866  	b := structWithMap{map[string]structWithUnexportedProperty{
   867  		"key": {"hi"},
   868  	}}
   869  	defer func() {
   870  		if r := recover(); r != nil {
   871  			t.Errorf("Should not have panicked")
   872  		}
   873  	}()
   874  	mergo.Merge(&a, b)
   875  }
   876  
   877  type structWithBoolPointer struct {
   878  	C *bool
   879  }
   880  
   881  func TestBooleanPointer(t *testing.T) {
   882  	bt, bf := true, false
   883  	src := structWithBoolPointer{
   884  		&bt,
   885  	}
   886  	dst := structWithBoolPointer{
   887  		&bf,
   888  	}
   889  	if err := mergo.Merge(&dst, src); err != nil {
   890  		t.FailNow()
   891  	}
   892  	if dst.C == src.C {
   893  		t.Errorf("dst.C should be a different pointer than src.C")
   894  	}
   895  	if *dst.C != *src.C {
   896  		t.Errorf("dst.C should be true")
   897  	}
   898  }
   899  
   900  func TestMergeMapWithInnerSliceOfDifferentType(t *testing.T) {
   901  	testCases := []struct {
   902  		name    string
   903  		err     string
   904  		options []func(*mergo.Config)
   905  	}{
   906  		{
   907  			"With override and append slice",
   908  			"cannot append two slices with different type",
   909  			[]func(*mergo.Config){mergo.WithOverride, mergo.WithAppendSlice},
   910  		},
   911  		{
   912  			"With override and type check",
   913  			"cannot override two slices with different type",
   914  			[]func(*mergo.Config){mergo.WithOverride, mergo.WithTypeCheck},
   915  		},
   916  	}
   917  	for _, tc := range testCases {
   918  		t.Run(tc.name, func(t *testing.T) {
   919  			src := map[string]interface{}{
   920  				"foo": []string{"a", "b"},
   921  			}
   922  			dst := map[string]interface{}{
   923  				"foo": []int{1, 2},
   924  			}
   925  
   926  			if err := mergo.Merge(&src, &dst, tc.options...); err == nil || !strings.Contains(err.Error(), tc.err) {
   927  				t.Errorf("expected %q, got %q", tc.err, err)
   928  			}
   929  		})
   930  	}
   931  }
   932  
   933  func TestMergeDifferentSlicesIsNotSupported(t *testing.T) {
   934  	src := []string{"a", "b"}
   935  	dst := []int{1, 2}
   936  
   937  	if err := mergo.Merge(&src, &dst, mergo.WithOverride, mergo.WithAppendSlice); err != mergo.ErrDifferentArgumentsTypes {
   938  		t.Errorf("expected %q, got %q", mergo.ErrNotSupported, err)
   939  	}
   940  }
   941  

View as plain text