Skip to content

Commit

Permalink
Merge pull request #119 from math-nao/master
Browse files Browse the repository at this point in the history
Add support to copy from a nil slice pointer to a slice field when DeepCopy is enabled
  • Loading branch information
jinzhu committed Dec 13, 2021
2 parents 633a171 + 8af390d commit ab50287
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 4 deletions.
3 changes: 3 additions & 0 deletions copier.go
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,9 @@ func set(to, from reflect.Value, deepCopy bool) bool {
toKind = reflect.TypeOf(to.Interface()).Kind()
}
}
if from.Kind() == reflect.Ptr && from.IsNil() {
return true
}
if toKind == reflect.Struct || toKind == reflect.Map || toKind == reflect.Slice {
return false
}
Expand Down
64 changes: 60 additions & 4 deletions copier_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -334,10 +334,14 @@ func TestStructField(t *testing.T) {
type UserWithDetailsPtr struct {
Details []*Detail
Detail *Detail
Notes *[]string
Notes2 *[]string
}
type UserWithDetails struct {
Details []Detail
Detail Detail
Notes []string
Notes2 []string
}
type UserWithSimilarDetailsPtr struct {
Detail *SimilarDetail
Expand Down Expand Up @@ -389,7 +393,7 @@ func TestStructField(t *testing.T) {
t.Fatalf("DeepCopy not enabled")
}

if len(to.Details) != len(to.Details) {
if len(from.Details) != len(to.Details) {
t.Fatalf("slice should be copied")
}

Expand All @@ -414,7 +418,7 @@ func TestStructField(t *testing.T) {
t.Fatalf("DeepCopy not enabled")
}

if len(to.Details) != len(to.Details) {
if len(from.Details) != len(to.Details) {
t.Fatalf("slice should be copied")
}

Expand Down Expand Up @@ -502,6 +506,27 @@ func TestStructField(t *testing.T) {
t.Errorf("should be different")
}
})

t.Run("Should work with from a nil ptr slice field to a slice field", func(t *testing.T) {
notes := []string{"hello", "world"}
from := UserWithDetailsPtr{Notes: &notes, Notes2: nil}
to := UserWithDetails{}
err := copier.Copy(&to, from)
if err != nil {
t.Errorf("should not return an error")
return
}

if len(to.Notes) != len(*from.Notes) {
t.Errorf("should be the same length")
}
if to.Notes[0] != (*from.Notes)[0] {
t.Errorf("should be the same")
}
if to.Notes[1] != (*from.Notes)[1] {
t.Errorf("should be the same")
}
})
})

t.Run("Should work with deepCopy", func(t *testing.T) {
Expand All @@ -521,7 +546,7 @@ func TestStructField(t *testing.T) {
t.Fatalf("DeepCopy enabled")
}

if len(to.Details) != len(to.Details) {
if len(from.Details) != len(to.Details) {
t.Fatalf("slice should be copied")
}

Expand All @@ -545,7 +570,7 @@ func TestStructField(t *testing.T) {
t.Fatalf("DeepCopy enabled")
}

if len(to.Details) != len(to.Details) {
if len(from.Details) != len(to.Details) {
t.Fatalf("slice should be copied")
}

Expand Down Expand Up @@ -633,6 +658,37 @@ func TestStructField(t *testing.T) {
t.Errorf("should be different")
}
})

t.Run("Should work with from a nil ptr slice field to a slice field", func(t *testing.T) {
notes := []string{"hello", "world"}
from := UserWithDetailsPtr{Notes: &notes, Notes2: nil}
to := UserWithDetails{}
err := copier.CopyWithOption(&to, from, optionsDeepCopy)
if err != nil {
t.Errorf("should not return an error")
return
}

if len(to.Notes) != len(*from.Notes) {
t.Errorf("should be the same length")
}
if to.Notes[0] != (*from.Notes)[0] {
t.Errorf("should be the same")
}
if to.Notes[1] != (*from.Notes)[1] {
t.Errorf("should be the same")
}

newValue := []string{"new", "value"}
to.Notes = newValue

if to.Notes[0] == (*from.Notes)[0] {
t.Errorf("should be different")
}
if to.Notes[1] == (*from.Notes)[1] {
t.Errorf("should be different")
}
})
})
}

Expand Down

0 comments on commit ab50287

Please sign in to comment.