Codebase list golang-github-imdario-mergo / 41ac176
Update upstream source from tag 'upstream/0.3.12' Update to upstream version '0.3.12' with Debian dir 51c6250db8f4b955c55cf0c364920ed8d4f9191c Shengjing Zhu 2 years ago
44 changed file(s) with 1315 addition(s) and 379 deletion(s). Raw diff Collapse all Expand all
0 version = 1
1
2 test_patterns = [
3 "*_test.go"
4 ]
5
6 [[analyzers]]
7 name = "go"
8 enabled = true
9
10 [analyzers.meta]
11 import_path = "github.com/imdario/mergo"
00 # These are supported funding model platforms
11
2 github: imdario
23 ko_fi: dariocc
34 custom: https://beerpay.io/imdario/mergo
00 language: go
1 arch:
2 - amd64
3 - ppc64le
14 install:
25 - go get -t
36 - go get golang.org/x/tools/cmd/cover
0 {
1 "go.lintTool": "golangci-lint",
2 "go.lintFlags": [
3 "--enable-all",
4 "--disable=gomnd"
5 ]
6 }
00 # Mergo
11
2 A helper to merge structs and maps in Golang. Useful for configuration default values, avoiding messy if-statements.
3
4 Also a lovely [comune](http://en.wikipedia.org/wiki/Mergo) (municipality) in the Province of Ancona in the Italian region of Marche.
5
6 ## Status
7
8 It is ready for production use. [It is used in several projects by Docker, Google, The Linux Foundation, VMWare, Shopify, etc](https://github.com/imdario/mergo#mergo-in-the-wild).
92
103 [![GoDoc][3]][4]
11 [![GoCard][5]][6]
4 [![GitHub release][5]][6]
5 [![GoCard][7]][8]
126 [![Build Status][1]][2]
13 [![Coverage Status][7]][8]
14 [![Sourcegraph][9]][10]
15 [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fimdario%2Fmergo.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Fimdario%2Fmergo?ref=badge_shield)
7 [![Coverage Status][9]][10]
8 [![Sourcegraph][11]][12]
9 [![FOSSA Status][13]][14]
10
11 [![GoCenter Kudos][15]][16]
1612
1713 [1]: https://travis-ci.org/imdario/mergo.png
1814 [2]: https://travis-ci.org/imdario/mergo
1915 [3]: https://godoc.org/github.com/imdario/mergo?status.svg
2016 [4]: https://godoc.org/github.com/imdario/mergo
21 [5]: https://goreportcard.com/badge/imdario/mergo
22 [6]: https://goreportcard.com/report/github.com/imdario/mergo
23 [7]: https://coveralls.io/repos/github/imdario/mergo/badge.svg?branch=master
24 [8]: https://coveralls.io/github/imdario/mergo?branch=master
25 [9]: https://sourcegraph.com/github.com/imdario/mergo/-/badge.svg
26 [10]: https://sourcegraph.com/github.com/imdario/mergo?badge
27
28 ### Latest release
29
30 [Release v0.3.7](https://github.com/imdario/mergo/releases/tag/v0.3.7).
17 [5]: https://img.shields.io/github/release/imdario/mergo.svg
18 [6]: https://github.com/imdario/mergo/releases
19 [7]: https://goreportcard.com/badge/imdario/mergo
20 [8]: https://goreportcard.com/report/github.com/imdario/mergo
21 [9]: https://coveralls.io/repos/github/imdario/mergo/badge.svg?branch=master
22 [10]: https://coveralls.io/github/imdario/mergo?branch=master
23 [11]: https://sourcegraph.com/github.com/imdario/mergo/-/badge.svg
24 [12]: https://sourcegraph.com/github.com/imdario/mergo?badge
25 [13]: https://app.fossa.io/api/projects/git%2Bgithub.com%2Fimdario%2Fmergo.svg?type=shield
26 [14]: https://app.fossa.io/projects/git%2Bgithub.com%2Fimdario%2Fmergo?ref=badge_shield
27 [15]: https://search.gocenter.io/api/ui/badge/github.com%2Fimdario%2Fmergo
28 [16]: https://search.gocenter.io/github.com/imdario/mergo
29
30 A helper to merge structs and maps in Golang. Useful for configuration default values, avoiding messy if-statements.
31
32 Mergo merges same-type structs and maps by setting default values in zero-value fields. Mergo won't merge unexported (private) fields. It will do recursively any exported one. It also won't merge structs inside maps (because they are not addressable using Go reflection).
33
34 Also a lovely [comune](http://en.wikipedia.org/wiki/Mergo) (municipality) in the Province of Ancona in the Italian region of Marche.
35
36 ## Status
37
38 It is ready for production use. [It is used in several projects by Docker, Google, The Linux Foundation, VMWare, Shopify, etc](https://github.com/imdario/mergo#mergo-in-the-wild).
3139
3240 ### Important note
3341
34 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.
35
36 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).
42 Please keep in mind that a problematic PR broke [0.3.9](//github.com/imdario/mergo/releases/tag/0.3.9). I reverted it in [0.3.10](//github.com/imdario/mergo/releases/tag/0.3.10), and I consider it stable but not bug-free. Also, this version adds suppot for go modules.
43
44 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). I added an optional/variadic argument so that it won't break the existing code.
45
46 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 in existing projects after the change (release 0.2.0).
3747
3848 ### Donations
3949
40 If Mergo is useful to you, consider buying me a coffee, a beer or making a monthly donation so I can keep building great free software. :heart_eyes:
50 If Mergo is useful to you, consider buying me a coffee, a beer, or making a monthly donation to allow me to keep building great free software. :heart_eyes:
4151
4252 <a href='https://ko-fi.com/B0B58839' target='_blank'><img height='36' style='border:0px;height:36px;' src='https://az743702.vo.msecnd.net/cdn/kofi1.png?v=0' border='0' alt='Buy Me a Coffee at ko-fi.com' /></a>
4353 [![Beerpay](https://beerpay.io/imdario/mergo/badge.svg)](https://beerpay.io/imdario/mergo)
8696 - [mantasmatelis/whooplist-server](https://github.com/mantasmatelis/whooplist-server)
8797 - [jnuthong/item_search](https://github.com/jnuthong/item_search)
8898 - [bukalapak/snowboard](https://github.com/bukalapak/snowboard)
89
90 ## Installation
99 - [containerssh/containerssh](https://github.com/containerssh/containerssh)
100
101 ## Install
91102
92103 go get github.com/imdario/mergo
93104
98109
99110 ## Usage
100111
101 You can only merge same-type structs with exported fields initialized as zero value of their type and same-types maps. Mergo won't merge unexported (private) fields but will do recursively any exported one. It won't merge empty structs value as [they are not considered zero values](https://golang.org/ref/spec#The_zero_value) either. Also maps will be merged recursively except for structs inside maps (because they are not addressable using Go reflection).
112 You can only merge same-type structs with exported fields initialized as zero value of their type and same-types maps. Mergo won't merge unexported (private) fields but will do recursively any exported one. It won't merge empty structs value as [they are zero values](https://golang.org/ref/spec#The_zero_value) too. Also, maps will be merged recursively except for structs inside maps (because they are not addressable using Go reflection).
102113
103114 ```go
104115 if err := mergo.Merge(&dst, src); err != nil {
124135
125136 Warning: if you map a struct to map, it won't do it recursively. Don't expect Mergo to map struct members of your struct as `map[string]interface{}`. They will be just assigned as values.
126137
127 More information and examples in [godoc documentation](http://godoc.org/github.com/imdario/mergo).
128
129 ### Nice example
138 Here is a nice example:
130139
131140 ```go
132141 package main
174183 "time"
175184 )
176185
177 type timeTransfomer struct {
178 }
179
180 func (t timeTransfomer) Transformer(typ reflect.Type) func(dst, src reflect.Value) error {
186 type timeTransformer struct {
187 }
188
189 func (t timeTransformer) Transformer(typ reflect.Type) func(dst, src reflect.Value) error {
181190 if typ == reflect.TypeOf(time.Time{}) {
182191 return func(dst, src reflect.Value) error {
183192 if dst.CanSet() {
201210 func main() {
202211 src := Snapshot{time.Now()}
203212 dest := Snapshot{}
204 mergo.Merge(&dest, src, mergo.WithTransformers(timeTransfomer{}))
213 mergo.Merge(&dest, src, mergo.WithTransformers(timeTransformer{}))
205214 fmt.Println(dest)
206215 // Will print
207216 // { 2018-01-12 01:15:00 +0000 UTC m=+0.000000001 }
+120
-21
doc.go less more
33 // license that can be found in the LICENSE file.
44
55 /*
6 Package mergo merges same-type structs and maps by setting default values in zero-value fields.
6 A helper to merge structs and maps in Golang. Useful for configuration default values, avoiding messy if-statements.
77
8 Mergo won't merge unexported (private) fields but will do recursively any exported one. It also won't merge structs inside maps (because they are not addressable using Go reflection).
8 Mergo merges same-type structs and maps by setting default values in zero-value fields. Mergo won't merge unexported (private) fields. It will do recursively any exported one. It also won't merge structs inside maps (because they are not addressable using Go reflection).
9
10 Status
11
12 It is ready for production use. It is used in several projects by Docker, Google, The Linux Foundation, VMWare, Shopify, etc.
13
14 Important note
15
16 Please keep in mind that a problematic PR broke 0.3.9. We reverted it in 0.3.10. We consider 0.3.10 as stable but not bug-free. . Also, this version adds suppot for go modules.
17
18 Keep in mind that in 0.3.2, Mergo changed Merge() and Map() signatures to support transformers. We added an optional/variadic argument so that it won't break the existing code.
19
20 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 in existing projects after the change (release 0.2.0).
21
22 Install
23
24 Do your usual installation procedure:
25
26 go get github.com/imdario/mergo
27
28 // use in your .go code
29 import (
30 "github.com/imdario/mergo"
31 )
932
1033 Usage
1134
12 From my own work-in-progress project:
35 You can only merge same-type structs with exported fields initialized as zero value of their type and same-types maps. Mergo won't merge unexported (private) fields but will do recursively any exported one. It won't merge empty structs value as they are zero values too. Also, maps will be merged recursively except for structs inside maps (because they are not addressable using Go reflection).
1336
14 type networkConfig struct {
15 Protocol string
16 Address string
17 ServerType string `json: "server_type"`
18 Port uint16
37 if err := mergo.Merge(&dst, src); err != nil {
38 // ...
1939 }
2040
21 type FssnConfig struct {
22 Network networkConfig
41 Also, you can merge overwriting values using the transformer WithOverride.
42
43 if err := mergo.Merge(&dst, src, mergo.WithOverride); err != nil {
44 // ...
2345 }
2446
25 var fssnDefault = FssnConfig {
26 networkConfig {
27 "tcp",
28 "127.0.0.1",
29 "http",
30 31560,
31 },
47 Additionally, you can map a map[string]interface{} to a struct (and otherwise, from struct to map), following the same restrictions as in Merge(). Keys are capitalized to find each corresponding exported field.
48
49 if err := mergo.Map(&dst, srcMap); err != nil {
50 // ...
3251 }
3352
34 // Inside a function [...]
53 Warning: if you map a struct to map, it won't do it recursively. Don't expect Mergo to map struct members of your struct as map[string]interface{}. They will be just assigned as values.
3554
36 if err := mergo.Merge(&config, fssnDefault); err != nil {
37 log.Fatal(err)
55 Here is a nice example:
56
57 package main
58
59 import (
60 "fmt"
61 "github.com/imdario/mergo"
62 )
63
64 type Foo struct {
65 A string
66 B int64
3867 }
3968
40 // More code [...]
69 func main() {
70 src := Foo{
71 A: "one",
72 B: 2,
73 }
74 dest := Foo{
75 A: "two",
76 }
77 mergo.Merge(&dest, src)
78 fmt.Println(dest)
79 // Will print
80 // {two 2}
81 }
82
83 Transformers
84
85 Transformers allow to merge specific types differently than in the default behavior. In other words, now you can customize how some types are merged. For example, time.Time is a struct; it doesn't have zero value but IsZero can return true because it has fields with zero value. How can we merge a non-zero time.Time?
86
87 package main
88
89 import (
90 "fmt"
91 "github.com/imdario/mergo"
92 "reflect"
93 "time"
94 )
95
96 type timeTransformer struct {
97 }
98
99 func (t timeTransformer) Transformer(typ reflect.Type) func(dst, src reflect.Value) error {
100 if typ == reflect.TypeOf(time.Time{}) {
101 return func(dst, src reflect.Value) error {
102 if dst.CanSet() {
103 isZero := dst.MethodByName("IsZero")
104 result := isZero.Call([]reflect.Value{})
105 if result[0].Bool() {
106 dst.Set(src)
107 }
108 }
109 return nil
110 }
111 }
112 return nil
113 }
114
115 type Snapshot struct {
116 Time time.Time
117 // ...
118 }
119
120 func main() {
121 src := Snapshot{time.Now()}
122 dest := Snapshot{}
123 mergo.Merge(&dest, src, mergo.WithTransformers(timeTransformer{}))
124 fmt.Println(dest)
125 // Will print
126 // { 2018-01-12 01:15:00 +0000 UTC m=+0.000000001 }
127 }
128
129 Contact me
130
131 If I can help you, you have an idea or you are using Mergo in your projects, don't hesitate to drop me a line (or a pull request): https://twitter.com/im_dario
132
133 About
134
135 Written by Dario Castañé: https://da.rio.hn
136
137 License
138
139 BSD 3-Clause license, as Go language.
41140
42141 */
43142 package mergo
0 module github.com/imdario/mergo
1
2 go 1.13
3
4 require gopkg.in/yaml.v2 v2.3.0
0 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
1 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
2 gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
3 gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
0 package mergo_test
1
2 import (
3 "testing"
4
5 "github.com/imdario/mergo"
6 )
7
8 type issue100s struct {
9 Member interface{}
10 }
11
12 func TestIssue100(t *testing.T) {
13 m := make(map[string]interface{})
14 m["Member"] = "anything"
15
16 st := &issue100s{}
17 if err := mergo.Map(st, m); err != nil {
18 t.Error(err)
19 }
20 }
0 package mergo_test
1
2 import (
3 "reflect"
4 "testing"
5
6 "github.com/imdario/mergo"
7 )
8
9 type Record struct {
10 Data map[string]interface{}
11 Mapping map[string]string
12 }
13
14 func StructToRecord(in interface{}) *Record {
15 rec := Record{}
16 rec.Data = make(map[string]interface{})
17 rec.Mapping = make(map[string]string)
18 typ := reflect.TypeOf(in)
19 for i := 0; i < typ.NumField(); i++ {
20 field := typ.Field(i)
21 dbFieldName := field.Tag.Get("db")
22 if dbFieldName != "" {
23 rec.Mapping[field.Name] = dbFieldName
24 }
25 }
26
27 if err := mergo.Map(&rec.Data, in); err != nil {
28 panic(err)
29 }
30 return &rec
31 }
32
33 func TestStructToRecord(t *testing.T) {
34 type A struct {
35 Name string `json:"name" db:"name"`
36 CIDR string `json:"cidr" db:"cidr"`
37 }
38 type Record struct {
39 Data map[string]interface{}
40 Mapping map[string]string
41 }
42 a := A{Name: "David", CIDR: "10.0.0.0/8"}
43 rec := StructToRecord(a)
44 if len(rec.Mapping) < 2 {
45 t.Fatalf("struct to record failed, no mapping, struct missing tags?, rec: %+v, a: %+v ", rec, a)
46 }
47 }
0 package mergo_test
1
2 import (
3 "testing"
4
5 "github.com/imdario/mergo"
6 )
7
8 func TestIssue121WithSliceDeepCopy(t *testing.T) {
9 dst := map[string]interface{}{
10 "inter": map[string]interface{}{
11 "a": "1",
12 "b": "2",
13 },
14 }
15
16 src := map[string]interface{}{
17 "inter": map[string]interface{}{
18 "a": "3",
19 "c": "4",
20 },
21 }
22
23 if err := mergo.Merge(&dst, src, mergo.WithSliceDeepCopy); err != nil {
24 t.Errorf("Error during the merge: %v", err)
25 }
26
27 if dst["inter"].(map[string]interface{})["a"].(string) != "3" {
28 t.Error("inter.a should equal '3'")
29 }
30
31 if dst["inter"].(map[string]interface{})["c"].(string) != "4" {
32 t.Error("inter.c should equal '4'")
33 }
34 }
0 package mergo_test
1
2 import (
3 "testing"
4
5 "github.com/imdario/mergo"
6 )
7
8 func TestIssue123(t *testing.T) {
9 src := map[string]interface{}{
10 "col1": nil,
11 "col2": 4,
12 "col3": nil,
13 }
14 dst := map[string]interface{}{
15 "col1": 2,
16 "col2": 3,
17 "col3": 3,
18 }
19
20 // Expected behavior
21 if err := mergo.Merge(&dst, src, mergo.WithOverride); err != nil {
22 t.Fatal(err)
23 }
24 testCases := []struct {
25 key string
26 expected interface{}
27 }{
28 {
29 "col1",
30 nil,
31 },
32 {
33 "col2",
34 4,
35 },
36 {
37 "col3",
38 nil,
39 },
40 }
41 for _, tC := range testCases {
42 if dst[tC.key] != tC.expected {
43 t.Fatalf("expected %v in dst[%q], got %v", tC.expected, tC.key, dst[tC.key])
44 }
45 }
46 }
0 package mergo
0 package mergo_test
11
22 import (
33 "encoding/json"
44 "testing"
5 )
65
7 var (
8 data = `{"FirstSlice":[], "SecondSlice": null}`
6 "github.com/imdario/mergo"
97 )
108
119 type settings struct {
1412 }
1513
1614 func TestIssue125MergeWithOverwrite(t *testing.T) {
15 var (
16 defaultSettings = settings{
17 FirstSlice: []string{},
18 SecondSlice: []string{},
19 }
20 something settings
21 data = `{"FirstSlice":[], "SecondSlice": null}`
22 )
1723
18 defaultSettings := settings{
19 FirstSlice: []string{},
20 SecondSlice: []string{},
21 }
22
23 var something settings
2424 if err := json.Unmarshal([]byte(data), &something); err != nil {
2525 t.Errorf("Error while Unmarshalling maprequest: %s", err)
2626 }
27 if err := Merge(&something, defaultSettings, WithOverrideEmptySlice); err != nil {
27
28 if err := mergo.Merge(&something, defaultSettings, mergo.WithOverrideEmptySlice); err != nil {
2829 t.Errorf("Error while merging: %s", err)
2930 }
31
3032 if something.FirstSlice == nil {
3133 t.Error("Invalid merging first slice")
3234 }
35
3336 if something.SecondSlice == nil {
3437 t.Error("Invalid merging second slice")
3538 }
0 package mergo_test
1
2 import (
3 "testing"
4
5 "github.com/imdario/mergo"
6 )
7
8 func TestIssue129Boolean(t *testing.T) {
9 type Foo struct {
10 A bool
11 B bool
12 }
13
14 src := Foo{
15 A: true,
16 B: false,
17 }
18 dst := Foo{
19 A: false,
20 B: true,
21 }
22
23 // Standard behavior
24 if err := mergo.Merge(&dst, src); err != nil {
25 t.Error(err)
26 }
27 if dst.A != true {
28 t.Errorf("expected true, got false")
29 }
30 if dst.B != true {
31 t.Errorf("expected true, got false")
32 }
33
34 // Expected behavior
35 dst = Foo{
36 A: false,
37 B: true,
38 }
39 if err := mergo.Merge(&dst, src, mergo.WithOverwriteWithEmptyValue); err != nil {
40 t.Error(err)
41 }
42 if dst.A != true {
43 t.Errorf("expected true, got false")
44 }
45 if dst.B != false {
46 t.Errorf("expected false, got true")
47 }
48 }
0 package mergo_test
1
2 import (
3 "testing"
4
5 "github.com/imdario/mergo"
6 )
7
8 type foz struct {
9 A *bool
10 B string
11 }
12
13 func TestIssue131MergeWithOverwriteWithEmptyValue(t *testing.T) {
14 src := foz{
15 A: func(v bool) *bool { return &v }(false),
16 B: "src",
17 }
18 dest := foz{
19 A: func(v bool) *bool { return &v }(true),
20 B: "dest",
21 }
22 if err := mergo.Merge(&dest, src, mergo.WithOverwriteWithEmptyValue); err != nil {
23 t.Error(err)
24 }
25 if *src.A != *dest.A {
26 t.Errorf("dest.A not merged in properly: %v != %v", *src.A, *dest.A)
27 }
28 if src.B != dest.B {
29 t.Errorf("dest.B not merged in properly: %v != %v", src.B, dest.B)
30 }
31 }
0 package mergo_test
1
2 import (
3 "testing"
4
5 "github.com/imdario/mergo"
6 )
7
8 type embeddedTestA struct {
9 Name string
10 Age uint8
11 }
12
13 type embeddedTestB struct {
14 embeddedTestA
15 Address string
16 }
17
18 func TestMergeEmbedded(t *testing.T) {
19 var (
20 err error
21 a = &embeddedTestA{
22 "Suwon", 16,
23 }
24 b = &embeddedTestB{}
25 )
26
27 if err := mergo.Merge(&b.embeddedTestA, *a); err != nil {
28 t.Error(err)
29 }
30
31 if b.Name != "Suwon" {
32 t.Errorf("%v %v", b.Name, err)
33 }
34 }
0 package mergo_test
1
2 import (
3 "encoding/json"
4 "testing"
5
6 "github.com/imdario/mergo"
7 )
8
9 const issue138configuration string = `
10 {
11 "Port": 80
12 }
13 `
14
15 func TestIssue138(t *testing.T) {
16 type config struct {
17 Port uint16
18 }
19 type compatibleConfig struct {
20 Port float64
21 }
22
23 foo := make(map[string]interface{})
24 // encoding/json unmarshals numbers as float64
25 // https://golang.org/pkg/encoding/json/#Unmarshal
26 json.Unmarshal([]byte(issue138configuration), &foo)
27
28 err := mergo.Map(&config{}, foo)
29 if err == nil {
30 t.Error("expected type mismatch error, got nil")
31 } else {
32 if err.Error() != "type mismatch on Port field: found float64, expected uint16" {
33 t.Errorf("expected type mismatch error, got %q", err)
34 }
35 }
36
37 c := compatibleConfig{}
38 if err := mergo.Map(&c, foo); err != nil {
39 t.Error(err)
40 }
41 }
0 package mergo_test
1
2 import (
3 "fmt"
4 "testing"
5
6 "github.com/imdario/mergo"
7 )
8
9 func TestIssue143(t *testing.T) {
10 testCases := []struct {
11 options []func(*mergo.Config)
12 expected func(map[string]interface{}) error
13 }{
14 {
15 options: []func(*mergo.Config){mergo.WithOverride},
16 expected: func(m map[string]interface{}) error {
17 properties := m["properties"].(map[string]interface{})
18 if properties["field1"] != "wrong" {
19 return fmt.Errorf("expected %q, got %v", "wrong", properties["field1"])
20 }
21 return nil
22 },
23 },
24 {
25 options: []func(*mergo.Config){},
26 expected: func(m map[string]interface{}) error {
27 properties := m["properties"].(map[string]interface{})
28 if properties["field1"] == "wrong" {
29 return fmt.Errorf("expected a map, got %v", "wrong")
30 }
31 return nil
32 },
33 },
34 }
35 for _, tC := range testCases {
36 base := map[string]interface{}{
37 "properties": map[string]interface{}{
38 "field1": map[string]interface{}{
39 "type": "text",
40 },
41 },
42 }
43
44 err := mergo.Map(
45 &base,
46 map[string]interface{}{
47 "properties": map[string]interface{}{
48 "field1": "wrong",
49 },
50 },
51 tC.options...,
52 )
53 if err != nil {
54 t.Error(err)
55 }
56 if err := tC.expected(base); err != nil {
57 t.Error(err)
58 }
59 }
60 }
0 package mergo_test
1
2 import (
3 "testing"
4
5 "github.com/imdario/mergo"
6 )
7
8 type user struct {
9 Name string
10 }
11
12 type token struct {
13 User *user
14 Token *string
15 }
16
17 func TestIssue149(t *testing.T) {
18 dest := &token{
19 User: &user{
20 Name: "destination",
21 },
22 Token: nil,
23 }
24 tokenValue := "Issue149"
25 src := &token{
26 User: nil,
27 Token: &tokenValue,
28 }
29 if err := mergo.Merge(dest, src, mergo.WithOverwriteWithEmptyValue); err != nil {
30 t.Error(err)
31 }
32 if dest.User != nil {
33 t.Errorf("expected nil User, got %q", dest.User)
34 }
35 if dest.Token == nil {
36 t.Errorf("expected not nil Token, got %q", *dest.Token)
37 }
38 }
0 package mergo_test
1
2 import (
3 "testing"
4
5 "github.com/imdario/mergo"
6 )
7
8 type structWithBlankField struct {
9 _ struct{}
10 A struct{}
11 }
12
13 func TestIssue174(t *testing.T) {
14 dst := structWithBlankField{}
15 src := structWithBlankField{}
16
17 if err := mergo.Merge(&dst, src, mergo.WithOverride); err != nil {
18 t.Error(err)
19 }
20 }
0 package mergo
0 package mergo_test
11
22 import (
33 "encoding/json"
44 "testing"
5 )
65
7 var (
8 request = `{"timestamp":null, "name": "foo"}`
9 maprequest = map[string]interface{}{
10 "timestamp": nil,
11 "name": "foo",
12 "newStuff": "foo",
13 }
6 "github.com/imdario/mergo"
147 )
158
169 func TestIssue17MergeWithOverwrite(t *testing.T) {
10 var (
11 request = `{"timestamp":null, "name": "foo"}`
12 maprequest = map[string]interface{}{
13 "timestamp": nil,
14 "name": "foo",
15 "newStuff": "foo",
16 }
17 )
18
1719 var something map[string]interface{}
1820 if err := json.Unmarshal([]byte(request), &something); err != nil {
1921 t.Errorf("Error while Unmarshalling maprequest: %s", err)
2022 }
21 if err := MergeWithOverwrite(&something, maprequest); err != nil {
23
24 if err := mergo.MergeWithOverwrite(&something, maprequest); err != nil {
2225 t.Errorf("Error while merging: %s", err)
2326 }
2427 }
0 package mergo
0 package mergo_test
11
22 import (
33 "testing"
44 "time"
5
6 "github.com/imdario/mergo"
57 )
68
79 type document struct {
1719 src := document{
1820 &expected,
1921 }
20 if err := MergeWithOverwrite(&dst, src); err != nil {
22
23 if err := mergo.MergeWithOverwrite(&dst, src); err != nil {
2124 t.Errorf("Error while merging %s", err)
2225 }
26
2327 if !dst.Created.Equal(*src.Created) { //--> https://golang.org/pkg/time/#pkg-overview
24 t.Fatalf("Created not merged in properly: dst.Created(%v) != src.Created(%v)", dst.Created, src.Created)
28 t.Errorf("Created not merged in properly: dst.Created(%v) != src.Created(%v)", dst.Created, src.Created)
2529 }
2630 }
0 package mergo
0 package mergo_test
11
22 import (
33 "testing"
4
5 "github.com/imdario/mergo"
46 )
57
68 type Foo struct {
1416 Str: "b",
1517 Bslice: []byte{1, 2},
1618 }
17 if err := Merge(&dest, toMerge); err != nil {
19
20 if err := mergo.Merge(&dest, toMerge); err != nil {
1821 t.Errorf("Error while merging: %s", err)
1922 }
2023 // Merge doesn't overwrite an attribute if in destination it doesn't have a zero value.
2326 t.Errorf("dest.Str should have not been override as it has a non-zero value: dest.Str(%v) != 'a'", dest.Str)
2427 }
2528 // If we want to override, we must use MergeWithOverwrite or Merge using WithOverride.
26 if err := Merge(&dest, toMerge, WithOverride); err != nil {
29 if err := mergo.Merge(&dest, toMerge, mergo.WithOverride); err != nil {
2730 t.Errorf("Error while merging: %s", err)
2831 }
32
2933 if dest.Str != toMerge.Str {
3034 t.Errorf("dest.Str should have been override: dest.Str(%v) != toMerge.Str(%v)", dest.Str, toMerge.Str)
3135 }
0 package mergo
0 package mergo_test
11
22 import (
33 "testing"
44 "time"
5
6 "github.com/imdario/mergo"
57 )
68
79 type structWithoutTimePointer struct {
1719 src := structWithoutTimePointer{
1820 expected,
1921 }
20 if err := Merge(&dst, src); err != nil {
22
23 if err := mergo.Merge(&dst, src); err != nil {
2124 t.Errorf("Error while merging %s", err)
2225 }
26
2327 if dst.Created == src.Created {
24 t.Fatalf("Created merged unexpectedly: dst.Created(%v) == src.Created(%v)", dst.Created, src.Created)
28 t.Errorf("Created merged unexpectedly: dst.Created(%v) == src.Created(%v)", dst.Created, src.Created)
2529 }
2630 }
2731
3236 src := structWithoutTimePointer{
3337 expected,
3438 }
35 if err := Merge(&dst, src); err != nil {
39
40 if err := mergo.Merge(&dst, src); err != nil {
3641 t.Errorf("Error while merging %s", err)
3742 }
43
3844 if dst.Created == src.Created {
39 t.Fatalf("Created merged unexpectedly: dst.Created(%v) == src.Created(%v)", dst.Created, src.Created)
45 t.Errorf("Created merged unexpectedly: dst.Created(%v) == src.Created(%v)", dst.Created, src.Created)
4046 }
4147 }
4248
4955 src := structWithoutTimePointer{
5056 expected,
5157 }
52 if err := MergeWithOverwrite(&dst, src); err != nil {
58
59 if err := mergo.MergeWithOverwrite(&dst, src); err != nil {
5360 t.Errorf("Error while merging %s", err)
5461 }
62
5563 if dst.Created != src.Created {
56 t.Fatalf("Created not merged in properly: dst.Created(%v) != src.Created(%v)", dst.Created, src.Created)
64 t.Errorf("Created not merged in properly: dst.Created(%v) != src.Created(%v)", dst.Created, src.Created)
5765 }
5866 }
0 package mergo
0 package mergo_test
11
22 import (
33 "testing"
44 "time"
5
6 "github.com/imdario/mergo"
57 )
68
79 type testStruct struct {
1113 func TestIssue50Merge(t *testing.T) {
1214 to := testStruct{}
1315 from := testStruct{}
14 if err := Merge(&to, from); err != nil {
16
17 if err := mergo.Merge(&to, from); err != nil {
1518 t.Fail()
1619 }
1720 }
0 package mergo
0 package mergo_test
11
22 import (
33 "reflect"
44 "testing"
55 "time"
6
7 "github.com/imdario/mergo"
68 )
79
810 type structWithTime struct {
1921 if dst.CanSet() {
2022 if t.overwrite {
2123 isZero := src.MethodByName("IsZero")
24
2225 result := isZero.Call([]reflect.Value{})
2326 if !result[0].Bool() {
2427 dst.Set(src)
2528 }
2629 } else {
2730 isZero := dst.MethodByName("IsZero")
31
2832 result := isZero.Call([]reflect.Value{})
2933 if result[0].Bool() {
3034 dst.Set(src)
4145 now := time.Now()
4246 dst := structWithTime{now}
4347 src := structWithTime{}
44 if err := MergeWithOverwrite(&dst, src); err != nil {
48
49 if err := mergo.MergeWithOverwrite(&dst, src); err != nil {
4550 t.FailNow()
4651 }
52
4753 if !dst.Birth.IsZero() {
48 t.Fatalf("dst should have been overwritten: dst.Birth(%v) != now(%v)", dst.Birth, now)
54 t.Errorf("dst should have been overwritten: dst.Birth(%v) != now(%v)", dst.Birth, now)
4955 }
5056 }
5157
5359 now := time.Now()
5460 dst := structWithTime{now}
5561 src := structWithTime{}
56 if err := MergeWithOverwrite(&dst, src, WithTransformers(timeTransfomer{true})); err != nil {
62
63 if err := mergo.MergeWithOverwrite(&dst, src, mergo.WithTransformers(timeTransfomer{true})); err != nil {
5764 t.FailNow()
5865 }
66
5967 if dst.Birth.IsZero() {
60 t.Fatalf("dst should not have been overwritten: dst.Birth(%v) != now(%v)", dst.Birth, now)
68 t.Errorf("dst should not have been overwritten: dst.Birth(%v) != now(%v)", dst.Birth, now)
6169 }
6270 }
6371
6573 now := time.Now()
6674 dst := structWithTime{}
6775 src := structWithTime{now}
68 if err := MergeWithOverwrite(&dst, src); err != nil {
76
77 if err := mergo.MergeWithOverwrite(&dst, src); err != nil {
6978 t.FailNow()
7079 }
80
7181 if dst.Birth.IsZero() {
72 t.Fatalf("dst should have been overwritten: dst.Birth(%v) != zero(%v)", dst.Birth, time.Time{})
82 t.Errorf("dst should have been overwritten: dst.Birth(%v) != zero(%v)", dst.Birth, time.Time{})
7383 }
7484 }
7585
7787 now := time.Now()
7888 dst := structWithTime{}
7989 src := structWithTime{now}
80 if err := Merge(&dst, src); err != nil {
90
91 if err := mergo.Merge(&dst, src); err != nil {
8192 t.FailNow()
8293 }
94
8395 if !dst.Birth.IsZero() {
84 t.Fatalf("dst should not have been overwritten: dst.Birth(%v) != zero(%v)", dst.Birth, time.Time{})
96 t.Errorf("dst should not have been overwritten: dst.Birth(%v) != zero(%v)", dst.Birth, time.Time{})
8597 }
8698 }
8799
89101 now := time.Now()
90102 dst := structWithTime{}
91103 src := structWithTime{now}
92 if err := Merge(&dst, src, WithTransformers(timeTransfomer{})); err != nil {
104
105 if err := mergo.Merge(&dst, src, mergo.WithTransformers(timeTransfomer{})); err != nil {
93106 t.FailNow()
94107 }
108
95109 if dst.Birth.IsZero() {
96 t.Fatalf("dst should have been overwritten: dst.Birth(%v) != now(%v)", dst.Birth, now)
110 t.Errorf("dst should have been overwritten: dst.Birth(%v) != now(%v)", dst.Birth, now)
97111 }
98112 }
0 package mergo
0 package mergo_test
11
22 import (
33 "reflect"
44 "testing"
5
6 "github.com/imdario/mergo"
57 )
68
79 func TestIssue61MergeNilMap(t *testing.T) {
1012 }
1113 t1 := T{}
1214 t2 := T{I: map[string][]string{"hi": {"there"}}}
13 if err := Merge(&t1, t2); err != nil {
15
16 if err := mergo.Merge(&t1, t2); err != nil {
1417 t.Fail()
1518 }
19
1620 if !reflect.DeepEqual(t2, T{I: map[string][]string{"hi": {"there"}}}) {
1721 t.FailNow()
1822 }
0 package mergo
0 package mergo_test
11
22 import (
33 "testing"
4
5 "github.com/imdario/mergo"
46 )
57
68 type Student struct {
810 Books []string
911 }
1012
11 var testData = []struct {
13 type issue64TestData struct {
1214 S1 Student
1315 S2 Student
1416 ExpectedSlice []string
15 }{
16 {Student{"Jack", []string{"a", "B"}}, Student{"Tom", []string{"1"}}, []string{"a", "B"}},
17 {Student{"Jack", []string{"a", "B"}}, Student{"Tom", []string{}}, []string{"a", "B"}},
18 {Student{"Jack", []string{}}, Student{"Tom", []string{"1"}}, []string{"1"}},
19 {Student{"Jack", []string{}}, Student{"Tom", []string{}}, []string{}},
17 }
18
19 func issue64Data() []issue64TestData {
20 return []issue64TestData{
21 {Student{"Jack", []string{"a", "B"}}, Student{"Tom", []string{"1"}}, []string{"a", "B"}},
22 {Student{"Jack", []string{"a", "B"}}, Student{"Tom", []string{}}, []string{"a", "B"}},
23 {Student{"Jack", []string{}}, Student{"Tom", []string{"1"}}, []string{"1"}},
24 {Student{"Jack", []string{}}, Student{"Tom", []string{}}, []string{}},
25 }
2026 }
2127
2228 func TestIssue64MergeSliceWithOverride(t *testing.T) {
23 for _, data := range testData {
24 err := Merge(&data.S2, data.S1, WithOverride)
29 for _, data := range issue64Data() {
30 err := mergo.Merge(&data.S2, data.S1, mergo.WithOverride)
2531 if err != nil {
2632 t.Errorf("Error while merging %s", err)
2733 }
34
2835 if len(data.S2.Books) != len(data.ExpectedSlice) {
29 t.Fatalf("Got %d elements in slice, but expected %d", len(data.S2.Books), len(data.ExpectedSlice))
36 t.Errorf("Got %d elements in slice, but expected %d", len(data.S2.Books), len(data.ExpectedSlice))
3037 }
38
3139 for i, val := range data.S2.Books {
3240 if val != data.ExpectedSlice[i] {
33 t.Fatalf("Expected %s, but got %s while merging slice with override", data.ExpectedSlice[i], val)
41 t.Errorf("Expected %s, but got %s while merging slice with override", data.ExpectedSlice[i], val)
3442 }
3543 }
3644 }
0 package mergo
0 package mergo_test
11
22 import (
33 "testing"
4
5 "github.com/imdario/mergo"
46 )
57
68 type PrivateSliceTest66 struct {
1618 p2 := PrivateSliceTest66{
1719 PublicStrings: []string{"six", "seven"},
1820 }
19 if err := Merge(&p1, p2); err != nil {
20 t.Fatalf("Error during the merge: %v", err)
21
22 if err := mergo.Merge(&p1, p2); err != nil {
23 t.Errorf("Error during the merge: %v", err)
2124 }
25
2226 if len(p1.PublicStrings) != 3 {
23 t.Error("5 elements should be in 'PublicStrings' field")
27 t.Error("3 elements should be in 'PublicStrings' field, when no append")
2428 }
29
2530 if len(p1.privateStrings) != 2 {
2631 t.Error("2 elements should be in 'privateStrings' field")
2732 }
3540 p2 := PrivateSliceTest66{
3641 PublicStrings: []string{"six", "seven"},
3742 }
38 if err := Merge(&p1, p2, WithAppendSlice); err != nil {
39 t.Fatalf("Error during the merge: %v", err)
43
44 if err := mergo.Merge(&p1, p2, mergo.WithAppendSlice); err != nil {
45 t.Errorf("Error during the merge: %v", err)
4046 }
47
4148 if len(p1.PublicStrings) != 5 {
4249 t.Error("5 elements should be in 'PublicStrings' field")
4350 }
51
4452 if len(p1.privateStrings) != 2 {
4553 t.Error("2 elements should be in 'privateStrings' field")
4654 }
0 package mergo_test
1
2 import (
3 "testing"
4
5 "github.com/imdario/mergo"
6 )
7
8 type issue83My struct {
9 Data []int
10 }
11
12 func TestIssue83(t *testing.T) {
13 dst := issue83My{Data: []int{1, 2, 3}}
14 new := issue83My{}
15 if err := mergo.Merge(&dst, new, mergo.WithOverwriteWithEmptyValue); err != nil {
16 t.Error(err)
17 }
18 if len(dst.Data) > 0 {
19 t.Errorf("expected empty slice, got %v", dst.Data)
20 }
21 }
0 package mergo
0 package mergo_test
11
22 import (
33 "testing"
4
5 "github.com/imdario/mergo"
46 )
57
68 type DstStructIssue84 struct {
2628 p2 := map[string]interface{}{
2729 "A": 3, "B": 4, "C": 0,
2830 }
29 if err := Map(&p1, p2, WithOverride); err != nil {
30 t.Fatalf("Error during the merge: %v", err)
31
32 if err := mergo.Map(&p1, p2, mergo.WithOverride); err != nil {
33 t.Errorf("Error during the merge: %v", err)
3134 }
35
3236 if p1.C != 0 {
3337 t.Error("C field should become '0'")
3438 }
4145 p2 := map[string]interface{}{
4246 "A": 3, "B": 4,
4347 }
44 if err := Map(&p1, p2, WithOverride); err != nil {
45 t.Fatalf("Error during the merge: %v", err)
48
49 if err := mergo.Map(&p1, p2, mergo.WithOverride); err != nil {
50 t.Errorf("Error during the merge: %v", err)
4651 }
52
4753 if p1.C != 2 {
4854 t.Error("C field should be '2'")
4955 }
6470 "A": 0, "B": 0, "C": 5,
6571 }, "B": 4, "C": 0,
6672 }
67 if err := Map(&p1, p2, WithOverride); err != nil {
68 t.Fatalf("Error during the merge: %v", err)
73
74 if err := mergo.Map(&p1, p2, mergo.WithOverride); err != nil {
75 t.Errorf("Error during the merge: %v", err)
6976 }
77
7078 if p1.B != 4 {
7179 t.Error("A.C field should become '4'")
7280 }
0 package mergo_test
1
2 import (
3 "testing"
4
5 "github.com/imdario/mergo"
6 )
7
8 func TestIssue89Boolean(t *testing.T) {
9 type Foo struct {
10 Bar bool `json:"bar"`
11 }
12
13 src := Foo{Bar: true}
14 dst := Foo{Bar: false}
15
16 if err := mergo.Merge(&dst, src); err != nil {
17 t.Error(err)
18 }
19 if dst.Bar == false {
20 t.Errorf("expected true, got false")
21 }
22 }
23
24 func TestIssue89MergeWithEmptyValue(t *testing.T) {
25 p1 := map[string]interface{}{
26 "A": 3, "B": "note", "C": true,
27 }
28 p2 := map[string]interface{}{
29 "B": "", "C": false,
30 }
31 if err := mergo.Merge(&p1, p2, mergo.WithOverwriteWithEmptyValue); err != nil {
32 t.Error(err)
33 }
34 testCases := []struct {
35 key string
36 expected interface{}
37 }{
38 {
39 "A",
40 3,
41 },
42 {
43 "B",
44 "",
45 },
46 {
47 "C",
48 false,
49 },
50 }
51 for _, tC := range testCases {
52 if p1[tC.key] != tC.expected {
53 t.Errorf("expected %v in p1[%q], got %v", tC.expected, tC.key, p1[tC.key])
54 }
55 }
56 }
0 package mergo_test
1
2 import (
3 "github.com/imdario/mergo"
4 "reflect"
5 "testing"
6 )
7
8 type structWithStringMap struct {
9 Data map[string]string
10 }
11
12
13 func TestIssue90(t *testing.T) {
14 dst := map[string]structWithStringMap{
15 "struct": {
16 Data: nil,
17 },
18 }
19 src := map[string]structWithStringMap{
20 "struct": {
21 Data: map[string]string{
22 "foo": "bar",
23 },
24 },
25 }
26 expected := map[string]structWithStringMap{
27 "struct": {
28 Data: map[string]string{
29 "foo": "bar",
30 },
31 },
32 }
33
34 err := mergo.Merge(&dst, src, mergo.WithOverride)
35 if err != nil {
36 t.Errorf("unexpected error %v", err)
37 }
38
39 if !reflect.DeepEqual(dst, expected) {
40 t.Errorf("expected: %#v\ngot: %#v", expected, dst)
41 }
42 }
0 package mergo_test
1
2 import (
3 "testing"
4
5 "github.com/imdario/mergo"
6 )
7
8 var testDataS = []struct {
9 S1 Student
10 S2 Student
11 ExpectedSlice []string
12 }{
13 {Student{"Jack", []string{"a", "B"}}, Student{"Tom", []string{"1"}}, []string{"1", "a", "B"}},
14 {Student{"Jack", []string{"a", "B"}}, Student{"Tom", []string{}}, []string{"a", "B"}},
15 {Student{"Jack", []string{}}, Student{"Tom", []string{"1"}}, []string{"1"}},
16 {Student{"Jack", []string{}}, Student{"Tom", []string{}}, []string{}},
17 }
18
19 func TestMergeSliceWithOverrideWithAppendSlice(t *testing.T) {
20 for _, data := range testDataS {
21 err := mergo.Merge(&data.S2, data.S1, mergo.WithOverride, mergo.WithAppendSlice)
22 if err != nil {
23 t.Errorf("Error while merging %s", err)
24 }
25
26 if len(data.S2.Books) != len(data.ExpectedSlice) {
27 t.Errorf("Got %d elements in slice, but expected %d", len(data.S2.Books), len(data.ExpectedSlice))
28 }
29
30 for i, val := range data.S2.Books {
31 if val != data.ExpectedSlice[i] {
32 t.Errorf("Expected %s, but got %s while merging slice with override", data.ExpectedSlice[i], val)
33 }
34 }
35 }
36 }
140140 }
141141
142142 func _map(dst, src interface{}, opts ...func(*Config)) error {
143 if dst != nil && reflect.ValueOf(dst).Kind() != reflect.Ptr {
144 return ErrNonPointerAgument
145 }
143146 var (
144147 vDst, vSrc reflect.Value
145148 err error
1212 "reflect"
1313 )
1414
15 func hasExportedField(dst reflect.Value) (exported bool) {
15 func hasMergeableFields(dst reflect.Value) (exported bool) {
1616 for i, n := 0, dst.NumField(); i < n; i++ {
1717 field := dst.Type().Field(i)
1818 if field.Anonymous && dst.Field(i).Kind() == reflect.Struct {
19 exported = exported || hasExportedField(dst.Field(i))
20 } else {
19 exported = exported || hasMergeableFields(dst.Field(i))
20 } else if isExportedComponent(&field) {
2121 exported = exported || len(field.PkgPath) == 0
2222 }
2323 }
2424 return
25 }
26
27 func isExportedComponent(field *reflect.StructField) bool {
28 pkgPath := field.PkgPath
29 if len(pkgPath) > 0 {
30 return false
31 }
32 c := field.Name[0]
33 if 'a' <= c && c <= 'z' || c == '_' {
34 return false
35 }
36 return true
2537 }
2638
2739 type Config struct {
3143 Transformers Transformers
3244 overwriteWithEmptyValue bool
3345 overwriteSliceWithEmptyValue bool
46 sliceDeepCopy bool
47 debug bool
3448 }
3549
3650 type Transformers interface {
4559 typeCheck := config.TypeCheck
4660 overwriteWithEmptySrc := config.overwriteWithEmptyValue
4761 overwriteSliceWithEmptySrc := config.overwriteSliceWithEmptyValue
48 config.overwriteWithEmptyValue = false
62 sliceDeepCopy := config.sliceDeepCopy
4963
5064 if !src.IsValid() {
5165 return
7387
7488 switch dst.Kind() {
7589 case reflect.Struct:
76 if hasExportedField(dst) {
90 if hasMergeableFields(dst) {
7791 for i, n := 0, dst.NumField(); i < n; i++ {
7892 if err = deepMerge(dst.Field(i), src.Field(i), visited, depth+1, config); err != nil {
7993 return
8094 }
8195 }
8296 } else {
83 if dst.CanSet() && (!isEmptyValue(src) || overwriteWithEmptySrc) && (overwrite || isEmptyValue(dst)) {
97 if dst.CanSet() && (isReflectNil(dst) || overwrite) && (!isEmptyValue(src) || overwriteWithEmptySrc) {
8498 dst.Set(src)
8599 }
86100 }
87101 case reflect.Map:
88102 if dst.IsNil() && !src.IsNil() {
89 dst.Set(reflect.MakeMap(dst.Type()))
90 }
103 if dst.CanSet() {
104 dst.Set(reflect.MakeMap(dst.Type()))
105 } else {
106 dst = src
107 return
108 }
109 }
110
111 if src.Kind() != reflect.Map {
112 if overwrite {
113 dst.Set(src)
114 }
115 return
116 }
117
91118 for _, key := range src.MapKeys() {
92119 srcElement := src.MapIndex(key)
93120 if !srcElement.IsValid() {
97124 switch srcElement.Kind() {
98125 case reflect.Chan, reflect.Func, reflect.Map, reflect.Interface, reflect.Slice:
99126 if srcElement.IsNil() {
127 if overwrite {
128 dst.SetMapIndex(key, srcElement)
129 }
100130 continue
101131 }
102132 fallthrough
131161 dstSlice = reflect.ValueOf(dstElement.Interface())
132162 }
133163
134 if (!isEmptyValue(src) || overwriteWithEmptySrc || overwriteSliceWithEmptySrc) && (overwrite || isEmptyValue(dst)) && !config.AppendSlice {
164 if (!isEmptyValue(src) || overwriteWithEmptySrc || overwriteSliceWithEmptySrc) && (overwrite || isEmptyValue(dst)) && !config.AppendSlice && !sliceDeepCopy {
135165 if typeCheck && srcSlice.Type() != dstSlice.Type() {
136166 return fmt.Errorf("cannot override two slices with different type (%s, %s)", srcSlice.Type(), dstSlice.Type())
137167 }
141171 return fmt.Errorf("cannot append two slices with different type (%s, %s)", srcSlice.Type(), dstSlice.Type())
142172 }
143173 dstSlice = reflect.AppendSlice(dstSlice, srcSlice)
174 } else if sliceDeepCopy {
175 i := 0
176 for ; i < srcSlice.Len() && i < dstSlice.Len(); i++ {
177 srcElement := srcSlice.Index(i)
178 dstElement := dstSlice.Index(i)
179
180 if srcElement.CanInterface() {
181 srcElement = reflect.ValueOf(srcElement.Interface())
182 }
183 if dstElement.CanInterface() {
184 dstElement = reflect.ValueOf(dstElement.Interface())
185 }
186
187 if err = deepMerge(dstElement, srcElement, visited, depth+1, config); err != nil {
188 return
189 }
190 }
191
144192 }
145193 dst.SetMapIndex(key, dstSlice)
146194 }
160208 if !dst.CanSet() {
161209 break
162210 }
163 if (!isEmptyValue(src) || overwriteWithEmptySrc || overwriteSliceWithEmptySrc) && (overwrite || isEmptyValue(dst)) && !config.AppendSlice {
211 if (!isEmptyValue(src) || overwriteWithEmptySrc || overwriteSliceWithEmptySrc) && (overwrite || isEmptyValue(dst)) && !config.AppendSlice && !sliceDeepCopy {
164212 dst.Set(src)
165213 } else if config.AppendSlice {
166214 if src.Type() != dst.Type() {
167215 return fmt.Errorf("cannot append two slice with different type (%s, %s)", src.Type(), dst.Type())
168216 }
169217 dst.Set(reflect.AppendSlice(dst, src))
218 } else if sliceDeepCopy {
219 for i := 0; i < src.Len() && i < dst.Len(); i++ {
220 srcElement := src.Index(i)
221 dstElement := dst.Index(i)
222 if srcElement.CanInterface() {
223 srcElement = reflect.ValueOf(srcElement.Interface())
224 }
225 if dstElement.CanInterface() {
226 dstElement = reflect.ValueOf(dstElement.Interface())
227 }
228
229 if err = deepMerge(dstElement, srcElement, visited, depth+1, config); err != nil {
230 return
231 }
232 }
170233 }
171234 case reflect.Ptr:
172235 fallthrough
173236 case reflect.Interface:
174 if src.IsNil() {
175 break
176 }
177
178 if dst.Kind() != reflect.Ptr && src.Type().AssignableTo(dst.Type()) {
179 if dst.IsNil() || overwrite {
180 if dst.CanSet() && (overwrite || isEmptyValue(dst)) {
181 dst.Set(src)
182 }
237 if isReflectNil(src) {
238 if overwriteWithEmptySrc && dst.CanSet() && src.Type().AssignableTo(dst.Type()) {
239 dst.Set(src)
183240 }
184241 break
185242 }
202259 }
203260 break
204261 }
262
205263 if dst.IsNil() || overwrite {
206264 if dst.CanSet() && (overwrite || isEmptyValue(dst)) {
207265 dst.Set(src)
208266 }
209 } else if err = deepMerge(dst.Elem(), src.Elem(), visited, depth+1, config); err != nil {
210 return
267 break
268 }
269
270 if dst.Elem().Kind() == src.Elem().Kind() {
271 if err = deepMerge(dst.Elem(), src.Elem(), visited, depth+1, config); err != nil {
272 return
273 }
274 break
211275 }
212276 default:
213 if dst.CanSet() && (!isEmptyValue(src) || overwriteWithEmptySrc) && (overwrite || isEmptyValue(dst)) {
214 dst.Set(src)
277 mustSet := (isEmptyValue(dst) || overwrite) && (!isEmptyValue(src) || overwriteWithEmptySrc)
278 if mustSet {
279 if dst.CanSet() {
280 dst.Set(src)
281 } else {
282 dst = src
283 }
215284 }
216285 }
217286
245314 config.Overwrite = true
246315 }
247316
248 // WithOverride will make merge override empty dst slice with empty src slice.
317 // WithOverwriteWithEmptyValue will make merge override non empty dst attributes with empty src attributes values.
318 func WithOverwriteWithEmptyValue(config *Config) {
319 config.Overwrite = true
320 config.overwriteWithEmptyValue = true
321 }
322
323 // WithOverrideEmptySlice will make merge override empty dst slice with empty src slice.
249324 func WithOverrideEmptySlice(config *Config) {
250325 config.overwriteSliceWithEmptyValue = true
251326 }
260335 config.TypeCheck = true
261336 }
262337
338 // WithSliceDeepCopy will merge slice element one by one with Overwrite flag.
339 func WithSliceDeepCopy(config *Config) {
340 config.sliceDeepCopy = true
341 config.Overwrite = true
342 }
343
263344 func merge(dst, src interface{}, opts ...func(*Config)) error {
345 if dst != nil && reflect.ValueOf(dst).Kind() != reflect.Ptr {
346 return ErrNonPointerAgument
347 }
264348 var (
265349 vDst, vSrc reflect.Value
266350 err error
280364 }
281365 return deepMerge(vDst, vSrc, make(map[uintptr]*visit), 0, config)
282366 }
367
368 // IsReflectNil is the reflect value provided nil
369 func isReflectNil(v reflect.Value) bool {
370 k := v.Kind()
371 switch k {
372 case reflect.Interface, reflect.Slice, reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr:
373 // Both interface and slice are nil if first word is 0.
374 // Both are always bigger than a word; assume flagIndir.
375 return v.IsNil()
376 default:
377 return false
378 }
379 }
+0
-33
merge_appendslice_test.go less more
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 }
+0
-42
merge_interface_concrete_test.go less more
0 package mergo
1
2 import (
3 "net/http"
4 "net/http/httptest"
5 "testing"
6 )
7
8 type ifaceTypesTest struct {
9 N int
10 Handler http.Handler
11 }
12
13 type ifaceTypesHandler int
14
15 func (*ifaceTypesHandler) ServeHTTP(rw http.ResponseWriter, _ *http.Request) {
16 rw.Header().Set("Test", "ifaceTypesHandler")
17 }
18
19 func TestMergeInterfaceWithDifferentConcreteTypes(t *testing.T) {
20 dst := ifaceTypesTest{
21 Handler: new(ifaceTypesHandler),
22 }
23
24 src := ifaceTypesTest{
25 N: 42,
26 Handler: http.HandlerFunc(func(rw http.ResponseWriter, _ *http.Request) {
27 rw.Header().Set("Test", "handlerFunc")
28 }),
29 }
30
31 if err := Merge(&dst, src); err != nil {
32 t.Errorf("Error while merging %s", err)
33 }
34
35 rw := httptest.NewRecorder()
36 dst.Handler.ServeHTTP(rw, nil)
37
38 if got, want := rw.Header().Get("Test"), "ifaceTypesHandler"; got != want {
39 t.Errorf("Handler not merged in properly: got %q header value %q, want %q", "Test", got, want)
40 }
41 }
0 package mergo
0 package mergo_test
11
22 import (
33 "reflect"
44 "testing"
5
6 "github.com/imdario/mergo"
57 )
68
79 type transformer struct {
2830 func TestMergeWithTransformerNilStruct(t *testing.T) {
2931 a := foo{s: "foo"}
3032 b := foo{Bar: &bar{i: 2, s: map[string]string{"foo": "bar"}}}
31 if err := Merge(&a, &b, WithOverride, WithTransformers(&transformer{
33
34 if err := mergo.Merge(&a, &b, mergo.WithOverride, mergo.WithTransformers(&transformer{
3235 m: map[reflect.Type]func(dst, src reflect.Value) error{
3336 reflect.TypeOf(&bar{}): func(dst, src reflect.Value) error {
3437 // Do sthg with Elem
3841 },
3942 },
4043 })); err != nil {
41 t.Fatal(err)
44 t.Error(err)
4245 }
46
4347 if a.s != "foo" {
44 t.Fatalf("b not merged in properly: a.s.Value(%s) != expected(%s)", a.s, "foo")
48 t.Errorf("b not merged in properly: a.s.Value(%s) != expected(%s)", a.s, "foo")
4549 }
50
4651 if a.Bar == nil {
47 t.Fatalf("b not merged in properly: a.Bar shouldn't be nil")
52 t.Errorf("b not merged in properly: a.Bar shouldn't be nil")
4853 }
4954 }
55
56 func TestMergeNonPointer(t *testing.T) {
57 dst := bar{
58 i: 1,
59 }
60 src := bar{
61 i: 2,
62 s: map[string]string{
63 "a": "1",
64 },
65 }
66 want := mergo.ErrNonPointerAgument
67
68 if got := mergo.Merge(dst, src); got != want {
69 t.Errorf("want: %s, got: %s", want, got)
70 }
71 }
72
73 func TestMapNonPointer(t *testing.T) {
74 dst := make(map[string]bar)
75 src := map[string]bar{
76 "a": {
77 i: 2,
78 s: map[string]string{
79 "a": "1",
80 },
81 },
82 }
83 want := mergo.ErrNonPointerAgument
84 if got := mergo.Merge(dst, src); got != want {
85 t.Errorf("want: %s, got: %s", want, got)
86 }
87 }
1919 ErrNotSupported = errors.New("only structs and maps are supported")
2020 ErrExpectedMapAsDestination = errors.New("dst was expected to be a map")
2121 ErrExpectedStructAsDestination = errors.New("dst was expected to be a struct")
22 ErrNonPointerAgument = errors.New("dst must be a pointer")
2223 )
2324
2425 // During deepMerge, must keep track of checks that are
7475 }
7576 return
7677 }
77
78 // Traverses recursively both values, assigning src's fields values to dst.
79 // The map argument tracks comparisons that have already been seen, which allows
80 // short circuiting on recursive types.
81 func deeper(dst, src reflect.Value, visited map[uintptr]*visit, depth int) (err error) {
82 if dst.CanAddr() {
83 addr := dst.UnsafeAddr()
84 h := 17 * addr
85 seen := visited[h]
86 typ := dst.Type()
87 for p := seen; p != nil; p = p.next {
88 if p.ptr == addr && p.typ == typ {
89 return nil
90 }
91 }
92 // Remember, remember...
93 visited[h] = &visit{addr, typ, seen}
94 }
95 return // TODO refactor
96 }
22 // Use of this source code is governed by a BSD-style
33 // license that can be found in the LICENSE file.
44
5 package mergo
5 package mergo_test
66
77 import (
88 "io/ioutil"
1111 "testing"
1212 "time"
1313
14 "github.com/stretchr/testify/assert"
15
14 "github.com/imdario/mergo"
1615 "gopkg.in/yaml.v2"
1716 )
1817
7675 expected.Name = "B"
7776 expected.KeyValue = ekv
7877
79 Merge(&b, a)
78 if err := mergo.Merge(&b, a); err != nil {
79 t.Error(err)
80 }
8081
8182 if !reflect.DeepEqual(b, expected) {
8283 t.Errorf("Actual: %#v did not match \nExpected: %#v", b, expected)
8485 }
8586
8687 func TestNil(t *testing.T) {
87 if err := Merge(nil, nil); err != ErrNilArguments {
88 if err := mergo.Merge(nil, nil); err != mergo.ErrNilArguments {
8889 t.Fail()
8990 }
9091 }
9293 func TestDifferentTypes(t *testing.T) {
9394 a := simpleTest{42}
9495 b := 42
95 if err := Merge(&a, b); err != ErrDifferentArgumentsTypes {
96 if err := mergo.Merge(&a, b); err != mergo.ErrDifferentArgumentsTypes {
9697 t.Fail()
9798 }
9899 }
100101 func TestSimpleStruct(t *testing.T) {
101102 a := simpleTest{}
102103 b := simpleTest{42}
103 if err := Merge(&a, b); err != nil {
104 if err := mergo.Merge(&a, b); err != nil {
104105 t.FailNow()
105106 }
106107 if a.Value != 42 {
107 t.Fatalf("b not merged in properly: a.Value(%d) != b.Value(%d)", a.Value, b.Value)
108 t.Errorf("b not merged in properly: a.Value(%d) != b.Value(%d)", a.Value, b.Value)
108109 }
109110 if !reflect.DeepEqual(a, b) {
110111 t.FailNow()
115116 a := complexTest{}
116117 a.ID = "athing"
117118 b := complexTest{simpleTest{42}, 1, "bthing"}
118 if err := Merge(&a, b); err != nil {
119 if err := mergo.Merge(&a, b); err != nil {
119120 t.FailNow()
120121 }
121122 if a.St.Value != 42 {
122 t.Fatalf("b not merged in properly: a.St.Value(%d) != b.St.Value(%d)", a.St.Value, b.St.Value)
123 t.Errorf("b not merged in properly: a.St.Value(%d) != b.St.Value(%d)", a.St.Value, b.St.Value)
123124 }
124125 if a.sz == 1 {
125 t.Fatalf("a's private field sz not preserved from merge: a.sz(%d) == b.sz(%d)", a.sz, b.sz)
126 t.Errorf("a's private field sz not preserved from merge: a.sz(%d) == b.sz(%d)", a.sz, b.sz)
126127 }
127128 if a.ID == b.ID {
128 t.Fatalf("a's field ID merged unexpectedly: a.ID(%s) == b.ID(%s)", a.ID, b.ID)
129 t.Errorf("a's field ID merged unexpectedly: a.ID(%s) == b.ID(%s)", a.ID, b.ID)
129130 }
130131 }
131132
134135 b := complexTest{simpleTest{42}, 2, ""}
135136
136137 expect := complexTest{simpleTest{42}, 1, "do-not-overwrite-with-empty-value"}
137 if err := MergeWithOverwrite(&a, b); err != nil {
138 if err := mergo.MergeWithOverwrite(&a, b); err != nil {
138139 t.FailNow()
139140 }
140141
141142 if !reflect.DeepEqual(a, expect) {
142 t.Fatalf("Test failed:\ngot :\n%#v\n\nwant :\n%#v\n\n", a, expect)
143 t.Errorf("Test failed:\ngot :\n%#v\n\nwant :\n%#v\n\n", a, expect)
143144 }
144145 }
145146
148149 s2 := simpleTest{19}
149150 a := pointerTest{&s1}
150151 b := pointerTest{&s2}
151 if err := Merge(&a, b); err != nil {
152 if err := mergo.Merge(&a, b); err != nil {
152153 t.FailNow()
153154 }
154155 if a.C.Value != b.C.Value {
155 t.Fatalf("b not merged in properly: a.C.Value(%d) != b.C.Value(%d)", a.C.Value, b.C.Value)
156 t.Errorf("b not merged in properly: a.C.Value(%d) != b.C.Value(%d)", a.C.Value, b.C.Value)
156157 }
157158 }
158159
206207 }
207208
208209 for _, test := range tests {
209 err := Merge(&test.dst, test.src)
210 err := mergo.Merge(&test.dst, test.src)
210211 if err != nil {
211212 t.Errorf("unexpected error: %v", err)
212213 continue
220221 func TestPointerStructNil(t *testing.T) {
221222 a := pointerTest{nil}
222223 b := pointerTest{&simpleTest{19}}
223 if err := Merge(&a, b); err != nil {
224 if err := mergo.Merge(&a, b); err != nil {
224225 t.FailNow()
225226 }
226227 if a.C.Value != b.C.Value {
227 t.Fatalf("b not merged in a properly: a.C.Value(%d) != b.C.Value(%d)", a.C.Value, b.C.Value)
228 }
229 }
230
231 func testSlice(t *testing.T, a []int, b []int, e []int, opts ...func(*Config)) {
228 t.Errorf("b not merged in a properly: a.C.Value(%d) != b.C.Value(%d)", a.C.Value, b.C.Value)
229 }
230 }
231
232 func testSlice(t *testing.T, a []int, b []int, e []int, opts ...func(*mergo.Config)) {
232233 t.Helper()
233234 bc := b
234235
235236 sa := sliceTest{a}
236237 sb := sliceTest{b}
237 if err := Merge(&sa, sb, opts...); err != nil {
238 if err := mergo.Merge(&sa, sb, opts...); err != nil {
238239 t.FailNow()
239240 }
240241 if !reflect.DeepEqual(sb.S, bc) {
241 t.Fatalf("Source slice was modified %d != %d", sb.S, bc)
242 t.Errorf("Source slice was modified %d != %d", sb.S, bc)
242243 }
243244 if !reflect.DeepEqual(sa.S, e) {
244 t.Fatalf("b not merged in a proper way %d != %d", sa.S, e)
245 t.Errorf("b not merged in a proper way %d != %d", sa.S, e)
245246 }
246247
247248 ma := map[string][]int{"S": a}
248249 mb := map[string][]int{"S": b}
249 if err := Merge(&ma, mb, opts...); err != nil {
250 if err := mergo.Merge(&ma, mb, opts...); err != nil {
250251 t.FailNow()
251252 }
252253 if !reflect.DeepEqual(mb["S"], bc) {
253 t.Fatalf("map value: Source slice was modified %d != %d", mb["S"], bc)
254 t.Errorf("map value: Source slice was modified %d != %d", mb["S"], bc)
254255 }
255256 if !reflect.DeepEqual(ma["S"], e) {
256 t.Fatalf("map value: b not merged in a proper way %d != %d", ma["S"], e)
257 t.Errorf("map value: b not merged in a proper way %d != %d", ma["S"], e)
257258 }
258259
259260 if a == nil {
260261 // test case with missing dst key
261262 ma := map[string][]int{}
262263 mb := map[string][]int{"S": b}
263 if err := Merge(&ma, mb); err != nil {
264 if err := mergo.Merge(&ma, mb); err != nil {
264265 t.FailNow()
265266 }
266267 if !reflect.DeepEqual(mb["S"], bc) {
267 t.Fatalf("missing dst key: Source slice was modified %d != %d", mb["S"], bc)
268 t.Errorf("missing dst key: Source slice was modified %d != %d", mb["S"], bc)
268269 }
269270 if !reflect.DeepEqual(ma["S"], e) {
270 t.Fatalf("missing dst key: b not merged in a proper way %d != %d", ma["S"], e)
271 t.Errorf("missing dst key: b not merged in a proper way %d != %d", ma["S"], e)
271272 }
272273 }
273274
275276 // test case with missing src key
276277 ma := map[string][]int{"S": a}
277278 mb := map[string][]int{}
278 if err := Merge(&ma, mb); err != nil {
279 if err := mergo.Merge(&ma, mb); err != nil {
279280 t.FailNow()
280281 }
281282 if !reflect.DeepEqual(mb["S"], bc) {
282 t.Fatalf("missing src key: Source slice was modified %d != %d", mb["S"], bc)
283 t.Errorf("missing src key: Source slice was modified %d != %d", mb["S"], bc)
283284 }
284285 if !reflect.DeepEqual(ma["S"], e) {
285 t.Fatalf("missing src key: b not merged in a proper way %d != %d", ma["S"], e)
286 t.Errorf("missing src key: b not merged in a proper way %d != %d", ma["S"], e)
286287 }
287288 }
288289 }
293294 testSlice(t, []int{1}, []int{2, 3}, []int{1})
294295 testSlice(t, []int{1}, []int{}, []int{1})
295296 testSlice(t, []int{1}, nil, []int{1})
296 testSlice(t, nil, []int{1, 2, 3}, []int{1, 2, 3}, WithAppendSlice)
297 testSlice(t, []int{}, []int{1, 2, 3}, []int{1, 2, 3}, WithAppendSlice)
298 testSlice(t, []int{1}, []int{2, 3}, []int{1, 2, 3}, WithAppendSlice)
299 testSlice(t, []int{1}, []int{2, 3}, []int{1, 2, 3}, WithAppendSlice, WithOverride)
300 testSlice(t, []int{1}, []int{}, []int{1}, WithAppendSlice)
301 testSlice(t, []int{1}, nil, []int{1}, WithAppendSlice)
297 testSlice(t, nil, []int{1, 2, 3}, []int{1, 2, 3}, mergo.WithAppendSlice)
298 testSlice(t, []int{}, []int{1, 2, 3}, []int{1, 2, 3}, mergo.WithAppendSlice)
299 testSlice(t, []int{1}, []int{2, 3}, []int{1, 2, 3}, mergo.WithAppendSlice)
300 testSlice(t, []int{1}, []int{2, 3}, []int{1, 2, 3}, mergo.WithAppendSlice, mergo.WithOverride)
301 testSlice(t, []int{1}, []int{}, []int{1}, mergo.WithAppendSlice)
302 testSlice(t, []int{1}, nil, []int{1}, mergo.WithAppendSlice)
302303 }
303304
304305 func TestEmptyMaps(t *testing.T) {
306307 b := mapTest{
307308 map[int]int{},
308309 }
309 if err := Merge(&a, b); err != nil {
310 if err := mergo.Merge(&a, b); err != nil {
310311 t.Fail()
311312 }
312313 if !reflect.DeepEqual(a, b) {
317318 func TestEmptyToEmptyMaps(t *testing.T) {
318319 a := mapTest{}
319320 b := mapTest{}
320 if err := Merge(&a, b); err != nil {
321 if err := mergo.Merge(&a, b); err != nil {
321322 t.Fail()
322323 }
323324 if !reflect.DeepEqual(a, b) {
337338 b := mapTest{
338339 map[int]int{},
339340 }
340 if err := Merge(&a, b); err != nil {
341 if err := mergo.Merge(&a, b); err != nil {
341342 t.Fail()
342343 }
343344 if !reflect.DeepEqual(a, aa) {
366367 "e": {14},
367368 }
368369
369 if err := MergeWithOverwrite(&m, n); err != nil {
370 t.Fatalf(err.Error())
370 if err := mergo.MergeWithOverwrite(&m, n); err != nil {
371 t.Errorf(err.Error())
371372 }
372373
373374 if !reflect.DeepEqual(m, expect) {
374 t.Fatalf("Test failed:\ngot :\n%#v\n\nwant :\n%#v\n\n", m, expect)
375 t.Errorf("Test failed:\ngot :\n%#v\n\nwant :\n%#v\n\n", m, expect)
375376 }
376377 }
377378
396397 "e": {14},
397398 }
398399
399 if err := Merge(&m, n, WithOverride); err != nil {
400 t.Fatalf(err.Error())
401 }
402
403 assert.Equalf(t, expect, m, "Test Failed")
400 if err := mergo.Merge(&m, n, mergo.WithOverride); err != nil {
401 t.Errorf(err.Error())
402 }
403
404404 if !reflect.DeepEqual(m, expect) {
405 t.Fatalf("Test failed:\ngot :\n%#v\n\nwant :\n%#v\n\n", m, expect)
405 t.Errorf("Test failed:\ngot :\n%#v\n\nwant :\n%#v\n\n", m, expect)
406406 }
407407 }
408408
523523 t.Run(tc.name, func(t *testing.T) {
524524 var err error
525525 if tc.overwrite {
526 err = Merge(tc.target, *tc.changes, WithOverride)
526 err = mergo.Merge(tc.target, *tc.changes, mergo.WithOverride)
527527 } else {
528 err = Merge(tc.target, *tc.changes)
528 err = mergo.Merge(tc.target, *tc.changes)
529529 }
530530 if err != nil {
531531 t.Error(err)
532532 }
533533 if !reflect.DeepEqual(tc.target, tc.output) {
534 t.Fatalf("Test failed:\ngot :\n%#v\n\nwant :\n%#v\n\n", tc.target, tc.output)
534 t.Errorf("Test failed:\ngot :\n%+v\n\nwant :\n%+v\n\n", tc.target.Params, tc.output.Params)
535535 }
536536 })
537537 }
557557 "e": {14},
558558 }
559559
560 if err := Merge(&m, n); err != nil {
561 t.Fatalf(err.Error())
560 if err := mergo.Merge(&m, n); err != nil {
561 t.Errorf(err.Error())
562562 }
563563
564564 if !reflect.DeepEqual(m, expect) {
565 t.Fatalf("Test failed:\ngot :\n%#v\n\nwant :\n%#v\n\n", m, expect)
565 t.Errorf("Test failed:\ngot :\n%#v\n\nwant :\n%#v\n\n", m, expect)
566566 }
567567 if m["a"].Value != 0 {
568 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)
568 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)
569569 }
570570 if m["b"].Value != 42 {
571 t.Fatalf(`n wrongly merged in m: m["b"].Value(%d) != n["b"].Value(%d)`, m["b"].Value, n["b"].Value)
571 t.Errorf(`n wrongly merged in m: m["b"].Value(%d) != n["b"].Value(%d)`, m["b"].Value, n["b"].Value)
572572 }
573573 if m["c"].Value != 13 {
574 t.Fatalf(`n overwritten in m: m["c"].Value(%d) != n["c"].Value(%d)`, m["c"].Value, n["c"].Value)
574 t.Errorf(`n overwritten in m: m["c"].Value(%d) != n["c"].Value(%d)`, m["c"].Value, n["c"].Value)
575575 }
576576 }
577577
590590 "c": nil,
591591 }
592592
593 if err := Merge(&m, n, WithOverride); err != nil {
594 t.Fatalf(err.Error())
593 if err := mergo.Merge(&m, n, mergo.WithOverride); err != nil {
594 t.Errorf(err.Error())
595595 }
596596
597597 if !reflect.DeepEqual(m, expect) {
598 t.Fatalf("Test failed:\ngot :\n%#v\n\nwant :\n%#v\n\n", m, expect)
598 t.Errorf("Test failed:\ngot :\n%#v\n\nwant :\n%#v\n\n", m, expect)
599599 }
600600 }
601601
606606 fl := license["fields"].(map[interface{}]interface{})
607607 // license has one extra field (site) and another already existing in thing (author) that Mergo won't override.
608608 expectedLength := len(ft) + len(fl) - 1
609 if err := Merge(&license, thing); err != nil {
610 t.Fatal(err.Error())
609 if err := mergo.Merge(&license, thing); err != nil {
610 t.Error(err.Error())
611611 }
612612 currentLength := len(license["fields"].(map[interface{}]interface{}))
613613 if currentLength != expectedLength {
614 t.Fatalf(`thing not merged in license properly, license must have %d elements instead of %d`, expectedLength, currentLength)
614 t.Errorf(`thing not merged in license properly, license must have %d elements instead of %d`, expectedLength, currentLength)
615615 }
616616 fields := license["fields"].(map[interface{}]interface{})
617617 if _, ok := fields["id"]; !ok {
618 t.Fatalf(`thing not merged in license properly, license must have a new id field from thing`)
618 t.Errorf(`thing not merged in license properly, license must have a new id field from thing`)
619619 }
620620 }
621621
622622 func TestTwoPointerValues(t *testing.T) {
623623 a := &simpleTest{}
624624 b := &simpleTest{42}
625 if err := Merge(a, b); err != nil {
626 t.Fatalf(`Boom. You crossed the streams: %s`, err)
625 if err := mergo.Merge(a, b); err != nil {
626 t.Errorf(`Boom. You crossed the streams: %s`, err)
627627 }
628628 }
629629
643643 "zt": simpleTest{299}, // Mapping a missing field (zt doesn't exist)
644644 "nt": simpleTest{3},
645645 }
646 if err := Map(&c, b); err != nil {
646 if err := mergo.Map(&c, b); err != nil {
647647 t.FailNow()
648648 }
649649 m := b["ct"].(map[string]interface{})
651651 o := b["st"].(*simpleTest)
652652 p := b["nt"].(simpleTest)
653653 if c.Ct.St.Value != 42 {
654 t.Fatalf("b not merged in properly: c.Ct.St.Value(%d) != b.Ct.St.Value(%d)", c.Ct.St.Value, n["value"])
654 t.Errorf("b not merged in properly: c.Ct.St.Value(%d) != b.Ct.St.Value(%d)", c.Ct.St.Value, n["value"])
655655 }
656656 if c.St.Value != 144 {
657 t.Fatalf("b not merged in properly: c.St.Value(%d) != b.St.Value(%d)", c.St.Value, o.Value)
657 t.Errorf("b not merged in properly: c.St.Value(%d) != b.St.Value(%d)", c.St.Value, o.Value)
658658 }
659659 if c.Nt.Value != 3 {
660 t.Fatalf("b not merged in properly: c.Nt.Value(%d) != b.Nt.Value(%d)", c.St.Value, p.Value)
660 t.Errorf("b not merged in properly: c.Nt.Value(%d) != b.Nt.Value(%d)", c.St.Value, p.Value)
661661 }
662662 if c.Ct.sz == 1 {
663 t.Fatalf("a's private field sz not preserved from merge: c.Ct.sz(%d) == b.Ct.sz(%d)", c.Ct.sz, m["sz"])
663 t.Errorf("a's private field sz not preserved from merge: c.Ct.sz(%d) == b.Ct.sz(%d)", c.Ct.sz, m["sz"])
664664 }
665665 if c.Ct.ID == m["id"] {
666 t.Fatalf("a's field ID merged unexpectedly: c.Ct.ID(%s) == b.Ct.ID(%s)", c.Ct.ID, m["id"])
666 t.Errorf("a's field ID merged unexpectedly: c.Ct.ID(%s) == b.Ct.ID(%s)", c.Ct.ID, m["id"])
667667 }
668668 }
669669
672672 b := map[string]interface{}{
673673 "value": 42,
674674 }
675 if err := Map(&a, b); err != nil {
675 if err := mergo.Map(&a, b); err != nil {
676676 t.FailNow()
677677 }
678678 if a.Value != 42 {
679 t.Fatalf("b not merged in properly: a.Value(%d) != b.Value(%v)", a.Value, b["value"])
679 t.Errorf("b not merged in properly: a.Value(%d) != b.Value(%v)", a.Value, b["value"])
680680 }
681681 }
682682
683683 func TestIfcMap(t *testing.T) {
684684 a := ifcTest{}
685685 b := ifcTest{42}
686 if err := Map(&a, b); err != nil {
686 if err := mergo.Map(&a, b); err != nil {
687687 t.FailNow()
688688 }
689689 if a.I != 42 {
690 t.Fatalf("b not merged in properly: a.I(%d) != b.I(%d)", a.I, b.I)
690 t.Errorf("b not merged in properly: a.I(%d) != b.I(%d)", a.I, b.I)
691691 }
692692 if !reflect.DeepEqual(a, b) {
693693 t.FailNow()
697697 func TestIfcMapNoOverwrite(t *testing.T) {
698698 a := ifcTest{13}
699699 b := ifcTest{42}
700 if err := Map(&a, b); err != nil {
700 if err := mergo.Map(&a, b); err != nil {
701701 t.FailNow()
702702 }
703703 if a.I != 13 {
704 t.Fatalf("a not left alone: a.I(%d) == b.I(%d)", a.I, b.I)
704 t.Errorf("a not left alone: a.I(%d) == b.I(%d)", a.I, b.I)
705705 }
706706 }
707707
708708 func TestIfcMapWithOverwrite(t *testing.T) {
709709 a := ifcTest{13}
710710 b := ifcTest{42}
711 if err := MapWithOverwrite(&a, b); err != nil {
711 if err := mergo.MapWithOverwrite(&a, b); err != nil {
712712 t.FailNow()
713713 }
714714 if a.I != 42 {
715 t.Fatalf("b not merged in properly: a.I(%d) != b.I(%d)", a.I, b.I)
715 t.Errorf("b not merged in properly: a.I(%d) != b.I(%d)", a.I, b.I)
716716 }
717717 if !reflect.DeepEqual(a, b) {
718718 t.FailNow()
728728 func TestBackAndForth(t *testing.T) {
729729 pt := pointerMapTest{42, 1, &simpleTest{66}}
730730 m := make(map[string]interface{})
731 if err := Map(&m, pt); err != nil {
731 if err := mergo.Map(&m, pt); err != nil {
732732 t.FailNow()
733733 }
734734 var (
736736 ok bool
737737 )
738738 if v, ok = m["a"]; v.(int) != pt.A || !ok {
739 t.Fatalf("pt not merged in properly: m[`a`](%d) != pt.A(%d)", v, pt.A)
739 t.Errorf("pt not merged in properly: m[`a`](%d) != pt.A(%d)", v, pt.A)
740740 }
741741 if v, ok = m["b"]; !ok {
742 t.Fatalf("pt not merged in properly: B is missing in m")
742 t.Errorf("pt not merged in properly: B is missing in m")
743743 }
744744 var st *simpleTest
745745 if st = v.(*simpleTest); st.Value != 66 {
746 t.Fatalf("something went wrong while mapping pt on m, B wasn't copied")
746 t.Errorf("something went wrong while mapping pt on m, B wasn't copied")
747747 }
748748 bpt := pointerMapTest{}
749 if err := Map(&bpt, m); err != nil {
750 t.Fatal(err)
749 if err := mergo.Map(&bpt, m); err != nil {
750 t.Error(err)
751751 }
752752 if bpt.A != pt.A {
753 t.Fatalf("pt not merged in properly: bpt.A(%d) != pt.A(%d)", bpt.A, pt.A)
753 t.Errorf("pt not merged in properly: bpt.A(%d) != pt.A(%d)", bpt.A, pt.A)
754754 }
755755 if bpt.hidden == pt.hidden {
756 t.Fatalf("pt unexpectedly merged: bpt.hidden(%d) == pt.hidden(%d)", bpt.hidden, pt.hidden)
756 t.Errorf("pt unexpectedly merged: bpt.hidden(%d) == pt.hidden(%d)", bpt.hidden, pt.hidden)
757757 }
758758 if bpt.B.Value != pt.B.Value {
759 t.Fatalf("pt not merged in properly: bpt.B.Value(%d) != pt.B.Value(%d)", bpt.B.Value, pt.B.Value)
759 t.Errorf("pt not merged in properly: bpt.B.Value(%d) != pt.B.Value(%d)", bpt.B.Value, pt.B.Value)
760760 }
761761 }
762762
773773 }
774774 for _, test := range tests {
775775 pt := test.input
776 if err := MapWithOverwrite(&pt, m); err != nil {
776 if err := mergo.MapWithOverwrite(&pt, m); err != nil {
777777 t.FailNow()
778778 }
779779 if pt.B.Value != newValue {
780 t.Fatalf("pt not mapped properly: pt.A.Value(%d) != m[`b`][`value`](%d)", pt.B.Value, newValue)
780 t.Errorf("pt not mapped properly: pt.A.Value(%d) != m[`b`][`value`](%d)", pt.B.Value, newValue)
781781 }
782782
783783 }
796796 "Birth": &now,
797797 }
798798 b := structWithTimePointer{}
799 if err := Merge(&b, dataStruct); err != nil {
799 if err := mergo.Merge(&b, dataStruct); err != nil {
800800 t.FailNow()
801801 }
802802 if b.Birth.IsZero() {
803 t.Fatalf("time.Time not merged in properly: b.Birth(%v) != dataStruct['Birth'](%v)", b.Birth, dataStruct.Birth)
803 t.Errorf("time.Time not merged in properly: b.Birth(%v) != dataStruct['Birth'](%v)", b.Birth, dataStruct.Birth)
804804 }
805805 if b.Birth != dataStruct.Birth {
806 t.Fatalf("time.Time not merged in properly: b.Birth(%v) != dataStruct['Birth'](%v)", b.Birth, dataStruct.Birth)
806 t.Errorf("time.Time not merged in properly: b.Birth(%v) != dataStruct['Birth'](%v)", b.Birth, dataStruct.Birth)
807807 }
808808 b = structWithTimePointer{}
809 if err := Map(&b, dataMap); err != nil {
809 if err := mergo.Map(&b, dataMap); err != nil {
810810 t.FailNow()
811811 }
812812 if b.Birth.IsZero() {
813 t.Fatalf("time.Time not merged in properly: b.Birth(%v) != dataMap['Birth'](%v)", b.Birth, dataMap["Birth"])
813 t.Errorf("time.Time not merged in properly: b.Birth(%v) != dataMap['Birth'](%v)", b.Birth, dataMap["Birth"])
814814 }
815815 }
816816
835835 "x": {},
836836 },
837837 }
838 if err := Map(dst, src); err != nil {
838 if err := mergo.Map(dst, src); err != nil {
839839 t.FailNow()
840840 }
841841 if dst.NestedPtrValue["x"].A == 0 {
842 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)
842 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)
843843 }
844844 }
845845
870870 t.Errorf("Should not have panicked")
871871 }
872872 }()
873 Merge(&a, b)
873 mergo.Merge(&a, b)
874874 }
875875
876876 type structWithBoolPointer struct {
885885 dst := structWithBoolPointer{
886886 &bf,
887887 }
888 if err := Merge(&dst, src); err != nil {
888 if err := mergo.Merge(&dst, src); err != nil {
889889 t.FailNow()
890890 }
891891 if dst.C == src.C {
892 t.Fatalf("dst.C should be a different pointer than src.C")
892 t.Errorf("dst.C should be a different pointer than src.C")
893893 }
894894 if *dst.C != *src.C {
895 t.Fatalf("dst.C should be true")
895 t.Errorf("dst.C should be true")
896896 }
897897 }
898898
899899 func TestMergeMapWithInnerSliceOfDifferentType(t *testing.T) {
900900 testCases := []struct {
901901 name string
902 options []func(*Config)
902 options []func(*mergo.Config)
903903 err string
904904 }{
905905 {
906906 "With override and append slice",
907 []func(*Config){WithOverride, WithAppendSlice},
907 []func(*mergo.Config){mergo.WithOverride, mergo.WithAppendSlice},
908908 "cannot append two slices with different type",
909909 },
910910 {
911911 "With override and type check",
912 []func(*Config){WithOverride, WithTypeCheck},
912 []func(*mergo.Config){mergo.WithOverride, mergo.WithTypeCheck},
913913 "cannot override two slices with different type",
914914 },
915915 }
922922 "foo": []int{1, 2},
923923 }
924924
925 if err := Merge(&src, &dst, tc.options...); err == nil || !strings.Contains(err.Error(), tc.err) {
926 t.Fatalf("expected %q, got %q", tc.err, err)
925 if err := mergo.Merge(&src, &dst, tc.options...); err == nil || !strings.Contains(err.Error(), tc.err) {
926 t.Errorf("expected %q, got %q", tc.err, err)
927927 }
928928 })
929929 }
933933 src := []string{"a", "b"}
934934 dst := []int{1, 2}
935935
936 if err := Merge(&src, &dst, WithOverride, WithAppendSlice); err != ErrNotSupported {
937 t.Fatalf("expected %q, got %q", ErrNotSupported, err)
938 }
939 }
936 if err := mergo.Merge(&src, &dst, mergo.WithOverride, mergo.WithAppendSlice); err != mergo.ErrNotSupported {
937 t.Errorf("expected %q, got %q", mergo.ErrNotSupported, err)
938 }
939 }
0 package mergo
0 package mergo_test
11
22 import (
33 "testing"
4
5 "github.com/imdario/mergo"
46 )
57
68 type mapInterface map[string]interface{}
810 func TestMergeMapsEmptyString(t *testing.T) {
911 a := mapInterface{"s": ""}
1012 b := mapInterface{"s": "foo"}
11 if err := Merge(&a, b); err != nil {
12 t.Fatal(err)
13 if err := mergo.Merge(&a, b); err != nil {
14 t.Error(err)
1315 }
1416 if a["s"] != "foo" {
15 t.Fatalf("b not merged in properly: a.s.Value(%s) != expected(%s)", a["s"], "foo")
17 t.Errorf("b not merged in properly: a.s.Value(%s) != expected(%s)", a["s"], "foo")
1618 }
1719 }
0 package mergo
0 package mergo_test
11
22 import (
33 "testing"
4
5 "github.com/imdario/mergo"
46 )
57
68 func TestMapInterfaceWithMultipleLayer(t *testing.T) {
1719 },
1820 }
1921
20 if err := Map(&m1, m2, WithOverride); err != nil {
21 t.Fatalf("Error merging: %v", err)
22 if err := mergo.Map(&m1, m2, mergo.WithOverride); err != nil {
23 t.Errorf("Error merging: %v", err)
2224 }
2325
2426 // Check overwrite of sub map works
2527 expected := "v2"
2628 actual := m1["k1"].(map[string]interface{})["k1.1"].(string)
2729 if actual != expected {
28 t.Fatalf("Expected %v but got %v",
30 t.Errorf("Expected %v but got %v",
2931 expected,
3032 actual)
3133 }
3436 expected = "v3"
3537 actual = m1["k1"].(map[string]interface{})["k1.2"].(string)
3638 if actual != expected {
37 t.Fatalf("Expected %v but got %v",
39 t.Errorf("Expected %v but got %v",
3840 expected,
3941 actual)
4042 }
0 package mergo_test
1
2 import (
3 "testing"
4
5 "github.com/imdario/mergo"
6 )
7
8 type inner struct {
9 A int
10 }
11
12 type outer struct {
13 inner
14 B int
15 }
16
17 func TestV039Issue139(t *testing.T) {
18 dst := outer{
19 inner: inner{A: 1},
20 B: 2,
21 }
22 src := outer{
23 inner: inner{A: 10},
24 B: 20,
25 }
26 err := mergo.MergeWithOverwrite(&dst, src)
27 if err != nil {
28 panic(err.Error())
29 }
30 if dst.inner.A == 1 {
31 t.Errorf("expected %d, got %d", src.inner.A, dst.inner.A)
32 }
33 }
34
35 func TestV039Issue152(t *testing.T) {
36 dst := map[string]interface{}{
37 "properties": map[string]interface{}{
38 "field1": map[string]interface{}{
39 "type": "text",
40 },
41 "field2": "ohai",
42 },
43 }
44 src := map[string]interface{}{
45 "properties": map[string]interface{}{
46 "field1": "wrong",
47 },
48 }
49 if err := mergo.Map(&dst, src, mergo.WithOverride); err != nil {
50 t.Error(err)
51 }
52 }
53
54 type issue146Foo struct {
55 A string
56 B map[string]issue146Bar
57 }
58
59 type issue146Bar struct {
60 C *string
61 D *string
62 }
63
64 func TestV039Issue146(t *testing.T) {
65 var (
66 s1 = "asd"
67 s2 = "sdf"
68 )
69 dst := issue146Foo{
70 A: "two",
71 B: map[string]issue146Bar{
72 "foo": {
73 C: &s1,
74 },
75 },
76 }
77 src := issue146Foo{
78 A: "one",
79 B: map[string]issue146Bar{
80 "foo": {
81 D: &s2,
82 },
83 },
84 }
85 if err := mergo.Merge(&dst, src, mergo.WithOverride); err != nil {
86 t.Error(err)
87 }
88 if dst.B["foo"].D == nil {
89 t.Errorf("expected %v, got nil", &s2)
90 }
91 }