Codebase list golang-github-imdario-mergo / upstream/0.3.5
New upstream version 0.3.5 Dmitry Smirnov 5 years ago
8 changed file(s) with 165 addition(s) and 24 deletion(s). Raw diff Collapse all Expand all
2626
2727 ### Latest release
2828
29 [Release v0.3.3](https://github.com/imdario/mergo/releases/tag/v0.3.3).
29 [Release v0.3.4](https://github.com/imdario/mergo/releases/tag/v0.3.4).
3030
3131 ### Important note
3232
33 Please keep in mind that in [v0.3.2](//github.com/imdario/mergo/releases/tag/v0.3.2) Mergo changed `Merge()`and `Map()` signatures to support [transformers](#transformers). An optional/variadic argument has been added, so it won't break existing code.
33 Please keep in mind that in [0.3.2](//github.com/imdario/mergo/releases/tag/0.3.2) Mergo changed `Merge()`and `Map()` signatures to support [transformers](#transformers). An optional/variadic argument has been added, so it won't break existing code.
3434
3535 If you were using Mergo **before** April 6th 2015, please check your project works as intended after updating your local copy with ```go get -u github.com/imdario/mergo```. I apologize for any issue caused by its previous behavior and any future bug that Mergo could cause (I hope it won't!) in existing projects after the change (release 0.2.0).
3636
1919 if err := Merge(&p1, p2); err != nil {
2020 t.Fatalf("Error during the merge: %v", err)
2121 }
22 if len(p1.PublicStrings) != 3 {
23 t.Error("5 elements should be in 'PublicStrings' field")
24 }
25 if len(p1.privateStrings) != 2 {
26 t.Error("2 elements should be in 'privateStrings' field")
27 }
28 }
29
30 func TestPrivateSliceWithAppendSlice(t *testing.T) {
31 p1 := PrivateSliceTest66{
32 PublicStrings: []string{"one", "two", "three"},
33 privateStrings: []string{"four", "five"},
34 }
35 p2 := PrivateSliceTest66{
36 PublicStrings: []string{"six", "seven"},
37 }
38 if err := Merge(&p1, p2, WithAppendSlice); err != nil {
39 t.Fatalf("Error during the merge: %v", err)
40 }
2241 if len(p1.PublicStrings) != 5 {
2342 t.Error("5 elements should be in 'PublicStrings' field")
2443 }
2525
2626 type Config struct {
2727 Overwrite bool
28 AppendSlice bool
2829 Transformers Transformers
2930 }
3031
101102 case reflect.Ptr:
102103 fallthrough
103104 case reflect.Map:
104 if err = deepMerge(dstElement, srcElement, visited, depth+1, config); err != nil {
105 srcMapElm := srcElement
106 dstMapElm := dstElement
107 if srcMapElm.CanInterface() {
108 srcMapElm = reflect.ValueOf(srcMapElm.Interface())
109 if dstMapElm.IsValid() {
110 dstMapElm = reflect.ValueOf(dstMapElm.Interface())
111 }
112 }
113 if err = deepMerge(dstMapElm, srcMapElm, visited, depth+1, config); err != nil {
105114 return
106115 }
107116 case reflect.Slice:
114123 dstSlice = reflect.ValueOf(dstElement.Interface())
115124 }
116125
117 dstSlice = reflect.AppendSlice(dstSlice, srcSlice)
126 if !isEmptyValue(src) && (overwrite || isEmptyValue(dst)) && !config.AppendSlice {
127 dstSlice = srcSlice
128 } else if config.AppendSlice {
129 dstSlice = reflect.AppendSlice(dstSlice, srcSlice)
130 }
118131 dst.SetMapIndex(key, dstSlice)
119132 }
120133 }
122135 continue
123136 }
124137
125 if srcElement.IsValid() && (overwrite || (!dstElement.IsValid() || isEmptyValue(dst))) {
138 if srcElement.IsValid() && (overwrite || (!dstElement.IsValid() || isEmptyValue(dstElement))) {
126139 if dst.IsNil() {
127140 dst.Set(reflect.MakeMap(dst.Type()))
128141 }
133146 if !dst.CanSet() {
134147 break
135148 }
136 if !isEmptyValue(src) && (overwrite || isEmptyValue(dst)) {
149 if !isEmptyValue(src) && (overwrite || isEmptyValue(dst)) && !config.AppendSlice {
137150 dst.Set(src)
138 } else {
151 } else if config.AppendSlice {
139152 dst.Set(reflect.AppendSlice(dst, src))
140153 }
141154 case reflect.Ptr:
204217 config.Overwrite = true
205218 }
206219
220 // WithAppendSlice will make merge append slices instead of overwriting it
221 func WithAppendSlice(config *Config) {
222 config.AppendSlice = true
223 }
224
207225 func merge(dst, src interface{}, opts ...func(*Config)) error {
208226 var (
209227 vDst, vSrc reflect.Value
0 package mergo
1
2 import (
3 "testing"
4 )
5
6 var testDataS = []struct {
7 S1 Student
8 S2 Student
9 ExpectedSlice []string
10 }{
11 {Student{"Jack", []string{"a", "B"}}, Student{"Tom", []string{"1"}}, []string{"1", "a", "B"}},
12 {Student{"Jack", []string{"a", "B"}}, Student{"Tom", []string{}}, []string{"a", "B"}},
13 {Student{"Jack", []string{}}, Student{"Tom", []string{"1"}}, []string{"1"}},
14 {Student{"Jack", []string{}}, Student{"Tom", []string{}}, []string{}},
15 }
16
17 func TestMergeSliceWithOverrideWithAppendSlice(t *testing.T) {
18 for _, data := range testDataS {
19 err := Merge(&data.S2, data.S1, WithOverride, WithAppendSlice)
20 if err != nil {
21 t.Errorf("Error while merging %s", err)
22 }
23 if len(data.S2.Books) != len(data.ExpectedSlice) {
24 t.Fatalf("Got %d elements in slice, but expected %d", len(data.S2.Books), len(data.ExpectedSlice))
25 }
26 for i, val := range data.S2.Books {
27 if val != data.ExpectedSlice[i] {
28 t.Fatalf("Expected %s, but got %s while merging slice with override", data.ExpectedSlice[i], val)
29 }
30 }
31 }
32 }
4444 return v.Uint() == 0
4545 case reflect.Float32, reflect.Float64:
4646 return v.Float() == 0
47 case reflect.Interface, reflect.Ptr, reflect.Func:
47 case reflect.Interface, reflect.Ptr:
48 if v.IsNil() {
49 return true
50 }
51 return isEmptyValue(v.Elem())
52 case reflect.Func:
4853 return v.IsNil()
4954 case reflect.Invalid:
5055 return true
55 package mergo
66
77 import (
8 "gopkg.in/yaml.v2"
98 "io/ioutil"
109 "reflect"
1110 "testing"
1211 "time"
12
13 "gopkg.in/yaml.v2"
1314 )
1415
1516 type simpleTest struct {
224225 }
225226 }
226227
227 func testSlice(t *testing.T, a []int, b []int) {
228 func testSlice(t *testing.T, a []int, b []int, e []int, opts ...func(*Config)) {
229 t.Helper()
228230 bc := b
229 e := append(a, b...)
230231
231232 sa := sliceTest{a}
232233 sb := sliceTest{b}
233 if err := Merge(&sa, sb); err != nil {
234 if err := Merge(&sa, sb, opts...); err != nil {
234235 t.FailNow()
235236 }
236237 if !reflect.DeepEqual(sb.S, bc) {
242243
243244 ma := map[string][]int{"S": a}
244245 mb := map[string][]int{"S": b}
245 if err := Merge(&ma, mb); err != nil {
246 if err := Merge(&ma, mb, opts...); err != nil {
246247 t.FailNow()
247248 }
248249 if !reflect.DeepEqual(mb["S"], bc) {
249 t.Fatalf("Source slice was modified %d != %d", mb["S"], bc)
250 t.Fatalf("map value: Source slice was modified %d != %d", mb["S"], bc)
250251 }
251252 if !reflect.DeepEqual(ma["S"], e) {
252 t.Fatalf("b not merged in a proper way %d != %d", ma["S"], e)
253 t.Fatalf("map value: b not merged in a proper way %d != %d", ma["S"], e)
253254 }
254255
255256 if a == nil {
260261 t.FailNow()
261262 }
262263 if !reflect.DeepEqual(mb["S"], bc) {
263 t.Fatalf("Source slice was modified %d != %d", mb["S"], bc)
264 t.Fatalf("missing dst key: Source slice was modified %d != %d", mb["S"], bc)
264265 }
265266 if !reflect.DeepEqual(ma["S"], e) {
266 t.Fatalf("b not merged in a proper way %d != %d", ma["S"], e)
267 t.Fatalf("missing dst key: b not merged in a proper way %d != %d", ma["S"], e)
267268 }
268269 }
269270
275276 t.FailNow()
276277 }
277278 if !reflect.DeepEqual(mb["S"], bc) {
278 t.Fatalf("Source slice was modified %d != %d", mb["S"], bc)
279 t.Fatalf("missing src key: Source slice was modified %d != %d", mb["S"], bc)
279280 }
280281 if !reflect.DeepEqual(ma["S"], e) {
281 t.Fatalf("b not merged in a proper way %d != %d", ma["S"], e)
282 t.Fatalf("missing src key: b not merged in a proper way %d != %d", ma["S"], e)
282283 }
283284 }
284285 }
285286
286287 func TestSlice(t *testing.T) {
287 testSlice(t, nil, []int{1, 2, 3})
288 testSlice(t, []int{}, []int{1, 2, 3})
289 testSlice(t, []int{1}, []int{2, 3})
290 testSlice(t, []int{1}, []int{})
291 testSlice(t, []int{1}, nil)
288 testSlice(t, nil, []int{1, 2, 3}, []int{1, 2, 3})
289 testSlice(t, []int{}, []int{1, 2, 3}, []int{1, 2, 3})
290 testSlice(t, []int{1}, []int{2, 3}, []int{1})
291 testSlice(t, []int{1}, []int{}, []int{1})
292 testSlice(t, []int{1}, nil, []int{1})
293 testSlice(t, nil, []int{1, 2, 3}, []int{1, 2, 3}, WithAppendSlice)
294 testSlice(t, []int{}, []int{1, 2, 3}, []int{1, 2, 3}, WithAppendSlice)
295 testSlice(t, []int{1}, []int{2, 3}, []int{1, 2, 3}, WithAppendSlice)
296 testSlice(t, []int{1}, []int{}, []int{1}, WithAppendSlice)
297 testSlice(t, []int{1}, nil, []int{1}, WithAppendSlice)
292298 }
293299
294300 func TestEmptyMaps(t *testing.T) {
0 package mergo
1
2 import (
3 "testing"
4 )
5
6 type mapInterface map[string]interface{}
7
8 func TestMergeMapsEmptyString(t *testing.T) {
9 a := mapInterface{"s": ""}
10 b := mapInterface{"s": "foo"}
11 if err := Merge(&a, b); err != nil {
12 t.Fatal(err)
13 }
14 if a["s"] != "foo" {
15 t.Fatalf("b not merged in properly: a.s.Value(%s) != expected(%s)", a["s"], "foo")
16 }
17 }
0 package mergo
1
2 import (
3 "testing"
4 )
5
6 func TestMapInterfaceWithMultipleLayer(t *testing.T) {
7 m1 := map[string]interface{}{
8 "k1": map[string]interface{}{
9 "k1.1": "v1",
10 },
11 }
12
13 m2 := map[string]interface{}{
14 "k1": map[string]interface{}{
15 "k1.1": "v2",
16 "k1.2": "v3",
17 },
18 }
19
20 if err := Map(&m1, m2, WithOverride); err != nil {
21 t.Fatalf("Error merging: %v", err)
22 }
23
24 // Check overwrite of sub map works
25 expected := "v2"
26 actual := m1["k1"].(map[string]interface{})["k1.1"].(string)
27 if actual != expected {
28 t.Fatalf("Expected %v but got %v",
29 expected,
30 actual)
31 }
32
33 // Check new key is merged
34 expected = "v3"
35 actual = m1["k1"].(map[string]interface{})["k1.2"].(string)
36 if actual != expected {
37 t.Fatalf("Expected %v but got %v",
38 expected,
39 actual)
40 }
41 }