Fix the dependency issue (#231)
This commit is contained in:
2
vendor/github.com/imdario/mergo/.travis.yml
generated
vendored
2
vendor/github.com/imdario/mergo/.travis.yml
generated
vendored
@@ -1,2 +0,0 @@
|
||||
language: go
|
||||
install: go get -t
|
||||
46
vendor/github.com/imdario/mergo/CODE_OF_CONDUCT.md
generated
vendored
46
vendor/github.com/imdario/mergo/CODE_OF_CONDUCT.md
generated
vendored
@@ -1,46 +0,0 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at i@dario.im. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
|
||||
|
||||
[homepage]: http://contributor-covenant.org
|
||||
[version]: http://contributor-covenant.org/version/1/4/
|
||||
141
vendor/github.com/imdario/mergo/README.md
generated
vendored
141
vendor/github.com/imdario/mergo/README.md
generated
vendored
@@ -1,141 +0,0 @@
|
||||
# Mergo
|
||||
|
||||
A helper to merge structs and maps in Golang. Useful for configuration default values, avoiding messy if-statements.
|
||||
|
||||
Also a lovely [comune](http://en.wikipedia.org/wiki/Mergo) (municipality) in the Province of Ancona in the Italian region Marche.
|
||||
|
||||

|
||||
|
||||
## Status
|
||||
|
||||
It is ready for production use. It works fine after extensive use in the wild.
|
||||
|
||||
[![Build Status][1]][2]
|
||||
[![GoDoc][3]][4]
|
||||
[![GoCard][5]][6]
|
||||
|
||||
[1]: https://travis-ci.org/imdario/mergo.png
|
||||
[2]: https://travis-ci.org/imdario/mergo
|
||||
[3]: https://godoc.org/github.com/imdario/mergo?status.svg
|
||||
[4]: https://godoc.org/github.com/imdario/mergo
|
||||
[5]: https://goreportcard.com/badge/imdario/mergo
|
||||
[6]: https://goreportcard.com/report/github.com/imdario/mergo
|
||||
|
||||
### Important note
|
||||
|
||||
Mergo is intended to assign **only** zero value fields on destination with source value. Since April 6th it works like this. Before it didn't work properly, causing some random overwrites. After some issues and PRs I found it didn't merge as I designed it. Thanks to [imdario/mergo#8](https://github.com/imdario/mergo/pull/8) overwriting functions were added and the wrong behavior was clearly detected.
|
||||
|
||||
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).
|
||||
|
||||
### Mergo in the wild
|
||||
|
||||
- [docker/docker](https://github.com/docker/docker/)
|
||||
- [kubernetes/kubernetes](https://github.com/kubernetes/kubernetes)
|
||||
- [imdario/zas](https://github.com/imdario/zas)
|
||||
- [soniah/dnsmadeeasy](https://github.com/soniah/dnsmadeeasy)
|
||||
- [EagerIO/Stout](https://github.com/EagerIO/Stout)
|
||||
- [lynndylanhurley/defsynth-api](https://github.com/lynndylanhurley/defsynth-api)
|
||||
- [russross/canvasassignments](https://github.com/russross/canvasassignments)
|
||||
- [rdegges/cryptly-api](https://github.com/rdegges/cryptly-api)
|
||||
- [casualjim/exeggutor](https://github.com/casualjim/exeggutor)
|
||||
- [divshot/gitling](https://github.com/divshot/gitling)
|
||||
- [RWJMurphy/gorl](https://github.com/RWJMurphy/gorl)
|
||||
- [andrerocker/deploy42](https://github.com/andrerocker/deploy42)
|
||||
- [elwinar/rambler](https://github.com/elwinar/rambler)
|
||||
- [tmaiaroto/gopartman](https://github.com/tmaiaroto/gopartman)
|
||||
- [jfbus/impressionist](https://github.com/jfbus/impressionist)
|
||||
- [Jmeyering/zealot](https://github.com/Jmeyering/zealot)
|
||||
- [godep-migrator/rigger-host](https://github.com/godep-migrator/rigger-host)
|
||||
- [Dronevery/MultiwaySwitch-Go](https://github.com/Dronevery/MultiwaySwitch-Go)
|
||||
- [thoas/picfit](https://github.com/thoas/picfit)
|
||||
- [mantasmatelis/whooplist-server](https://github.com/mantasmatelis/whooplist-server)
|
||||
- [jnuthong/item_search](https://github.com/jnuthong/item_search)
|
||||
- [Iris Web Framework](https://github.com/kataras/iris)
|
||||
|
||||
## Installation
|
||||
|
||||
go get github.com/imdario/mergo
|
||||
|
||||
// use in your .go code
|
||||
import (
|
||||
"github.com/imdario/mergo"
|
||||
)
|
||||
|
||||
## Usage
|
||||
|
||||
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. Also maps will be merged recursively except for structs inside maps (because they are not addressable using Go reflection).
|
||||
|
||||
```go
|
||||
if err := mergo.Merge(&dst, src); err != nil {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
Also, you can merge overwriting values using MergeWithOverwrite.
|
||||
|
||||
```go
|
||||
if err := mergo.MergeWithOverwrite(&dst, src); err != nil {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
```go
|
||||
if err := mergo.Map(&dst, srcMap); err != nil {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
More information and examples in [godoc documentation](http://godoc.org/github.com/imdario/mergo).
|
||||
|
||||
### Nice example
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/imdario/mergo"
|
||||
)
|
||||
|
||||
type Foo struct {
|
||||
A string
|
||||
B int64
|
||||
}
|
||||
|
||||
func main() {
|
||||
src := Foo{
|
||||
A: "one",
|
||||
B: 2,
|
||||
}
|
||||
|
||||
dest := Foo{
|
||||
A: "two",
|
||||
}
|
||||
|
||||
mergo.Merge(&dest, src)
|
||||
|
||||
fmt.Println(dest)
|
||||
// Will print
|
||||
// {two 2}
|
||||
}
|
||||
```
|
||||
|
||||
Note: if test are failing due missing package, please execute:
|
||||
|
||||
go get gopkg.in/yaml.v1
|
||||
|
||||
## Contact me
|
||||
|
||||
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): [@im_dario](https://twitter.com/im_dario)
|
||||
|
||||
## About
|
||||
|
||||
Written by [Dario Castañé](http://dario.im).
|
||||
|
||||
## License
|
||||
|
||||
[BSD 3-Clause](http://opensource.org/licenses/BSD-3-Clause) license, as [Go language](http://golang.org/LICENSE).
|
||||
25
vendor/github.com/imdario/mergo/issue17_test.go
generated
vendored
25
vendor/github.com/imdario/mergo/issue17_test.go
generated
vendored
@@ -1,25 +0,0 @@
|
||||
package mergo
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var (
|
||||
request = `{"timestamp":null, "name": "foo"}`
|
||||
maprequest = map[string]interface{}{
|
||||
"timestamp": nil,
|
||||
"name": "foo",
|
||||
"newStuff": "foo",
|
||||
}
|
||||
)
|
||||
|
||||
func TestIssue17MergeWithOverwrite(t *testing.T) {
|
||||
var something map[string]interface{}
|
||||
if err := json.Unmarshal([]byte(request), &something); err != nil {
|
||||
t.Errorf("Error while Unmarshalling maprequest %s", err)
|
||||
}
|
||||
if err := MergeWithOverwrite(&something, maprequest); err != nil {
|
||||
t.Errorf("Error while merging %s", err)
|
||||
}
|
||||
}
|
||||
27
vendor/github.com/imdario/mergo/issue23_test.go
generated
vendored
27
vendor/github.com/imdario/mergo/issue23_test.go
generated
vendored
@@ -1,27 +0,0 @@
|
||||
package mergo
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
type document struct {
|
||||
Created *time.Time
|
||||
}
|
||||
|
||||
func TestIssue23MergeWithOverwrite(t *testing.T) {
|
||||
now := time.Now()
|
||||
dst := document{
|
||||
&now,
|
||||
}
|
||||
expected := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)
|
||||
src := document{
|
||||
&expected,
|
||||
}
|
||||
if err := MergeWithOverwrite(&dst, src); err != nil {
|
||||
t.Errorf("Error while merging %s", err)
|
||||
}
|
||||
if dst.Created != src.Created {
|
||||
t.Fatalf("Created not merged in properly: dst.Created(%v) != src.Created(%v)", dst.Created, src.Created)
|
||||
}
|
||||
}
|
||||
59
vendor/github.com/imdario/mergo/issue38_test.go
generated
vendored
59
vendor/github.com/imdario/mergo/issue38_test.go
generated
vendored
@@ -1,59 +0,0 @@
|
||||
package mergo
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
type structWithoutTimePointer struct {
|
||||
Created time.Time
|
||||
}
|
||||
|
||||
func TestIssue38Merge(t *testing.T) {
|
||||
dst := structWithoutTimePointer{
|
||||
time.Now(),
|
||||
}
|
||||
|
||||
expected := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)
|
||||
src := structWithoutTimePointer{
|
||||
expected,
|
||||
}
|
||||
if err := Merge(&dst, src); err != nil {
|
||||
t.Errorf("Error while merging %s", err)
|
||||
}
|
||||
if dst.Created == src.Created {
|
||||
t.Fatalf("Created merged unexpectedly: dst.Created(%v) == src.Created(%v)", dst.Created, src.Created)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIssue38MergeEmptyStruct(t *testing.T) {
|
||||
dst := structWithoutTimePointer{}
|
||||
|
||||
expected := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)
|
||||
src := structWithoutTimePointer{
|
||||
expected,
|
||||
}
|
||||
if err := Merge(&dst, src); err != nil {
|
||||
t.Errorf("Error while merging %s", err)
|
||||
}
|
||||
if dst.Created == src.Created {
|
||||
t.Fatalf("Created merged unexpectedly: dst.Created(%v) == src.Created(%v)", dst.Created, src.Created)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIssue38MergeWithOverwrite(t *testing.T) {
|
||||
dst := structWithoutTimePointer{
|
||||
time.Now(),
|
||||
}
|
||||
|
||||
expected := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)
|
||||
src := structWithoutTimePointer{
|
||||
expected,
|
||||
}
|
||||
if err := MergeWithOverwrite(&dst, src); err != nil {
|
||||
t.Errorf("Error while merging %s", err)
|
||||
}
|
||||
if dst.Created != src.Created {
|
||||
t.Fatalf("Created not merged in properly: dst.Created(%v) != src.Created(%v)", dst.Created, src.Created)
|
||||
}
|
||||
}
|
||||
32
vendor/github.com/imdario/mergo/map.go
generated
vendored
32
vendor/github.com/imdario/mergo/map.go
generated
vendored
@@ -31,7 +31,8 @@ func isExported(field reflect.StructField) bool {
|
||||
// Traverses recursively both values, assigning src's fields values to dst.
|
||||
// The map argument tracks comparisons that have already been seen, which allows
|
||||
// short circuiting on recursive types.
|
||||
func deepMap(dst, src reflect.Value, visited map[uintptr]*visit, depth int, overwrite bool) (err error) {
|
||||
func deepMap(dst, src reflect.Value, visited map[uintptr]*visit, depth int, config *Config) (err error) {
|
||||
overwrite := config.Overwrite
|
||||
if dst.CanAddr() {
|
||||
addr := dst.UnsafeAddr()
|
||||
h := 17 * addr
|
||||
@@ -97,15 +98,15 @@ func deepMap(dst, src reflect.Value, visited map[uintptr]*visit, depth int, over
|
||||
continue
|
||||
}
|
||||
if srcKind == dstKind {
|
||||
if err = deepMerge(dstElement, srcElement, visited, depth+1, overwrite); err != nil {
|
||||
if err = deepMerge(dstElement, srcElement, visited, depth+1, config); err != nil {
|
||||
return
|
||||
}
|
||||
} else if dstKind == reflect.Interface && dstElement.Kind() == reflect.Interface {
|
||||
if err = deepMerge(dstElement, srcElement, visited, depth+1, overwrite); err != nil {
|
||||
if err = deepMerge(dstElement, srcElement, visited, depth+1, config); err != nil {
|
||||
return
|
||||
}
|
||||
} else if srcKind == reflect.Map {
|
||||
if err = deepMap(dstElement, srcElement, visited, depth+1, overwrite); err != nil {
|
||||
if err = deepMap(dstElement, srcElement, visited, depth+1, config); err != nil {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
@@ -127,28 +128,35 @@ func deepMap(dst, src reflect.Value, visited map[uintptr]*visit, depth int, over
|
||||
// doesn't apply if dst is a map.
|
||||
// This is separated method from Merge because it is cleaner and it keeps sane
|
||||
// semantics: merging equal types, mapping different (restricted) types.
|
||||
func Map(dst, src interface{}) error {
|
||||
return _map(dst, src, false)
|
||||
func Map(dst, src interface{}, opts ...func(*Config)) error {
|
||||
return _map(dst, src, opts...)
|
||||
}
|
||||
|
||||
// MapWithOverwrite will do the same as Map except that non-empty dst attributes will be overriden by
|
||||
// MapWithOverwrite will do the same as Map except that non-empty dst attributes will be overridden by
|
||||
// non-empty src attribute values.
|
||||
func MapWithOverwrite(dst, src interface{}) error {
|
||||
return _map(dst, src, true)
|
||||
// Deprecated: Use Map(…) with WithOverride
|
||||
func MapWithOverwrite(dst, src interface{}, opts ...func(*Config)) error {
|
||||
return _map(dst, src, append(opts, WithOverride)...)
|
||||
}
|
||||
|
||||
func _map(dst, src interface{}, overwrite bool) error {
|
||||
func _map(dst, src interface{}, opts ...func(*Config)) error {
|
||||
var (
|
||||
vDst, vSrc reflect.Value
|
||||
err error
|
||||
)
|
||||
config := &Config{}
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(config)
|
||||
}
|
||||
|
||||
if vDst, vSrc, err = resolveValues(dst, src); err != nil {
|
||||
return err
|
||||
}
|
||||
// To be friction-less, we redirect equal-type arguments
|
||||
// to deepMerge. Only because arguments can be anything.
|
||||
if vSrc.Kind() == vDst.Kind() {
|
||||
return deepMerge(vDst, vSrc, make(map[uintptr]*visit), 0, overwrite)
|
||||
return deepMerge(vDst, vSrc, make(map[uintptr]*visit), 0, config)
|
||||
}
|
||||
switch vSrc.Kind() {
|
||||
case reflect.Struct:
|
||||
@@ -162,5 +170,5 @@ func _map(dst, src interface{}, overwrite bool) error {
|
||||
default:
|
||||
return ErrNotSupported
|
||||
}
|
||||
return deepMap(vDst, vSrc, make(map[uintptr]*visit), 0, overwrite)
|
||||
return deepMap(vDst, vSrc, make(map[uintptr]*visit), 0, config)
|
||||
}
|
||||
|
||||
106
vendor/github.com/imdario/mergo/merge.go
generated
vendored
106
vendor/github.com/imdario/mergo/merge.go
generated
vendored
@@ -15,7 +15,7 @@ import (
|
||||
func hasExportedField(dst reflect.Value) (exported bool) {
|
||||
for i, n := 0, dst.NumField(); i < n; i++ {
|
||||
field := dst.Type().Field(i)
|
||||
if field.Anonymous {
|
||||
if field.Anonymous && dst.Field(i).Kind() == reflect.Struct {
|
||||
exported = exported || hasExportedField(dst.Field(i))
|
||||
} else {
|
||||
exported = exported || len(field.PkgPath) == 0
|
||||
@@ -24,10 +24,22 @@ func hasExportedField(dst reflect.Value) (exported bool) {
|
||||
return
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
Overwrite bool
|
||||
AppendSlice bool
|
||||
Transformers Transformers
|
||||
}
|
||||
|
||||
type Transformers interface {
|
||||
Transformer(reflect.Type) func(dst, src reflect.Value) error
|
||||
}
|
||||
|
||||
// Traverses recursively both values, assigning src's fields values to dst.
|
||||
// The map argument tracks comparisons that have already been seen, which allows
|
||||
// short circuiting on recursive types.
|
||||
func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, overwrite bool) (err error) {
|
||||
func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, config *Config) (err error) {
|
||||
overwrite := config.Overwrite
|
||||
|
||||
if !src.IsValid() {
|
||||
return
|
||||
}
|
||||
@@ -44,11 +56,19 @@ func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, ov
|
||||
// Remember, remember...
|
||||
visited[h] = &visit{addr, typ, seen}
|
||||
}
|
||||
|
||||
if config.Transformers != nil && !isEmptyValue(dst) {
|
||||
if fn := config.Transformers.Transformer(dst.Type()); fn != nil {
|
||||
err = fn(dst, src)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
switch dst.Kind() {
|
||||
case reflect.Struct:
|
||||
if hasExportedField(dst) {
|
||||
for i, n := 0, dst.NumField(); i < n; i++ {
|
||||
if err = deepMerge(dst.Field(i), src.Field(i), visited, depth+1, overwrite); err != nil {
|
||||
if err = deepMerge(dst.Field(i), src.Field(i), visited, depth+1, config); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -58,9 +78,8 @@ func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, ov
|
||||
}
|
||||
}
|
||||
case reflect.Map:
|
||||
if len(src.MapKeys()) == 0 && !src.IsNil() && len(dst.MapKeys()) == 0 {
|
||||
if dst.IsNil() && !src.IsNil() {
|
||||
dst.Set(reflect.MakeMap(dst.Type()))
|
||||
return
|
||||
}
|
||||
for _, key := range src.MapKeys() {
|
||||
srcElement := src.MapIndex(key)
|
||||
@@ -69,7 +88,7 @@ func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, ov
|
||||
}
|
||||
dstElement := dst.MapIndex(key)
|
||||
switch srcElement.Kind() {
|
||||
case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.Interface, reflect.Slice:
|
||||
case reflect.Chan, reflect.Func, reflect.Map, reflect.Interface, reflect.Slice:
|
||||
if srcElement.IsNil() {
|
||||
continue
|
||||
}
|
||||
@@ -84,36 +103,60 @@ func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, ov
|
||||
case reflect.Ptr:
|
||||
fallthrough
|
||||
case reflect.Map:
|
||||
if err = deepMerge(dstElement, srcElement, visited, depth+1, overwrite); err != nil {
|
||||
if err = deepMerge(dstElement, srcElement, visited, depth+1, config); err != nil {
|
||||
return
|
||||
}
|
||||
case reflect.Slice:
|
||||
srcSlice := reflect.ValueOf(srcElement.Interface())
|
||||
|
||||
var dstSlice reflect.Value
|
||||
if !dstElement.IsValid() || dstElement.IsNil() {
|
||||
dstSlice = reflect.MakeSlice(srcSlice.Type(), 0, srcSlice.Len())
|
||||
} else {
|
||||
dstSlice = reflect.ValueOf(dstElement.Interface())
|
||||
}
|
||||
|
||||
dstSlice = reflect.AppendSlice(dstSlice, srcSlice)
|
||||
dst.SetMapIndex(key, dstSlice)
|
||||
}
|
||||
}
|
||||
if dstElement.IsValid() && reflect.TypeOf(srcElement.Interface()).Kind() == reflect.Map {
|
||||
continue
|
||||
}
|
||||
|
||||
if !isEmptyValue(srcElement) && (overwrite || (!dstElement.IsValid() || isEmptyValue(dst))) {
|
||||
if srcElement.IsValid() && (overwrite || (!dstElement.IsValid() || isEmptyValue(dst))) {
|
||||
if dst.IsNil() {
|
||||
dst.Set(reflect.MakeMap(dst.Type()))
|
||||
}
|
||||
dst.SetMapIndex(key, srcElement)
|
||||
}
|
||||
}
|
||||
case reflect.Slice:
|
||||
if !dst.CanSet() {
|
||||
break
|
||||
}
|
||||
if !isEmptyValue(src) && (overwrite || isEmptyValue(dst)) && !config.AppendSlice {
|
||||
dst.Set(src)
|
||||
} else {
|
||||
dst.Set(reflect.AppendSlice(dst, src))
|
||||
}
|
||||
case reflect.Ptr:
|
||||
fallthrough
|
||||
case reflect.Interface:
|
||||
if src.IsNil() {
|
||||
break
|
||||
}
|
||||
if src.Kind() != reflect.Interface {
|
||||
if dst.IsNil() || overwrite {
|
||||
if dst.CanSet() && (overwrite || isEmptyValue(dst)) {
|
||||
dst.Set(src)
|
||||
}
|
||||
} else if src.Kind() == reflect.Ptr {
|
||||
if err = deepMerge(dst.Elem(), src.Elem(), visited, depth+1, overwrite); err != nil {
|
||||
if err = deepMerge(dst.Elem(), src.Elem(), visited, depth+1, config); err != nil {
|
||||
return
|
||||
}
|
||||
} else if dst.Elem().Type() == src.Type() {
|
||||
if err = deepMerge(dst.Elem(), src, visited, depth+1, overwrite); err != nil {
|
||||
if err = deepMerge(dst.Elem(), src, visited, depth+1, config); err != nil {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
@@ -121,13 +164,11 @@ func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, ov
|
||||
}
|
||||
break
|
||||
}
|
||||
if src.IsNil() {
|
||||
break
|
||||
} else if dst.IsNil() || overwrite {
|
||||
if dst.IsNil() || overwrite {
|
||||
if dst.CanSet() && (overwrite || isEmptyValue(dst)) {
|
||||
dst.Set(src)
|
||||
}
|
||||
} else if err = deepMerge(dst.Elem(), src.Elem(), visited, depth+1, overwrite); err != nil {
|
||||
} else if err = deepMerge(dst.Elem(), src.Elem(), visited, depth+1, config); err != nil {
|
||||
return
|
||||
}
|
||||
default:
|
||||
@@ -142,26 +183,51 @@ func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, ov
|
||||
// src attributes if they themselves are not empty. dst and src must be valid same-type structs
|
||||
// and dst must be a pointer to struct.
|
||||
// It won't merge unexported (private) fields and will do recursively any exported field.
|
||||
func Merge(dst, src interface{}) error {
|
||||
return merge(dst, src, false)
|
||||
func Merge(dst, src interface{}, opts ...func(*Config)) error {
|
||||
return merge(dst, src, opts...)
|
||||
}
|
||||
|
||||
// MergeWithOverwrite will do the same as Merge except that non-empty dst attributes will be overriden by
|
||||
// non-empty src attribute values.
|
||||
func MergeWithOverwrite(dst, src interface{}) error {
|
||||
return merge(dst, src, true)
|
||||
// Deprecated: use Merge(…) with WithOverride
|
||||
func MergeWithOverwrite(dst, src interface{}, opts ...func(*Config)) error {
|
||||
return merge(dst, src, append(opts, WithOverride)...)
|
||||
}
|
||||
|
||||
func merge(dst, src interface{}, overwrite bool) error {
|
||||
// WithTransformers adds transformers to merge, allowing to customize the merging of some types.
|
||||
func WithTransformers(transformers Transformers) func(*Config) {
|
||||
return func(config *Config) {
|
||||
config.Transformers = transformers
|
||||
}
|
||||
}
|
||||
|
||||
// WithOverride will make merge override non-empty dst attributes with non-empty src attributes values.
|
||||
func WithOverride(config *Config) {
|
||||
config.Overwrite = true
|
||||
}
|
||||
|
||||
// WithAppendSlice will make merge append slices instead of overwriting it
|
||||
func WithAppendSlice(config *Config) {
|
||||
config.AppendSlice = true
|
||||
}
|
||||
|
||||
func merge(dst, src interface{}, opts ...func(*Config)) error {
|
||||
var (
|
||||
vDst, vSrc reflect.Value
|
||||
err error
|
||||
)
|
||||
|
||||
config := &Config{}
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(config)
|
||||
}
|
||||
|
||||
if vDst, vSrc, err = resolveValues(dst, src); err != nil {
|
||||
return err
|
||||
}
|
||||
if vDst.Type() != vSrc.Type() {
|
||||
return ErrDifferentArgumentsTypes
|
||||
}
|
||||
return deepMerge(vDst, vSrc, make(map[uintptr]*visit), 0, overwrite)
|
||||
return deepMerge(vDst, vSrc, make(map[uintptr]*visit), 0, config)
|
||||
}
|
||||
|
||||
4
vendor/github.com/imdario/mergo/mergo.go
generated
vendored
4
vendor/github.com/imdario/mergo/mergo.go
generated
vendored
@@ -32,7 +32,7 @@ type visit struct {
|
||||
next *visit
|
||||
}
|
||||
|
||||
// From src/pkg/encoding/json.
|
||||
// From src/pkg/encoding/json/encode.go.
|
||||
func isEmptyValue(v reflect.Value) bool {
|
||||
switch v.Kind() {
|
||||
case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
|
||||
@@ -47,6 +47,8 @@ func isEmptyValue(v reflect.Value) bool {
|
||||
return v.Float() == 0
|
||||
case reflect.Interface, reflect.Ptr, reflect.Func:
|
||||
return v.IsNil()
|
||||
case reflect.Invalid:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
662
vendor/github.com/imdario/mergo/mergo_test.go
generated
vendored
662
vendor/github.com/imdario/mergo/mergo_test.go
generated
vendored
@@ -1,662 +0,0 @@
|
||||
// Copyright 2013 Dario Castañé. All rights reserved.
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package mergo
|
||||
|
||||
import (
|
||||
"gopkg.in/yaml.v2"
|
||||
"io/ioutil"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
type simpleTest struct {
|
||||
Value int
|
||||
}
|
||||
|
||||
type complexTest struct {
|
||||
St simpleTest
|
||||
sz int
|
||||
ID string
|
||||
}
|
||||
|
||||
type mapTest struct {
|
||||
M map[int]int
|
||||
}
|
||||
|
||||
type ifcTest struct {
|
||||
I interface{}
|
||||
}
|
||||
|
||||
type moreComplextText struct {
|
||||
Ct complexTest
|
||||
St simpleTest
|
||||
Nt simpleTest
|
||||
}
|
||||
|
||||
type pointerTest struct {
|
||||
C *simpleTest
|
||||
}
|
||||
|
||||
type sliceTest struct {
|
||||
S []int
|
||||
}
|
||||
|
||||
func TestKb(t *testing.T) {
|
||||
type testStruct struct {
|
||||
Name string
|
||||
KeyValue map[string]interface{}
|
||||
}
|
||||
|
||||
akv := make(map[string]interface{})
|
||||
akv["Key1"] = "not value 1"
|
||||
akv["Key2"] = "value2"
|
||||
a := testStruct{}
|
||||
a.Name = "A"
|
||||
a.KeyValue = akv
|
||||
|
||||
bkv := make(map[string]interface{})
|
||||
bkv["Key1"] = "value1"
|
||||
bkv["Key3"] = "value3"
|
||||
b := testStruct{}
|
||||
b.Name = "B"
|
||||
b.KeyValue = bkv
|
||||
|
||||
ekv := make(map[string]interface{})
|
||||
ekv["Key1"] = "value1"
|
||||
ekv["Key2"] = "value2"
|
||||
ekv["Key3"] = "value3"
|
||||
expected := testStruct{}
|
||||
expected.Name = "B"
|
||||
expected.KeyValue = ekv
|
||||
|
||||
Merge(&b, a)
|
||||
|
||||
if !reflect.DeepEqual(b, expected) {
|
||||
t.Errorf("Actual: %#v did not match \nExpected: %#v", b, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNil(t *testing.T) {
|
||||
if err := Merge(nil, nil); err != ErrNilArguments {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestDifferentTypes(t *testing.T) {
|
||||
a := simpleTest{42}
|
||||
b := 42
|
||||
if err := Merge(&a, b); err != ErrDifferentArgumentsTypes {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestSimpleStruct(t *testing.T) {
|
||||
a := simpleTest{}
|
||||
b := simpleTest{42}
|
||||
if err := Merge(&a, b); err != nil {
|
||||
t.FailNow()
|
||||
}
|
||||
if a.Value != 42 {
|
||||
t.Fatalf("b not merged in properly: a.Value(%d) != b.Value(%d)", a.Value, b.Value)
|
||||
}
|
||||
if !reflect.DeepEqual(a, b) {
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
func TestComplexStruct(t *testing.T) {
|
||||
a := complexTest{}
|
||||
a.ID = "athing"
|
||||
b := complexTest{simpleTest{42}, 1, "bthing"}
|
||||
if err := Merge(&a, b); err != nil {
|
||||
t.FailNow()
|
||||
}
|
||||
if a.St.Value != 42 {
|
||||
t.Fatalf("b not merged in properly: a.St.Value(%d) != b.St.Value(%d)", a.St.Value, b.St.Value)
|
||||
}
|
||||
if a.sz == 1 {
|
||||
t.Fatalf("a's private field sz not preserved from merge: a.sz(%d) == b.sz(%d)", a.sz, b.sz)
|
||||
}
|
||||
if a.ID == b.ID {
|
||||
t.Fatalf("a's field ID merged unexpectedly: a.ID(%s) == b.ID(%s)", a.ID, b.ID)
|
||||
}
|
||||
}
|
||||
|
||||
func TestComplexStructWithOverwrite(t *testing.T) {
|
||||
a := complexTest{simpleTest{1}, 1, "do-not-overwrite-with-empty-value"}
|
||||
b := complexTest{simpleTest{42}, 2, ""}
|
||||
|
||||
expect := complexTest{simpleTest{42}, 1, "do-not-overwrite-with-empty-value"}
|
||||
if err := MergeWithOverwrite(&a, b); err != nil {
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(a, expect) {
|
||||
t.Fatalf("Test failed:\ngot :\n%#v\n\nwant :\n%#v\n\n", a, expect)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPointerStruct(t *testing.T) {
|
||||
s1 := simpleTest{}
|
||||
s2 := simpleTest{19}
|
||||
a := pointerTest{&s1}
|
||||
b := pointerTest{&s2}
|
||||
if err := Merge(&a, b); err != nil {
|
||||
t.FailNow()
|
||||
}
|
||||
if a.C.Value != b.C.Value {
|
||||
t.Fatalf("b not merged in properly: a.C.Value(%d) != b.C.Value(%d)", a.C.Value, b.C.Value)
|
||||
}
|
||||
}
|
||||
|
||||
type embeddingStruct struct {
|
||||
embeddedStruct
|
||||
}
|
||||
|
||||
type embeddedStruct struct {
|
||||
A string
|
||||
}
|
||||
|
||||
func TestEmbeddedStruct(t *testing.T) {
|
||||
tests := []struct {
|
||||
src embeddingStruct
|
||||
dst embeddingStruct
|
||||
expected embeddingStruct
|
||||
}{
|
||||
{
|
||||
src: embeddingStruct{
|
||||
embeddedStruct{"foo"},
|
||||
},
|
||||
dst: embeddingStruct{
|
||||
embeddedStruct{""},
|
||||
},
|
||||
expected: embeddingStruct{
|
||||
embeddedStruct{"foo"},
|
||||
},
|
||||
},
|
||||
{
|
||||
src: embeddingStruct{
|
||||
embeddedStruct{""},
|
||||
},
|
||||
dst: embeddingStruct{
|
||||
embeddedStruct{"bar"},
|
||||
},
|
||||
expected: embeddingStruct{
|
||||
embeddedStruct{"bar"},
|
||||
},
|
||||
},
|
||||
{
|
||||
src: embeddingStruct{
|
||||
embeddedStruct{"foo"},
|
||||
},
|
||||
dst: embeddingStruct{
|
||||
embeddedStruct{"bar"},
|
||||
},
|
||||
expected: embeddingStruct{
|
||||
embeddedStruct{"bar"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
err := Merge(&test.dst, test.src)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
continue
|
||||
}
|
||||
if !reflect.DeepEqual(test.dst, test.expected) {
|
||||
t.Errorf("unexpected output\nexpected:\n%+v\nsaw:\n%+v\n", test.expected, test.dst)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPointerStructNil(t *testing.T) {
|
||||
a := pointerTest{nil}
|
||||
b := pointerTest{&simpleTest{19}}
|
||||
if err := Merge(&a, b); err != nil {
|
||||
t.FailNow()
|
||||
}
|
||||
if a.C.Value != b.C.Value {
|
||||
t.Fatalf("b not merged in a properly: a.C.Value(%d) != b.C.Value(%d)", a.C.Value, b.C.Value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSliceStruct(t *testing.T) {
|
||||
a := sliceTest{}
|
||||
b := sliceTest{[]int{1, 2, 3}}
|
||||
if err := Merge(&a, b); err != nil {
|
||||
t.FailNow()
|
||||
}
|
||||
if len(b.S) != 3 {
|
||||
t.FailNow()
|
||||
}
|
||||
if len(a.S) != len(b.S) {
|
||||
t.Fatalf("b not merged in a proper way %d != %d", len(a.S), len(b.S))
|
||||
}
|
||||
|
||||
a = sliceTest{[]int{1}}
|
||||
b = sliceTest{[]int{1, 2, 3}}
|
||||
if err := Merge(&a, b); err != nil {
|
||||
t.FailNow()
|
||||
}
|
||||
if len(a.S) != 1 {
|
||||
t.FailNow()
|
||||
}
|
||||
if len(a.S) == len(b.S) {
|
||||
t.Fatalf("b merged unexpectedly %d != %d", len(a.S), len(b.S))
|
||||
}
|
||||
}
|
||||
|
||||
func TestEmptyMaps(t *testing.T) {
|
||||
a := mapTest{}
|
||||
b := mapTest{
|
||||
map[int]int{},
|
||||
}
|
||||
if err := Merge(&a, b); err != nil {
|
||||
t.Fail()
|
||||
}
|
||||
if !reflect.DeepEqual(a, b) {
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
func TestEmptyToEmptyMaps(t *testing.T) {
|
||||
a := mapTest{}
|
||||
b := mapTest{}
|
||||
if err := Merge(&a, b); err != nil {
|
||||
t.Fail()
|
||||
}
|
||||
if !reflect.DeepEqual(a, b) {
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
func TestEmptyToNotEmptyMaps(t *testing.T) {
|
||||
a := mapTest{map[int]int{
|
||||
1: 2,
|
||||
3: 4,
|
||||
}}
|
||||
aa := mapTest{map[int]int{
|
||||
1: 2,
|
||||
3: 4,
|
||||
}}
|
||||
b := mapTest{
|
||||
map[int]int{},
|
||||
}
|
||||
if err := Merge(&a, b); err != nil {
|
||||
t.Fail()
|
||||
}
|
||||
if !reflect.DeepEqual(a, aa) {
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
func TestMapsWithOverwrite(t *testing.T) {
|
||||
m := map[string]simpleTest{
|
||||
"a": {}, // overwritten by 16
|
||||
"b": {42}, // not overwritten by empty value
|
||||
"c": {13}, // overwritten by 12
|
||||
"d": {61},
|
||||
}
|
||||
n := map[string]simpleTest{
|
||||
"a": {16},
|
||||
"b": {},
|
||||
"c": {12},
|
||||
"e": {14},
|
||||
}
|
||||
expect := map[string]simpleTest{
|
||||
"a": {16},
|
||||
"b": {},
|
||||
"c": {12},
|
||||
"d": {61},
|
||||
"e": {14},
|
||||
}
|
||||
|
||||
if err := MergeWithOverwrite(&m, n); err != nil {
|
||||
t.Fatalf(err.Error())
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(m, expect) {
|
||||
t.Fatalf("Test failed:\ngot :\n%#v\n\nwant :\n%#v\n\n", m, expect)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMaps(t *testing.T) {
|
||||
m := map[string]simpleTest{
|
||||
"a": {},
|
||||
"b": {42},
|
||||
"c": {13},
|
||||
"d": {61},
|
||||
}
|
||||
n := map[string]simpleTest{
|
||||
"a": {16},
|
||||
"b": {},
|
||||
"c": {12},
|
||||
"e": {14},
|
||||
}
|
||||
expect := map[string]simpleTest{
|
||||
"a": {0},
|
||||
"b": {42},
|
||||
"c": {13},
|
||||
"d": {61},
|
||||
"e": {14},
|
||||
}
|
||||
|
||||
if err := Merge(&m, n); err != nil {
|
||||
t.Fatalf(err.Error())
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(m, expect) {
|
||||
t.Fatalf("Test failed:\ngot :\n%#v\n\nwant :\n%#v\n\n", m, expect)
|
||||
}
|
||||
if m["a"].Value != 0 {
|
||||
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)
|
||||
}
|
||||
if m["b"].Value != 42 {
|
||||
t.Fatalf(`n wrongly merged in m: m["b"].Value(%d) != n["b"].Value(%d)`, m["b"].Value, n["b"].Value)
|
||||
}
|
||||
if m["c"].Value != 13 {
|
||||
t.Fatalf(`n overwritten in m: m["c"].Value(%d) != n["c"].Value(%d)`, m["c"].Value, n["c"].Value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestYAMLMaps(t *testing.T) {
|
||||
thing := loadYAML("testdata/thing.yml")
|
||||
license := loadYAML("testdata/license.yml")
|
||||
ft := thing["fields"].(map[interface{}]interface{})
|
||||
fl := license["fields"].(map[interface{}]interface{})
|
||||
// license has one extra field (site) and another already existing in thing (author) that Mergo won't override.
|
||||
expectedLength := len(ft) + len(fl) - 1
|
||||
if err := Merge(&license, thing); err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
currentLength := len(license["fields"].(map[interface{}]interface{}))
|
||||
if currentLength != expectedLength {
|
||||
t.Fatalf(`thing not merged in license properly, license must have %d elements instead of %d`, expectedLength, currentLength)
|
||||
}
|
||||
fields := license["fields"].(map[interface{}]interface{})
|
||||
if _, ok := fields["id"]; !ok {
|
||||
t.Fatalf(`thing not merged in license properly, license must have a new id field from thing`)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTwoPointerValues(t *testing.T) {
|
||||
a := &simpleTest{}
|
||||
b := &simpleTest{42}
|
||||
if err := Merge(a, b); err != nil {
|
||||
t.Fatalf(`Boom. You crossed the streams: %s`, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMap(t *testing.T) {
|
||||
a := complexTest{}
|
||||
a.ID = "athing"
|
||||
c := moreComplextText{a, simpleTest{}, simpleTest{}}
|
||||
b := map[string]interface{}{
|
||||
"ct": map[string]interface{}{
|
||||
"st": map[string]interface{}{
|
||||
"value": 42,
|
||||
},
|
||||
"sz": 1,
|
||||
"id": "bthing",
|
||||
},
|
||||
"st": &simpleTest{144}, // Mapping a reference
|
||||
"zt": simpleTest{299}, // Mapping a missing field (zt doesn't exist)
|
||||
"nt": simpleTest{3},
|
||||
}
|
||||
if err := Map(&c, b); err != nil {
|
||||
t.FailNow()
|
||||
}
|
||||
m := b["ct"].(map[string]interface{})
|
||||
n := m["st"].(map[string]interface{})
|
||||
o := b["st"].(*simpleTest)
|
||||
p := b["nt"].(simpleTest)
|
||||
if c.Ct.St.Value != 42 {
|
||||
t.Fatalf("b not merged in properly: c.Ct.St.Value(%d) != b.Ct.St.Value(%d)", c.Ct.St.Value, n["value"])
|
||||
}
|
||||
if c.St.Value != 144 {
|
||||
t.Fatalf("b not merged in properly: c.St.Value(%d) != b.St.Value(%d)", c.St.Value, o.Value)
|
||||
}
|
||||
if c.Nt.Value != 3 {
|
||||
t.Fatalf("b not merged in properly: c.Nt.Value(%d) != b.Nt.Value(%d)", c.St.Value, p.Value)
|
||||
}
|
||||
if c.Ct.sz == 1 {
|
||||
t.Fatalf("a's private field sz not preserved from merge: c.Ct.sz(%d) == b.Ct.sz(%d)", c.Ct.sz, m["sz"])
|
||||
}
|
||||
if c.Ct.ID == m["id"] {
|
||||
t.Fatalf("a's field ID merged unexpectedly: c.Ct.ID(%s) == b.Ct.ID(%s)", c.Ct.ID, m["id"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestSimpleMap(t *testing.T) {
|
||||
a := simpleTest{}
|
||||
b := map[string]interface{}{
|
||||
"value": 42,
|
||||
}
|
||||
if err := Map(&a, b); err != nil {
|
||||
t.FailNow()
|
||||
}
|
||||
if a.Value != 42 {
|
||||
t.Fatalf("b not merged in properly: a.Value(%d) != b.Value(%v)", a.Value, b["value"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestIfcMap(t *testing.T) {
|
||||
a := ifcTest{}
|
||||
b := ifcTest{42}
|
||||
if err := Map(&a, b); err != nil {
|
||||
t.FailNow()
|
||||
}
|
||||
if a.I != 42 {
|
||||
t.Fatalf("b not merged in properly: a.I(%d) != b.I(%d)", a.I, b.I)
|
||||
}
|
||||
if !reflect.DeepEqual(a, b) {
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
func TestIfcMapNoOverwrite(t *testing.T) {
|
||||
a := ifcTest{13}
|
||||
b := ifcTest{42}
|
||||
if err := Map(&a, b); err != nil {
|
||||
t.FailNow()
|
||||
}
|
||||
if a.I != 13 {
|
||||
t.Fatalf("a not left alone: a.I(%d) == b.I(%d)", a.I, b.I)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIfcMapWithOverwrite(t *testing.T) {
|
||||
a := ifcTest{13}
|
||||
b := ifcTest{42}
|
||||
if err := MapWithOverwrite(&a, b); err != nil {
|
||||
t.FailNow()
|
||||
}
|
||||
if a.I != 42 {
|
||||
t.Fatalf("b not merged in properly: a.I(%d) != b.I(%d)", a.I, b.I)
|
||||
}
|
||||
if !reflect.DeepEqual(a, b) {
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
type pointerMapTest struct {
|
||||
A int
|
||||
hidden int
|
||||
B *simpleTest
|
||||
}
|
||||
|
||||
func TestBackAndForth(t *testing.T) {
|
||||
pt := pointerMapTest{42, 1, &simpleTest{66}}
|
||||
m := make(map[string]interface{})
|
||||
if err := Map(&m, pt); err != nil {
|
||||
t.FailNow()
|
||||
}
|
||||
var (
|
||||
v interface{}
|
||||
ok bool
|
||||
)
|
||||
if v, ok = m["a"]; v.(int) != pt.A || !ok {
|
||||
t.Fatalf("pt not merged in properly: m[`a`](%d) != pt.A(%d)", v, pt.A)
|
||||
}
|
||||
if v, ok = m["b"]; !ok {
|
||||
t.Fatalf("pt not merged in properly: B is missing in m")
|
||||
}
|
||||
var st *simpleTest
|
||||
if st = v.(*simpleTest); st.Value != 66 {
|
||||
t.Fatalf("something went wrong while mapping pt on m, B wasn't copied")
|
||||
}
|
||||
bpt := pointerMapTest{}
|
||||
if err := Map(&bpt, m); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if bpt.A != pt.A {
|
||||
t.Fatalf("pt not merged in properly: bpt.A(%d) != pt.A(%d)", bpt.A, pt.A)
|
||||
}
|
||||
if bpt.hidden == pt.hidden {
|
||||
t.Fatalf("pt unexpectedly merged: bpt.hidden(%d) == pt.hidden(%d)", bpt.hidden, pt.hidden)
|
||||
}
|
||||
if bpt.B.Value != pt.B.Value {
|
||||
t.Fatalf("pt not merged in properly: bpt.B.Value(%d) != pt.B.Value(%d)", bpt.B.Value, pt.B.Value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEmbeddedPointerUnpacking(t *testing.T) {
|
||||
tests := []struct{ input pointerMapTest }{
|
||||
{pointerMapTest{42, 1, nil}},
|
||||
{pointerMapTest{42, 1, &simpleTest{66}}},
|
||||
}
|
||||
newValue := 77
|
||||
m := map[string]interface{}{
|
||||
"b": map[string]interface{}{
|
||||
"value": newValue,
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
pt := test.input
|
||||
if err := MapWithOverwrite(&pt, m); err != nil {
|
||||
t.FailNow()
|
||||
}
|
||||
if pt.B.Value != newValue {
|
||||
t.Fatalf("pt not mapped properly: pt.A.Value(%d) != m[`b`][`value`](%d)", pt.B.Value, newValue)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
type structWithTimePointer struct {
|
||||
Birth *time.Time
|
||||
}
|
||||
|
||||
func TestTime(t *testing.T) {
|
||||
now := time.Now()
|
||||
dataStruct := structWithTimePointer{
|
||||
Birth: &now,
|
||||
}
|
||||
dataMap := map[string]interface{}{
|
||||
"Birth": &now,
|
||||
}
|
||||
b := structWithTimePointer{}
|
||||
if err := Merge(&b, dataStruct); err != nil {
|
||||
t.FailNow()
|
||||
}
|
||||
if b.Birth.IsZero() {
|
||||
t.Fatalf("time.Time not merged in properly: b.Birth(%v) != dataStruct['Birth'](%v)", b.Birth, dataStruct.Birth)
|
||||
}
|
||||
if b.Birth != dataStruct.Birth {
|
||||
t.Fatalf("time.Time not merged in properly: b.Birth(%v) != dataStruct['Birth'](%v)", b.Birth, dataStruct.Birth)
|
||||
}
|
||||
b = structWithTimePointer{}
|
||||
if err := Map(&b, dataMap); err != nil {
|
||||
t.FailNow()
|
||||
}
|
||||
if b.Birth.IsZero() {
|
||||
t.Fatalf("time.Time not merged in properly: b.Birth(%v) != dataMap['Birth'](%v)", b.Birth, dataMap["Birth"])
|
||||
}
|
||||
}
|
||||
|
||||
type simpleNested struct {
|
||||
A int
|
||||
}
|
||||
|
||||
type structWithNestedPtrValueMap struct {
|
||||
NestedPtrValue map[string]*simpleNested
|
||||
}
|
||||
|
||||
func TestNestedPtrValueInMap(t *testing.T) {
|
||||
src := &structWithNestedPtrValueMap{
|
||||
NestedPtrValue: map[string]*simpleNested{
|
||||
"x": {
|
||||
A: 1,
|
||||
},
|
||||
},
|
||||
}
|
||||
dst := &structWithNestedPtrValueMap{
|
||||
NestedPtrValue: map[string]*simpleNested{
|
||||
"x": {},
|
||||
},
|
||||
}
|
||||
if err := Map(dst, src); err != nil {
|
||||
t.FailNow()
|
||||
}
|
||||
if dst.NestedPtrValue["x"].A == 0 {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
func loadYAML(path string) (m map[string]interface{}) {
|
||||
m = make(map[string]interface{})
|
||||
raw, _ := ioutil.ReadFile(path)
|
||||
_ = yaml.Unmarshal(raw, &m)
|
||||
return
|
||||
}
|
||||
|
||||
type structWithMap struct {
|
||||
m map[string]structWithUnexportedProperty
|
||||
}
|
||||
|
||||
type structWithUnexportedProperty struct {
|
||||
s string
|
||||
}
|
||||
|
||||
func TestUnexportedProperty(t *testing.T) {
|
||||
a := structWithMap{map[string]structWithUnexportedProperty{
|
||||
"key": structWithUnexportedProperty{"hello"},
|
||||
}}
|
||||
b := structWithMap{map[string]structWithUnexportedProperty{
|
||||
"key": structWithUnexportedProperty{"hi"},
|
||||
}}
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
t.Errorf("Should not have panicked")
|
||||
}
|
||||
}()
|
||||
Merge(&a, b)
|
||||
}
|
||||
|
||||
type structWithBoolPointer struct {
|
||||
C *bool
|
||||
}
|
||||
|
||||
func TestBooleanPointer(t *testing.T) {
|
||||
bt, bf := true, false
|
||||
src := structWithBoolPointer{
|
||||
&bt,
|
||||
}
|
||||
dst := structWithBoolPointer{
|
||||
&bf,
|
||||
}
|
||||
if err := Merge(&dst, src); err != nil {
|
||||
t.FailNow()
|
||||
}
|
||||
if dst.C == src.C {
|
||||
t.Fatalf("dst.C should be a different pointer than src.C")
|
||||
}
|
||||
if *dst.C != *src.C {
|
||||
t.Fatalf("dst.C should be true")
|
||||
}
|
||||
}
|
||||
6
vendor/github.com/imdario/mergo/testdata/thing.yml
generated
vendored
6
vendor/github.com/imdario/mergo/testdata/thing.yml
generated
vendored
@@ -1,6 +0,0 @@
|
||||
fields:
|
||||
id: int
|
||||
name: string
|
||||
parent: ref "datu:thing"
|
||||
status: enum(draft, public, private)
|
||||
author: updater
|
||||
Reference in New Issue
Block a user