New Upstream Release - golang-github-jinzhu-copier
Ready changes
Summary
Merged new upstream version: 0.3.5 (was: 0.3.2).
Resulting package
Built on 2022-09-29T06:40 (took 3m34s)
The resulting binary packages can be installed (if you have the apt repository enabled) by running one of:
apt install -t fresh-releases golang-github-jinzhu-copier-dev
Lintian Result
Diff
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 2aa6f61..774b29c 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -12,7 +12,7 @@ jobs:
ci:
strategy:
matrix:
- go: ['1.15', '1.14', '1.13']
+ go: ['1.16', '1.17']
platform: [ubuntu-latest, macos-latest] # can not run in windows OS
runs-on: ${{ matrix.platform }}
diff --git a/copier.go b/copier.go
index 412ff54..6dc9600 100644
--- a/copier.go
+++ b/copier.go
@@ -24,6 +24,13 @@ const (
// Denotes that the value as been copied
hasCopied
+
+ // Some default converter types for a nicer syntax
+ String string = ""
+ Bool bool = false
+ Int int = 0
+ Float32 float32 = 0
+ Float64 float64 = 0
)
// Option sets copy options
@@ -32,6 +39,18 @@ type Option struct {
// struct having all it's fields set to their zero values respectively (see IsZero() in reflect/value.go)
IgnoreEmpty bool
DeepCopy bool
+ Converters []TypeConverter
+}
+
+type TypeConverter struct {
+ SrcType interface{}
+ DstType interface{}
+ Fn func(src interface{}) (interface{}, error)
+}
+
+type converterPair struct {
+ SrcType reflect.Type
+ DstType reflect.Type
}
// Tag Flags
@@ -59,12 +78,27 @@ func CopyWithOption(toValue interface{}, fromValue interface{}, opt Option) (err
func copier(toValue interface{}, fromValue interface{}, opt Option) (err error) {
var (
- isSlice bool
- amount = 1
- from = indirect(reflect.ValueOf(fromValue))
- to = indirect(reflect.ValueOf(toValue))
+ isSlice bool
+ amount = 1
+ from = indirect(reflect.ValueOf(fromValue))
+ to = indirect(reflect.ValueOf(toValue))
+ converters map[converterPair]TypeConverter
)
+ // save convertes into map for faster lookup
+ for i := range opt.Converters {
+ if converters == nil {
+ converters = make(map[converterPair]TypeConverter)
+ }
+
+ pair := converterPair{
+ SrcType: reflect.TypeOf(opt.Converters[i].SrcType),
+ DstType: reflect.TypeOf(opt.Converters[i].DstType),
+ }
+
+ converters[pair] = opt.Converters[i]
+ }
+
if !to.CanAddr() {
return ErrInvalidCopyDestination
}
@@ -113,13 +147,16 @@ func copier(toValue interface{}, fromValue interface{}, opt Option) (err error)
for _, k := range from.MapKeys() {
toKey := indirect(reflect.New(toType.Key()))
- if !set(toKey, k, opt.DeepCopy) {
+ if !set(toKey, k, opt.DeepCopy, converters) {
return fmt.Errorf("%w map, old key: %v, new key: %v", ErrNotSupported, k.Type(), toType.Key())
}
- elemType, _ := indirectType(toType.Elem())
+ elemType := toType.Elem()
+ if elemType.Kind() != reflect.Slice {
+ elemType, _ = indirectType(elemType)
+ }
toValue := indirect(reflect.New(elemType))
- if !set(toValue, from.MapIndex(k), opt.DeepCopy) {
+ if !set(toValue, from.MapIndex(k), opt.DeepCopy, converters) {
if err = copier(toValue.Addr().Interface(), from.MapIndex(k).Interface(), opt); err != nil {
return err
}
@@ -148,7 +185,7 @@ func copier(toValue interface{}, fromValue interface{}, opt Option) (err error)
to.Set(reflect.Append(to, reflect.New(to.Type().Elem()).Elem()))
}
- if !set(to.Index(i), from.Index(i), opt.DeepCopy) {
+ if !set(to.Index(i), from.Index(i), opt.DeepCopy, converters) {
// ignore error while copy slice element
err = copier(to.Index(i).Addr().Interface(), from.Index(i).Interface(), opt)
if err != nil {
@@ -203,6 +240,8 @@ func copier(toValue interface{}, fromValue interface{}, opt Option) (err error)
// check source
if source.IsValid() {
+ copyUnexportedStructFields(dest, source)
+
// Copy from source field to dest field or method
fromTypeFields := deepFields(fromType)
for _, field := range fromTypeFields {
@@ -249,7 +288,7 @@ func copier(toValue interface{}, fromValue interface{}, opt Option) (err error)
toField := dest.FieldByName(destFieldName)
if toField.IsValid() {
if toField.CanSet() {
- if !set(toField, fromField, opt.DeepCopy) {
+ if !set(toField, fromField, opt.DeepCopy, converters) {
if err := copier(toField.Addr().Interface(), fromField.Interface(), opt); err != nil {
return err
}
@@ -291,7 +330,7 @@ func copier(toValue interface{}, fromValue interface{}, opt Option) (err error)
if toField := dest.FieldByName(destFieldName); toField.IsValid() && toField.CanSet() {
values := fromMethod.Call([]reflect.Value{})
if len(values) >= 1 {
- set(toField, values[0], opt.DeepCopy)
+ set(toField, values[0], opt.DeepCopy, converters)
}
}
}
@@ -303,7 +342,7 @@ func copier(toValue interface{}, fromValue interface{}, opt Option) (err error)
if to.Len() < i+1 {
to.Set(reflect.Append(to, dest.Addr()))
} else {
- if !set(to.Index(i), dest.Addr(), opt.DeepCopy) {
+ if !set(to.Index(i), dest.Addr(), opt.DeepCopy, converters) {
// ignore error while copy slice element
err = copier(to.Index(i).Addr().Interface(), dest.Addr().Interface(), opt)
if err != nil {
@@ -315,7 +354,7 @@ func copier(toValue interface{}, fromValue interface{}, opt Option) (err error)
if to.Len() < i+1 {
to.Set(reflect.Append(to, dest))
} else {
- if !set(to.Index(i), dest, opt.DeepCopy) {
+ if !set(to.Index(i), dest, opt.DeepCopy, converters) {
// ignore error while copy slice element
err = copier(to.Index(i).Addr().Interface(), dest.Interface(), opt)
if err != nil {
@@ -334,6 +373,24 @@ func copier(toValue interface{}, fromValue interface{}, opt Option) (err error)
return
}
+func copyUnexportedStructFields(to, from reflect.Value) {
+ if from.Kind() != reflect.Struct || to.Kind() != reflect.Struct || !from.Type().AssignableTo(to.Type()) {
+ return
+ }
+
+ // create a shallow copy of 'to' to get all fields
+ tmp := indirect(reflect.New(to.Type()))
+ tmp.Set(from)
+
+ // revert exported fields
+ for i := 0; i < to.NumField(); i++ {
+ if tmp.Field(i).CanSet() {
+ tmp.Field(i).Set(to.Field(i))
+ }
+ }
+ to.Set(tmp)
+}
+
func shouldIgnore(v reflect.Value, ignoreEmpty bool) bool {
if !ignoreEmpty {
return false
@@ -348,10 +405,15 @@ func deepFields(reflectType reflect.Type) []reflect.StructField {
for i := 0; i < reflectType.NumField(); i++ {
v := reflectType.Field(i)
- if v.Anonymous {
- fields = append(fields, deepFields(v.Type)...)
- } else {
+ // PkgPath is the package path that qualifies a lower case (unexported)
+ // field name. It is empty for upper case (exported) field names.
+ // See https://golang.org/ref/spec#Uniqueness_of_identifiers
+ if v.PkgPath == "" {
fields = append(fields, v)
+ if v.Anonymous {
+ // also consider fields of anonymous fields as fields of the root
+ fields = append(fields, deepFields(v.Type)...)
+ }
}
}
@@ -376,8 +438,14 @@ func indirectType(reflectType reflect.Type) (_ reflect.Type, isPtr bool) {
return reflectType, isPtr
}
-func set(to, from reflect.Value, deepCopy bool) bool {
+func set(to, from reflect.Value, deepCopy bool, converters map[converterPair]TypeConverter) bool {
if from.IsValid() {
+ if ok, err := lookupAndCopyWithConverter(to, from, converters); err != nil {
+ return false
+ } else if ok {
+ return true
+ }
+
if to.Kind() == reflect.Ptr {
// set `to` to nil if from is nil
if from.Kind() == reflect.Ptr && from.IsNil() {
@@ -411,6 +479,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
}
@@ -452,7 +523,7 @@ func set(to, from reflect.Value, deepCopy bool) bool {
to.Set(rv)
}
} else if from.Kind() == reflect.Ptr {
- return set(to, from.Elem(), deepCopy)
+ return set(to, from.Elem(), deepCopy, converters)
} else {
return false
}
@@ -461,6 +532,33 @@ func set(to, from reflect.Value, deepCopy bool) bool {
return true
}
+// lookupAndCopyWithConverter looks up the type pair, on success the TypeConverter Fn func is called to copy src to dst field.
+func lookupAndCopyWithConverter(to, from reflect.Value, converters map[converterPair]TypeConverter) (copied bool, err error) {
+ pair := converterPair{
+ SrcType: from.Type(),
+ DstType: to.Type(),
+ }
+
+ if cnv, ok := converters[pair]; ok {
+ result, err := cnv.Fn(from.Interface())
+
+ if err != nil {
+ return false, err
+ }
+
+ if result != nil {
+ to.Set(reflect.ValueOf(result))
+ } else {
+ // in case we've got a nil value to copy
+ to.Set(reflect.Zero(to.Type()))
+ }
+
+ return true, nil
+ }
+
+ return false, nil
+}
+
// parseTags Parses struct tags and returns uint8 bit flags.
func parseTags(tag string) (flg uint8, name string, err error) {
for _, t := range strings.Split(tag, ",") {
diff --git a/copier_converter_test.go b/copier_converter_test.go
new file mode 100644
index 0000000..08bd038
--- /dev/null
+++ b/copier_converter_test.go
@@ -0,0 +1,187 @@
+package copier_test
+
+import (
+ "errors"
+ "strconv"
+ "testing"
+ "time"
+
+ "github.com/jinzhu/copier"
+)
+
+func TestCopyWithTypeConverters(t *testing.T) {
+ type SrcStruct struct {
+ Field1 time.Time
+ Field2 *time.Time
+ Field3 *time.Time
+ Field4 string
+ }
+
+ type DestStruct struct {
+ Field1 string
+ Field2 string
+ Field3 string
+ Field4 int
+ }
+
+ testTime := time.Date(2021, 3, 5, 1, 30, 0, 123000000, time.UTC)
+
+ src := SrcStruct{
+ Field1: testTime,
+ Field2: &testTime,
+ Field3: nil,
+ Field4: "9000",
+ }
+
+ var dst DestStruct
+
+ err := copier.CopyWithOption(&dst, &src, copier.Option{
+ IgnoreEmpty: true,
+ DeepCopy: true,
+ Converters: []copier.TypeConverter{
+ {
+ SrcType: time.Time{},
+ DstType: copier.String,
+ Fn: func(src interface{}) (interface{}, error) {
+ s, ok := src.(time.Time)
+
+ if !ok {
+ return nil, errors.New("src type not matching")
+ }
+
+ return s.Format(time.RFC3339), nil
+ },
+ },
+ {
+ SrcType: copier.String,
+ DstType: copier.Int,
+ Fn: func(src interface{}) (interface{}, error) {
+ s, ok := src.(string)
+
+ if !ok {
+ return nil, errors.New("src type not matching")
+ }
+
+ return strconv.Atoi(s)
+ },
+ },
+ },
+ })
+
+ if err != nil {
+ t.Fatalf(`Should be able to copy from src to dst object. %v`, err)
+ return
+ }
+
+ dateStr := "2021-03-05T01:30:00Z"
+
+ if dst.Field1 != dateStr {
+ t.Fatalf("got %q, wanted %q", dst.Field1, dateStr)
+ }
+
+ if dst.Field2 != dateStr {
+ t.Fatalf("got %q, wanted %q", dst.Field2, dateStr)
+ }
+
+ if dst.Field3 != "" {
+ t.Fatalf("got %q, wanted %q", dst.Field3, "")
+ }
+
+ if dst.Field4 != 9000 {
+ t.Fatalf("got %q, wanted %q", dst.Field4, 9000)
+ }
+}
+
+func TestCopyWithConverterAndAnnotation(t *testing.T) {
+ type SrcStruct struct {
+ Field1 string
+ }
+
+ type DestStruct struct {
+ Field1 string
+ Field2 string `copier:"Field1"`
+ }
+
+ src := SrcStruct{
+ Field1: "test",
+ }
+
+ var dst DestStruct
+
+ err := copier.CopyWithOption(&dst, &src, copier.Option{
+ IgnoreEmpty: true,
+ DeepCopy: true,
+ Converters: []copier.TypeConverter{
+ {
+ SrcType: copier.String,
+ DstType: copier.String,
+ Fn: func(src interface{}) (interface{}, error) {
+ s, ok := src.(string)
+
+ if !ok {
+ return nil, errors.New("src type not matching")
+ }
+
+ return s + "2", nil
+ },
+ },
+ },
+ })
+
+ if err != nil {
+ t.Fatalf(`Should be able to copy from src to dst object. %v`, err)
+ return
+ }
+
+ if dst.Field2 != "test2" {
+ t.Fatalf("got %q, wanted %q", dst.Field2, "test2")
+ }
+}
+
+func TestCopyWithConverterStrToStrPointer(t *testing.T) {
+ type SrcStruct struct {
+ Field1 string
+ }
+
+ type DestStruct struct {
+ Field1 *string
+ }
+
+ src := SrcStruct{
+ Field1: "",
+ }
+
+ var dst DestStruct
+
+ ptrStrType := ""
+
+ err := copier.CopyWithOption(&dst, &src, copier.Option{
+ IgnoreEmpty: true,
+ DeepCopy: true,
+ Converters: []copier.TypeConverter{
+ {
+ SrcType: copier.String,
+ DstType: &ptrStrType,
+ Fn: func(src interface{}) (interface{}, error) {
+ s, _ := src.(string)
+
+ // return nil on empty string
+ if s == "" {
+ return nil, nil
+ }
+
+ return &s, nil
+ },
+ },
+ },
+ })
+
+ if err != nil {
+ t.Fatalf(`Should be able to copy from src to dst object. %v`, err)
+ return
+ }
+
+ if dst.Field1 != nil {
+ t.Fatalf("got %q, wanted nil", *dst.Field1)
+ }
+}
diff --git a/copier_test.go b/copier_test.go
index 9450d8e..f6d68a4 100644
--- a/copier_test.go
+++ b/copier_test.go
@@ -4,6 +4,7 @@ import (
"database/sql"
"errors"
"fmt"
+ "reflect"
"testing"
"time"
@@ -26,6 +27,7 @@ func (user User) DoubleAge() int32 {
}
type Employee struct {
+ _User *User
Name string
Birthday *time.Time
Nickname *string
@@ -134,6 +136,10 @@ func TestCopyStruct(t *testing.T) {
employee4 := &Employee{}
copier.Copy(&employee4, user)
checkEmployee(*employee4, user, t, "Copy From Ptr To Double Ptr")
+
+ employee5 := &Employee{}
+ copier.Copy(&employee5, &employee)
+ checkEmployee(*employee5, user, t, "Copy From Employee To Employee")
}
func TestCopyFromStructToSlice(t *testing.T) {
@@ -328,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
@@ -383,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")
}
@@ -408,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")
}
@@ -496,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: ¬es, 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) {
@@ -515,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")
}
@@ -539,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")
}
@@ -627,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: ¬es, 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")
+ }
+ })
})
}
@@ -1138,6 +1200,107 @@ func TestCopyMapOfInt(t *testing.T) {
}
}
+func TestCopyMapOfSliceValue(t *testing.T) {
+ // case1: map's value is a simple slice
+ key, value := 2, 3
+ src := map[int][]int{key: []int{value} }
+ dst1 := map[int][]int{}
+ var dst2 map[int][]int
+ err := copier.Copy(&dst1, src)
+ if err != nil {
+ t.Error("Should not raise error")
+ }
+ err = copier.Copy(&dst2, src)
+ if err != nil {
+ t.Error("Should not raise error")
+ }
+
+ for k, v1 := range src {
+ v2, ok := dst1[k]
+ if !ok || len(v1) != len(v2) || k != key {
+ t.Errorf("Map should be copied")
+ }
+ for i, _ := range v1 {
+ if v2[i] != value {
+ t.Errorf("Map's slice value shoud be copied")
+ }
+ }
+
+ v3, ok := dst2[k]
+ if !ok || len(v1) != len(v3) {
+ t.Errorf("Map should be copied")
+ }
+ for i := range v1 {
+ if v3[i] != value {
+ t.Errorf("Map's slice value shoud be copied")
+ }
+ }
+ }
+
+ // case2: map's value is a slice whose element is map
+ key1, key2 := 2, 3
+ value = 4
+ s := map[int][]map[int]int{key1: []map[int]int{ {key2: value} } }
+ d1 := map[int][]map[int]int{key1: []map[int]int{ {key1: key2 } } }
+ d2 := map[int][]map[int]int{key1: []map[int]int{ } }
+ d3 := map[int][]map[int]int{key1: nil }
+ d4 := map[int][]map[int]int{}
+ d5 := map[int][]map[int]int(nil)
+ ms := []map[int][]map[int]int{d1, d2, d3, d4, d5}
+ for i := range ms {
+ copier.CopyWithOption(&ms[i], s, copier.Option{IgnoreEmpty: false, DeepCopy: true})
+
+ if len(ms[i]) != len(s) {
+ t.Errorf("Number of map's keys should be equal")
+ }
+ for k, sliceMap := range ms[i] {
+ if k != key1 {
+ t.Errorf("Map's key should be copied")
+ }
+ if len(sliceMap) != len(s[key1]) || len(sliceMap) != 1 {
+ t.Errorf("Map's slice value should be copied")
+ }
+ m := sliceMap[0]
+ if len(m) != len(s[key1][0]) || len(m) != 1 {
+ t.Errorf("Map's slice value should be copied recursively")
+ }
+ for k, v := range m {
+ if k != key2 || v != value {
+ t.Errorf("Map's slice value should be copied recursively")
+ }
+ }
+ }
+ }
+}
+
+func TestCopyMapOfPtrValue(t *testing.T) {
+ intV := 3
+ intv := intV
+ src := map[int]*int{2: &intv }
+ dst1 := map[int]*int{}
+ var dst2 map[int]*int
+ err := copier.Copy(&dst1, src)
+ if err != nil {
+ t.Error("Should not raise error")
+ }
+ err = copier.Copy(&dst2, src)
+ if err != nil {
+ t.Error("Should not raise error")
+ }
+
+ for k, v1 := range src {
+ v2, ok := dst1[k]
+ if !ok || v2 == nil || v1 == nil || *v2 != *v1 || *v2 != intV {
+ t.Errorf("Map should be copied")
+ }
+
+ v3, ok := dst2[k]
+ if !ok || v3 == nil ||*v3 != *v1 || *v3 != intV {
+ t.Errorf("Map should be copied")
+ }
+ }
+}
+
func TestCopyWithOption(t *testing.T) {
from := structSameName2{D: "456", E: &someStruct{IntField: 100, UIntField: 1000}}
to := &structSameName1{A: "123", B: 2, C: time.Now(), D: "123", E: &someStruct{UIntField: 5000}}
@@ -1287,3 +1450,180 @@ func TestDeepCopyInterface(t *testing.T) {
t.Errorf("to value failed to be deep copied")
}
}
+
+func TestDeepCopyTime(t *testing.T) {
+ type embedT1 struct {
+ T5 time.Time
+ }
+
+ type embedT2 struct {
+ T6 *time.Time
+ }
+
+ var (
+ from struct {
+ T1 time.Time
+ T2 *time.Time
+
+ T3 *time.Time
+ T4 time.Time
+ T5 time.Time
+ T6 time.Time
+ }
+
+ to struct {
+ T1 time.Time
+ T2 *time.Time
+
+ T3 time.Time
+ T4 *time.Time
+ embedT1
+ embedT2
+ }
+ )
+
+ t1 := time.Now()
+ from.T1 = t1
+ t2 := t1.Add(time.Second)
+ from.T2 = &t2
+ t3 := t2.Add(time.Second)
+ from.T3 = &t3
+ t4 := t3.Add(time.Second)
+ from.T4 = t4
+ t5 := t4.Add(time.Second)
+ from.T5 = t5
+ t6 := t5.Add(time.Second)
+ from.T6 = t6
+
+ err := copier.CopyWithOption(&to, from, copier.Option{DeepCopy: true})
+ if err != nil {
+ t.Error("Should not raise error")
+ }
+
+ if !to.T1.Equal(from.T1) {
+ t.Errorf("Field T1 should be copied")
+ }
+ if !to.T2.Equal(*from.T2) {
+ t.Errorf("Field T2 should be copied")
+ }
+ if !to.T3.Equal(*from.T3) {
+ t.Errorf("Field T3 should be copied")
+ }
+ if !to.T4.Equal(from.T4) {
+ t.Errorf("Field T4 should be copied")
+ }
+ if !to.T5.Equal(from.T5) {
+ t.Errorf("Field T5 should be copied")
+ }
+ if !to.T6.Equal(from.T6) {
+ t.Errorf("Field T6 should be copied")
+ }
+}
+
+
+func TestNestedPrivateData(t *testing.T) {
+ type hasPrivate struct {
+ data int
+ }
+
+ type hasMembers struct {
+ Member hasPrivate
+ }
+
+ src := hasMembers{
+ Member: hasPrivate{
+ data: 42,
+ },
+ }
+ var shallow hasMembers
+ err := copier.Copy(&shallow, &src)
+ if err != nil {
+ t.Errorf("could not complete shallow copy")
+ }
+ if !reflect.DeepEqual(&src, &shallow) {
+ t.Errorf("shallow copy faild")
+ }
+
+ var deep hasMembers
+ err = copier.CopyWithOption(&deep, &src, copier.Option{DeepCopy: true})
+ if err != nil {
+ t.Errorf("could not complete deep copy")
+ }
+ if !reflect.DeepEqual(&src, &deep) {
+ t.Errorf("deep copy faild")
+ }
+
+ if !reflect.DeepEqual(&shallow, &deep) {
+ t.Errorf("unexpected difference between shallow and deep copy")
+ }
+}
+
+
+func TestDeepMapCopyTime(t *testing.T) {
+ t1 := time.Now()
+ t2 := t1.Add(time.Second)
+ from := []map[string]interface{}{
+ {
+ "t1": t1,
+ "t2": &t2,
+ },
+ }
+ to := make([]map[string]interface{}, len(from))
+
+ err := copier.CopyWithOption(&to, from, copier.Option{DeepCopy: true})
+ if err != nil {
+ t.Error("should not error")
+ }
+ if len(to) != len(from) {
+ t.Errorf("slice should be copied")
+ }
+ if !to[0]["t1"].(time.Time).Equal(from[0]["t1"].(time.Time)) {
+ t.Errorf("nested time ptr should be copied")
+ }
+ if !to[0]["t2"].(*time.Time).Equal(*from[0]["t2"].(*time.Time)) {
+ t.Errorf("nested time ptr should be copied")
+ }
+}
+
+func TestCopySimpleTime(t *testing.T) {
+ from := time.Now()
+ to := time.Time{}
+
+ err := copier.Copy(&to, from)
+ if err != nil {
+ t.Error("should not error")
+ }
+ if !from.Equal(to) {
+ t.Errorf("to (%v) value should equal from (%v) value", to, from)
+ }
+}
+
+func TestDeepCopySimpleTime(t *testing.T) {
+ from := time.Now()
+ to := time.Time{}
+
+ err := copier.CopyWithOption(&to, from, copier.Option{DeepCopy: true})
+ if err != nil {
+ t.Error("should not error")
+ }
+ if !from.Equal(to) {
+ t.Errorf("to (%v) value should equal from (%v) value", to, from)
+ }
+}
+
+type TimeWrapper struct{
+ time.Time
+}
+
+func TestDeepCopyAnonymousFieldTime(t *testing.T) {
+ from := TimeWrapper{time.Now()}
+ to := TimeWrapper{}
+
+ err := copier.CopyWithOption(&to, from, copier.Option{DeepCopy: true})
+ if err != nil {
+ t.Error("should not error")
+ }
+ if !from.Time.Equal(to.Time) {
+ t.Errorf("to (%v) value should equal from (%v) value", to.Time, from.Time)
+ }
+}
diff --git a/debian/changelog b/debian/changelog
index ce37c4d..d285572 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+golang-github-jinzhu-copier (0.3.5-1) UNRELEASED; urgency=low
+
+ * New upstream release.
+
+ -- Debian Janitor <janitor@jelmer.uk> Thu, 29 Sep 2022 06:37:18 -0000
+
golang-github-jinzhu-copier (0.3.2-2) unstable; urgency=medium
* update standards version
diff --git a/go.mod b/go.mod
index 531422d..309801e 100644
--- a/go.mod
+++ b/go.mod
@@ -1,3 +1,3 @@
module github.com/jinzhu/copier
-go 1.15
+go 1.13
Debdiff
[The following lists of changes regard files as different if they have different names, permissions or owners.]
Files in second set of .debs but not in first
-rw-r--r-- root/root /usr/share/gocode/src/github.com/jinzhu/copier/copier_converter_test.go
No differences were encountered in the control files