Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MergeWithOverwrite behavior on struct field inside a map #14

Closed
accerqueira opened this issue Apr 16, 2015 · 3 comments
Closed

MergeWithOverwrite behavior on struct field inside a map #14

accerqueira opened this issue Apr 16, 2015 · 3 comments
Labels

Comments

@accerqueira
Copy link

Hi,

I would expect that fields from a struct on a map would only be overwritten by MergeWithOverwrite if the src struct field was not empty valued, but according to the following test, it seems to be overwriting anyway on map to struct and map to struct pointer.

package mergo_test

import "testing"
import "github.com/imdario/mergo"

type Struct struct {
    Value string
}
type StructOfStruct struct {
    Value Struct
}

type MapToStructPtr map[string]*Struct
type MapToStruct map[string]Struct

func TestMapToStructPtr(t *testing.T) {
    var dst = make(MapToStructPtr)
    dst["a"] = &Struct{Value: "1"}
    var src = make(MapToStructPtr)
    src["a"] = &Struct{}
    var expect = make(MapToStructPtr)
    expect["a"] = &Struct{Value: "1"}

    if err := mergo.MergeWithOverwrite(&dst, src); err != nil {
        t.FailNow()
    }

    for k, _ := range expect {
        if ((expect[k] == nil) != (dst[k] == nil)) || (expect[k] != nil && dst[k].Value != expect[k].Value) {
            t.Errorf("Test failed:\ngot  :\n dst[\"%s\"] = %#v\n\nwant :\n dst[\"%s\"] = %#v\n\n", k, dst[k], k, expect[k])
        }
    }
}

func TestMapToStruct(t *testing.T) {
    var dst = make(MapToStruct)
    dst["a"] = Struct{Value: "1"}
    var src = make(MapToStruct)
    src["a"] = Struct{}
    var expect = make(MapToStruct)
    expect["a"] = Struct{Value: "1"}

    if err := mergo.MergeWithOverwrite(&dst, src); err != nil {
        t.FailNow()
    }

    for k, _ := range expect {
        if dst[k].Value != expect[k].Value {
            t.Errorf("Test failed:\ngot  :\n dst[\"%s\"] = %#v\n\nwant :\n dst[\"%s\"] = %#v\n\n", k, dst[k], k, expect[k])
        }
    }
}

func TestStruct(t *testing.T) {
    var dst = Struct{Value: "1"}
    var src = Struct{}
    var expect = Struct{Value: "1"}

    if err := mergo.MergeWithOverwrite(&dst, src); err != nil {
        t.FailNow()
    }

    if dst.Value != expect.Value {
        t.Errorf("Test failed:\ngot  :\n dst = %#v\n\nwant :\n dst = %#v\n\n", dst, expect)
    }
}

func TestStructOfStruct(t *testing.T) {
    var dst = StructOfStruct{Value: Struct{"1"}}
    var src = StructOfStruct{}
    var expect = StructOfStruct{Value: Struct{"1"}}

    if err := mergo.MergeWithOverwrite(&dst, src); err != nil {
        t.FailNow()
    }

    if dst.Value != expect.Value {
        t.Errorf("Test failed:\ngot  :\n dst = %#v\n\nwant :\n dst = %#v\n\n", dst, expect)
    }
}

go test -v mergo_test.go gives me the following output

=== RUN TestMapToStructPtr
--- FAIL: TestMapToStructPtr (0.00s)
        mergo_test.go:31: Test failed:
                got  :
                 dst["a"] = &mergo_test.Struct{Value:""}

                want :
                 dst["a"] = &mergo_test.Struct{Value:"1"}

=== RUN TestMapToStruct
--- FAIL: TestMapToStruct (0.00s)
        mergo_test.go:50: Test failed:
                got  :
                 dst["a"] = mergo_test.Struct{Value:""}

                want :
                 dst["a"] = mergo_test.Struct{Value:"1"}

=== RUN TestStruct
--- PASS: TestStruct (0.00s)
=== RUN TestStructOfStruct
--- PASS: TestStructOfStruct (0.00s)
FAIL
exit status 1
FAIL    command-line-arguments  0.118s

It seems to work the way I expected for struct and struct of struct though.

@svyotov
Copy link
Contributor

svyotov commented Jan 12, 2020

As far as I am aware it is not possible to differentiate between a string value not having been set or being empty "". Both "" and nil will result in the same value. If "" was to be considered unset, then merging with it when the user explicitly set the value to "" we will get wrong results.

Is there any solution? => Kind of, if the value is a pointer to a string, in such cases the code will receive nil.

@darccio
Copy link
Owner

darccio commented Mar 25, 2020

Pleas, check again with the latest version, @accerqueira.

@darccio darccio closed this as completed Jul 17, 2020
@darccio
Copy link
Owner

darccio commented Jul 17, 2020

This will be handled in the new cleanroom implementation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants