加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
copier_test.go 40.92 KB
一键复制 编辑 原始数据 按行查看 历史
helloqiu 提交于 2024-07-10 17:36 . fix: fix copying nil slice
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776
package copier_test
import (
"database/sql"
"errors"
"fmt"
"reflect"
"testing"
"time"
"github.com/jinzhu/copier"
)
type User struct {
Name string
Birthday *time.Time
Nickname string
Role string
Age int32
FakeAge *int32
Notes []string
flags []byte
}
func (user User) DoubleAge() int32 {
return 2 * user.Age
}
type Employee struct {
_User *User
Name string
Birthday *time.Time
NickName *string
Age int64
FakeAge int
EmployeID int64
DoubleAge int32
SuperRule string
Notes []*string
flags []byte
}
func (employee *Employee) Role(role string) {
employee.SuperRule = "Super " + role
}
func checkEmployee(employee Employee, user User, t *testing.T, testCase string) {
if employee.Name != user.Name {
t.Errorf("%v: Name haven't been copied correctly.", testCase)
}
if employee.NickName == nil || *employee.NickName != user.Nickname {
t.Errorf("%v: NickName haven't been copied correctly.", testCase)
}
if employee.Birthday == nil && user.Birthday != nil {
t.Errorf("%v: Birthday haven't been copied correctly.", testCase)
}
if employee.Birthday != nil && user.Birthday == nil {
t.Errorf("%v: Birthday haven't been copied correctly.", testCase)
}
if employee.Birthday != nil && user.Birthday != nil &&
!employee.Birthday.Equal(*(user.Birthday)) {
t.Errorf("%v: Birthday haven't been copied correctly.", testCase)
}
if employee.Age != int64(user.Age) {
t.Errorf("%v: Age haven't been copied correctly.", testCase)
}
if user.FakeAge != nil && employee.FakeAge != int(*user.FakeAge) {
t.Errorf("%v: FakeAge haven't been copied correctly.", testCase)
}
if employee.DoubleAge != user.DoubleAge() {
t.Errorf("%v: Copy from method doesn't work", testCase)
}
if employee.SuperRule != "Super "+user.Role {
t.Errorf("%v: Copy to method doesn't work", testCase)
}
if len(employee.Notes) != len(user.Notes) {
t.Fatalf("%v: Copy from slice doesn't work, employee notes len: %v, user: %v", testCase, len(employee.Notes), len(user.Notes))
}
for idx, note := range user.Notes {
if note != *employee.Notes[idx] {
t.Fatalf("%v: Copy from slice doesn't work, notes idx: %v employee: %v user: %v", testCase, idx, *employee.Notes[idx], note)
}
}
}
func TestCopySameStructWithPointerField(t *testing.T) {
var fakeAge int32 = 12
var currentTime time.Time = time.Now()
user := &User{Birthday: &currentTime, Name: "Jinzhu", Nickname: "jinzhu", Age: 18, FakeAge: &fakeAge, Role: "Admin", Notes: []string{"hello world", "welcome"}, flags: []byte{'x'}}
newUser := &User{}
copier.Copy(newUser, user)
if user.Birthday == newUser.Birthday {
t.Errorf("TestCopySameStructWithPointerField: copy Birthday failed since they need to have different address")
}
if user.FakeAge == newUser.FakeAge {
t.Errorf("TestCopySameStructWithPointerField: copy FakeAge failed since they need to have different address")
}
}
func checkEmployee2(employee Employee, user *User, t *testing.T, testCase string) {
if user == nil {
if employee.Name != "" || employee.NickName != nil || employee.Birthday != nil || employee.Age != 0 ||
employee.DoubleAge != 0 || employee.FakeAge != 0 || employee.SuperRule != "" || employee.Notes != nil {
t.Errorf("%v : employee should be empty", testCase)
}
return
}
checkEmployee(employee, *user, t, testCase)
}
func TestCopySliceOfDifferentTypes(t *testing.T) {
var ss []string
var is []int
if err := copier.Copy(&ss, is); err != nil {
t.Error(err)
}
var anotherSs []string
if !reflect.DeepEqual(ss, anotherSs) {
t.Errorf("Copy nil slice to nil slice should get nil slice")
}
}
func TestCopyStruct(t *testing.T) {
var fakeAge int32 = 12
user := User{Name: "Jinzhu", Nickname: "jinzhu", Age: 18, FakeAge: &fakeAge, Role: "Admin", Notes: []string{"hello world", "welcome"}, flags: []byte{'x'}}
employee := Employee{}
if err := copier.Copy(employee, &user); err == nil {
t.Errorf("Copy to unaddressable value should get error")
}
copier.Copy(&employee, &user)
checkEmployee(employee, user, t, "Copy From Ptr To Ptr")
employee2 := Employee{}
copier.Copy(&employee2, user)
checkEmployee(employee2, user, t, "Copy From Struct To Ptr")
employee3 := Employee{}
ptrToUser := &user
copier.Copy(&employee3, &ptrToUser)
checkEmployee(employee3, user, t, "Copy From Double Ptr To Ptr")
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) {
user := User{Name: "Jinzhu", Age: 18, Role: "Admin", Notes: []string{"hello world"}}
employees := []Employee{}
if err := copier.Copy(employees, &user); err != nil && len(employees) != 0 {
t.Errorf("Copy to unaddressable value should get error")
}
if copier.Copy(&employees, &user); len(employees) != 1 {
t.Errorf("Should only have one elem when copy struct to slice")
} else {
checkEmployee(employees[0], user, t, "Copy From Struct To Slice Ptr")
}
employees2 := &[]Employee{}
if copier.Copy(&employees2, user); len(*employees2) != 1 {
t.Errorf("Should only have one elem when copy struct to slice")
} else {
checkEmployee((*employees2)[0], user, t, "Copy From Struct To Double Slice Ptr")
}
employees3 := []*Employee{}
if copier.Copy(&employees3, user); len(employees3) != 1 {
t.Errorf("Should only have one elem when copy struct to slice")
} else {
checkEmployee(*(employees3[0]), user, t, "Copy From Struct To Ptr Slice Ptr")
}
employees4 := &[]*Employee{}
if copier.Copy(&employees4, user); len(*employees4) != 1 {
t.Errorf("Should only have one elem when copy struct to slice")
} else {
checkEmployee(*((*employees4)[0]), user, t, "Copy From Struct To Double Ptr Slice Ptr")
}
}
func TestCopyFromSliceToSlice(t *testing.T) {
users := []User{
{Name: "Jinzhu", Age: 18, Role: "Admin", Notes: []string{"hello world"}},
{Name: "Jinzhu2", Age: 22, Role: "Dev", Notes: []string{"hello world", "hello"}}}
employees := []Employee{}
if copier.Copy(&employees, users); len(employees) != 2 {
t.Errorf("Should have two elems when copy slice to slice")
} else {
checkEmployee(employees[0], users[0], t, "Copy From Slice To Slice Ptr @ 1")
checkEmployee(employees[1], users[1], t, "Copy From Slice To Slice Ptr @ 2")
}
employees2 := &[]Employee{}
if copier.Copy(&employees2, &users); len(*employees2) != 2 {
t.Errorf("Should have two elems when copy slice to slice")
} else {
checkEmployee((*employees2)[0], users[0], t, "Copy From Slice Ptr To Double Slice Ptr @ 1")
checkEmployee((*employees2)[1], users[1], t, "Copy From Slice Ptr To Double Slice Ptr @ 2")
}
employees3 := []*Employee{}
if copier.Copy(&employees3, users); len(employees3) != 2 {
t.Errorf("Should have two elems when copy slice to slice")
} else {
checkEmployee(*(employees3[0]), users[0], t, "Copy From Slice To Ptr Slice Ptr @ 1")
checkEmployee(*(employees3[1]), users[1], t, "Copy From Slice To Ptr Slice Ptr @ 2")
}
employees4 := &[]*Employee{}
if copier.Copy(&employees4, users); len(*employees4) != 2 {
t.Errorf("Should have two elems when copy slice to slice")
} else {
checkEmployee(*((*employees4)[0]), users[0], t, "Copy From Slice Ptr To Double Ptr Slice Ptr @ 1")
checkEmployee(*((*employees4)[1]), users[1], t, "Copy From Slice Ptr To Double Ptr Slice Ptr @ 2")
}
}
func TestCopyFromSliceToSlice2(t *testing.T) {
users := []*User{{Name: "Jinzhu", Age: 18, Role: "Admin", Notes: []string{"hello world"}}, nil}
employees := []Employee{}
if copier.Copy(&employees, users); len(employees) != 2 {
t.Errorf("Should have two elems when copy slice to slice")
} else {
checkEmployee2(employees[0], users[0], t, "Copy From Slice To Slice Ptr @ 1")
checkEmployee2(employees[1], users[1], t, "Copy From Slice To Slice Ptr @ 2")
}
employees2 := &[]Employee{}
if copier.Copy(&employees2, &users); len(*employees2) != 2 {
t.Errorf("Should have two elems when copy slice to slice")
} else {
checkEmployee2((*employees2)[0], users[0], t, "Copy From Slice Ptr To Double Slice Ptr @ 1")
checkEmployee2((*employees2)[1], users[1], t, "Copy From Slice Ptr To Double Slice Ptr @ 2")
}
employees3 := []*Employee{}
if copier.Copy(&employees3, users); len(employees3) != 2 {
t.Errorf("Should have two elems when copy slice to slice")
} else {
checkEmployee2(*(employees3[0]), users[0], t, "Copy From Slice To Ptr Slice Ptr @ 1")
checkEmployee2(*(employees3[1]), users[1], t, "Copy From Slice To Ptr Slice Ptr @ 2")
}
employees4 := &[]*Employee{}
if copier.Copy(&employees4, users); len(*employees4) != 2 {
t.Errorf("Should have two elems when copy slice to slice")
} else {
checkEmployee2(*((*employees4)[0]), users[0], t, "Copy From Slice Ptr To Double Ptr Slice Ptr @ 1")
checkEmployee2(*((*employees4)[1]), users[1], t, "Copy From Slice Ptr To Double Ptr Slice Ptr @ 2")
}
}
func TestCopyFromSliceToSlice3(t *testing.T) {
type CollectionAlias struct {
CollectionName string `json:"collection_name"`
Name string `json:"name"`
}
expectedResult := []*CollectionAlias{
{"collection", "collection_alias1"},
{"collection", "collection_alias2"},
{"collection", "collection_alias3"},
}
mockedResult := []*CollectionAlias{}
copier.Copy(&mockedResult, &expectedResult)
if len(mockedResult) != len(expectedResult) {
t.Fatalf("failed to copy results")
}
for idx := range mockedResult {
if mockedResult[idx].Name != mockedResult[idx].Name || mockedResult[idx].CollectionName != mockedResult[idx].CollectionName {
t.Fatalf("failed to copy results")
}
}
}
func TestEmbeddedAndBase(t *testing.T) {
type Base struct {
BaseField1 int
BaseField2 int
User *User
}
type Embed struct {
EmbedField1 int
EmbedField2 int
Base
}
base := Base{}
embedded := Embed{}
embedded.BaseField1 = 1
embedded.BaseField2 = 2
embedded.EmbedField1 = 3
embedded.EmbedField2 = 4
user := User{
Name: "testName",
}
embedded.User = &user
copier.Copy(&base, &embedded)
if base.BaseField1 != 1 || base.User.Name != "testName" {
t.Error("Embedded fields not copied")
}
base.BaseField1 = 11
base.BaseField2 = 12
user1 := User{
Name: "testName1",
}
base.User = &user1
copier.Copy(&embedded, &base)
if embedded.BaseField1 != 11 || embedded.User.Name != "testName1" {
t.Error("base fields not copied")
}
}
func TestStructField(t *testing.T) {
type Detail struct {
Info1 string
Info2 *string
}
type SimilarDetail struct {
Info1 string
Info2 *string
}
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
}
type UserWithSimilarDetails struct {
Detail SimilarDetail
}
type EmployeeWithDetails struct {
Detail Detail
}
type EmployeeWithDetailsPtr struct {
Detail *Detail
}
type EmployeeWithSimilarDetails struct {
Detail SimilarDetail
}
type EmployeeWithSimilarDetailsPtr struct {
Detail *SimilarDetail
}
optionsDeepCopy := copier.Option{
DeepCopy: true,
}
checkDetail := func(t *testing.T, source Detail, target Detail) {
if source.Info1 != target.Info1 {
t.Errorf("info1 is diff: source: %v, target: %v", source.Info1, target.Info1)
}
if (source.Info2 != nil || target.Info2 != nil) && (*source.Info2 != *target.Info2) {
t.Errorf("info2 is diff: source: %v, target: %v", *source.Info2, *target.Info2)
}
}
t.Run("Should work without deepCopy", func(t *testing.T) {
t.Run("Should work with same type and both ptr field", func(t *testing.T) {
info2 := "world"
from := UserWithDetailsPtr{
Detail: &Detail{Info1: "hello", Info2: &info2},
Details: []*Detail{{Info1: "hello", Info2: &info2}},
}
to := UserWithDetailsPtr{}
copier.Copy(&to, from)
checkDetail(t, *from.Detail, *to.Detail)
*to.Detail.Info2 = "new value"
if *from.Detail.Info2 != *to.Detail.Info2 {
t.Fatalf("DeepCopy not enabled")
}
if len(from.Details) != len(to.Details) {
t.Fatalf("slice should be copied")
}
for idx, detail := range from.Details {
checkDetail(t, *detail, *to.Details[idx])
}
})
t.Run("Should work with same type and both not ptr field", func(t *testing.T) {
info2 := "world"
from := UserWithDetails{
Detail: Detail{Info1: "hello", Info2: &info2},
Details: []Detail{{Info1: "hello", Info2: &info2}},
}
to := UserWithDetails{}
copier.Copy(&to, from)
checkDetail(t, from.Detail, to.Detail)
*to.Detail.Info2 = "new value"
if *from.Detail.Info2 != *to.Detail.Info2 {
t.Fatalf("DeepCopy not enabled")
}
if len(from.Details) != len(to.Details) {
t.Fatalf("slice should be copied")
}
for idx, detail := range from.Details {
checkDetail(t, detail, to.Details[idx])
}
})
t.Run("Should work with different type and both ptr field", func(t *testing.T) {
info2 := "world"
from := UserWithDetailsPtr{Detail: &Detail{Info1: "hello", Info2: &info2}}
to := EmployeeWithDetailsPtr{}
copier.Copy(&to, from)
newValue := "new value"
to.Detail.Info2 = &newValue
if to.Detail.Info1 == "" {
t.Errorf("should not be empty")
}
if to.Detail.Info1 != from.Detail.Info1 {
t.Errorf("should be the same")
}
if to.Detail.Info2 == from.Detail.Info2 {
t.Errorf("should be different")
}
})
t.Run("Should work with different type and both not ptr field", func(t *testing.T) {
info2 := "world"
from := UserWithDetails{Detail: Detail{Info1: "hello", Info2: &info2}}
to := EmployeeWithDetails{}
copier.Copy(&to, from)
newValue := "new value"
to.Detail.Info2 = &newValue
if to.Detail.Info1 == "" {
t.Errorf("should not be empty")
}
if to.Detail.Info1 != from.Detail.Info1 {
t.Errorf("should be the same")
}
if to.Detail.Info2 == from.Detail.Info2 {
t.Errorf("should be different")
}
})
t.Run("Should work with from ptr field and to not ptr field", func(t *testing.T) {
info2 := "world"
from := UserWithDetailsPtr{Detail: &Detail{Info1: "hello", Info2: &info2}}
to := EmployeeWithDetails{}
copier.Copy(&to, from)
newValue := "new value"
to.Detail.Info2 = &newValue
if to.Detail.Info1 == "" {
t.Errorf("should not be empty")
}
if to.Detail.Info1 != from.Detail.Info1 {
t.Errorf("should be the same")
}
if to.Detail.Info2 == from.Detail.Info2 {
t.Errorf("should be different")
}
})
t.Run("Should work with from not ptr field and to ptr field", func(t *testing.T) {
info2 := "world"
from := UserWithDetails{Detail: Detail{Info1: "hello", Info2: &info2}}
to := EmployeeWithDetailsPtr{}
copier.Copy(&to, from)
newValue := "new value"
to.Detail.Info2 = &newValue
if to.Detail.Info1 == "" {
t.Errorf("should not be empty")
}
if to.Detail.Info1 != from.Detail.Info1 {
t.Errorf("should be the same")
}
if to.Detail.Info2 == from.Detail.Info2 {
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) {
t.Run("Should work with same type and both ptr field", func(t *testing.T) {
info2 := "world"
from := UserWithDetailsPtr{
Detail: &Detail{Info1: "hello", Info2: &info2},
Details: []*Detail{{Info1: "hello", Info2: &info2}},
}
to := UserWithDetailsPtr{}
copier.CopyWithOption(&to, from, optionsDeepCopy)
checkDetail(t, *from.Detail, *to.Detail)
*to.Detail.Info2 = "new value"
if *from.Detail.Info2 == *to.Detail.Info2 {
t.Fatalf("DeepCopy enabled")
}
if len(from.Details) != len(to.Details) {
t.Fatalf("slice should be copied")
}
for idx, detail := range from.Details {
checkDetail(t, *detail, *to.Details[idx])
}
})
t.Run("Should work with same type and both not ptr field", func(t *testing.T) {
info2 := "world"
from := UserWithDetails{
Detail: Detail{Info1: "hello", Info2: &info2},
Details: []Detail{{Info1: "hello", Info2: &info2}},
}
to := UserWithDetails{}
copier.CopyWithOption(&to, from, optionsDeepCopy)
checkDetail(t, from.Detail, to.Detail)
*to.Detail.Info2 = "new value"
if *from.Detail.Info2 == *to.Detail.Info2 {
t.Fatalf("DeepCopy enabled")
}
if len(from.Details) != len(to.Details) {
t.Fatalf("slice should be copied")
}
for idx, detail := range from.Details {
checkDetail(t, detail, to.Details[idx])
}
})
t.Run("Should work with different type and both ptr field", func(t *testing.T) {
info2 := "world"
from := UserWithDetailsPtr{Detail: &Detail{Info1: "hello", Info2: &info2}}
to := EmployeeWithDetailsPtr{}
copier.CopyWithOption(&to, from, optionsDeepCopy)
newValue := "new value"
to.Detail.Info2 = &newValue
if to.Detail.Info1 == "" {
t.Errorf("should not be empty")
}
if to.Detail.Info1 != from.Detail.Info1 {
t.Errorf("should be the same")
}
if to.Detail.Info2 == from.Detail.Info2 {
t.Errorf("should be different")
}
})
t.Run("Should work with different type and both not ptr field", func(t *testing.T) {
info2 := "world"
from := UserWithDetails{Detail: Detail{Info1: "hello", Info2: &info2}}
to := EmployeeWithDetails{}
copier.CopyWithOption(&to, from, optionsDeepCopy)
newValue := "new value"
to.Detail.Info2 = &newValue
if to.Detail.Info1 == "" {
t.Errorf("should not be empty")
}
if to.Detail.Info1 != from.Detail.Info1 {
t.Errorf("should be the same")
}
if to.Detail.Info2 == from.Detail.Info2 {
t.Errorf("should be different")
}
})
t.Run("Should work with from ptr field and to not ptr field", func(t *testing.T) {
info2 := "world"
from := UserWithDetailsPtr{Detail: &Detail{Info1: "hello", Info2: &info2}}
to := EmployeeWithDetails{}
copier.CopyWithOption(&to, from, optionsDeepCopy)
newValue := "new value"
to.Detail.Info2 = &newValue
if to.Detail.Info1 == "" {
t.Errorf("should not be empty")
}
if to.Detail.Info1 != from.Detail.Info1 {
t.Errorf("should be the same")
}
if to.Detail.Info2 == from.Detail.Info2 {
t.Errorf("should be different")
}
})
t.Run("Should work with from not ptr field and to ptr field", func(t *testing.T) {
info2 := "world"
from := UserWithDetails{Detail: Detail{Info1: "hello", Info2: &info2}}
to := EmployeeWithDetailsPtr{}
copier.CopyWithOption(&to, from, optionsDeepCopy)
newValue := "new value"
to.Detail.Info2 = &newValue
if to.Detail.Info1 == "" {
t.Errorf("should not be empty")
}
if to.Detail.Info1 != from.Detail.Info1 {
t.Errorf("should be the same")
}
if to.Detail.Info2 == from.Detail.Info2 {
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")
}
})
})
}
func TestMapInterface(t *testing.T) {
type Inner struct {
IntPtr *int
unexportedField string
}
type Outer struct {
Inner Inner
}
type DriverOptions struct {
GenOptions map[string]interface{}
}
t.Run("Should work without deepCopy", func(t *testing.T) {
intVal := 5
outer := Outer{
Inner: Inner{
IntPtr: &intVal,
unexportedField: "hello",
},
}
from := DriverOptions{
GenOptions: map[string]interface{}{
"key": outer,
},
}
to := DriverOptions{}
if err := copier.Copy(&to, &from); nil != err {
t.Errorf("Unexpected error: %v", err)
return
}
*to.GenOptions["key"].(Outer).Inner.IntPtr = 6
if to.GenOptions["key"].(Outer).Inner.IntPtr != from.GenOptions["key"].(Outer).Inner.IntPtr {
t.Errorf("should be the same")
}
})
t.Run("Should work with deepCopy", func(t *testing.T) {
intVal := 5
outer := Outer{
Inner: Inner{
IntPtr: &intVal,
unexportedField: "Hello",
},
}
from := DriverOptions{
GenOptions: map[string]interface{}{
"key": outer,
},
}
to := DriverOptions{}
if err := copier.CopyWithOption(&to, &from, copier.Option{
DeepCopy: true,
}); nil != err {
t.Errorf("Unexpected error: %v", err)
return
}
*to.GenOptions["key"].(Outer).Inner.IntPtr = 6
if to.GenOptions["key"].(Outer).Inner.IntPtr == from.GenOptions["key"].(Outer).Inner.IntPtr {
t.Errorf("should be different")
}
})
t.Run("Test copy map with nil interface", func(t *testing.T) {
from := map[string]interface{}{"eventId": nil}
to := map[string]interface{}{"eventId": nil}
copier.CopyWithOption(&to, &from, copier.Option{IgnoreEmpty: true, DeepCopy: true})
if v, ok := to["eventId"]; !ok || v != nil {
t.Errorf("failed to deep copy map with nil, got %v", v)
}
from["eventId"] = 1
if v, ok := to["eventId"]; !ok || v != nil {
t.Errorf("failed to deep copy map with nil, got %v", v)
}
copier.CopyWithOption(&to, &from, copier.Option{IgnoreEmpty: true, DeepCopy: true})
if v, ok := to["eventId"]; !ok || v != 1 {
t.Errorf("failed to deep copy map with nil")
}
from["eventId"] = 2
if v, ok := to["eventId"]; !ok || v != 1 {
t.Errorf("failed to deep copy map with nil")
}
})
t.Run("Test copy map with nested slice map", func(t *testing.T) {
var out map[string]interface{}
value := map[string]interface{}{
"list": []map[string]interface{}{
{
"shop_id": 123,
},
},
"list2": []interface{}{
map[string]interface{}{
"shop_id": 123,
},
},
}
err := copier.CopyWithOption(&out, &value, copier.Option{IgnoreEmpty: false, DeepCopy: true})
if err != nil {
t.Fatalf("failed to deep copy nested map")
}
if fmt.Sprintf("%v", out) != fmt.Sprintf("%v", value) {
t.Fatalf("failed to deep copy nested map")
}
})
}
func TestInterface(t *testing.T) {
type Inner struct {
IntPtr *int
}
type Outer struct {
Inner Inner
}
type DriverOptions struct {
GenOptions interface{}
}
t.Run("Should work without deepCopy", func(t *testing.T) {
intVal := 5
outer := Outer{
Inner: Inner{
IntPtr: &intVal,
},
}
from := DriverOptions{
GenOptions: outer,
}
to := DriverOptions{}
if err := copier.Copy(&to, from); nil != err {
t.Errorf("Unexpected error: %v", err)
return
}
*to.GenOptions.(Outer).Inner.IntPtr = 6
if to.GenOptions.(Outer).Inner.IntPtr != from.GenOptions.(Outer).Inner.IntPtr {
t.Errorf("should be the same")
}
})
t.Run("Should work with deepCopy", func(t *testing.T) {
intVal := 5
outer := Outer{
Inner: Inner{
IntPtr: &intVal,
},
}
from := DriverOptions{
GenOptions: outer,
}
to := DriverOptions{}
if err := copier.CopyWithOption(&to, &from, copier.Option{
DeepCopy: true,
}); nil != err {
t.Errorf("Unexpected error: %v", err)
return
}
*to.GenOptions.(Outer).Inner.IntPtr = 6
if to.GenOptions.(Outer).Inner.IntPtr == from.GenOptions.(Outer).Inner.IntPtr {
t.Errorf("should be different")
}
})
}
func TestSlice(t *testing.T) {
type ElemOption struct {
Value int
}
type A struct {
X []int
Options []ElemOption
}
type B struct {
X []int
Options []ElemOption
}
t.Run("Should work with simple slice", func(t *testing.T) {
from := []int{1, 2}
var to []int
if err := copier.Copy(&to, from); nil != err {
t.Errorf("Unexpected error: %v", err)
return
}
from[0] = 3
from[1] = 4
if to[0] == from[0] {
t.Errorf("should be different")
}
if len(to) != len(from) {
t.Errorf("should be the same length, got len(from): %v, len(to): %v", len(from), len(to))
}
})
t.Run("Should work with empty slice", func(t *testing.T) {
from := []int{}
to := []int{}
if err := copier.Copy(&to, from); nil != err {
t.Errorf("Unexpected error: %v", err)
return
}
if to == nil {
t.Errorf("should be not nil")
}
})
t.Run("Should work without deepCopy", func(t *testing.T) {
x := []int{1, 2}
options := []ElemOption{
{Value: 10},
{Value: 20},
}
from := A{X: x, Options: options}
to := B{}
if err := copier.Copy(&to, from); nil != err {
t.Errorf("Unexpected error: %v", err)
return
}
from.X[0] = 3
from.X[1] = 4
from.Options[0].Value = 30
from.Options[1].Value = 40
if to.X[0] != from.X[0] {
t.Errorf("should be the same")
}
if len(to.X) != len(from.X) {
t.Errorf("should be the same length, got len(from.X): %v, len(to.X): %v", len(from.X), len(to.X))
}
if to.Options[0].Value != from.Options[0].Value {
t.Errorf("should be the same")
}
if to.Options[0].Value != from.Options[0].Value {
t.Errorf("should be the same")
}
if len(to.Options) != len(from.Options) {
t.Errorf("should be the same")
}
})
t.Run("Should work with deepCopy", func(t *testing.T) {
x := []int{1, 2}
options := []ElemOption{
{Value: 10},
{Value: 20},
}
from := A{X: x, Options: options}
to := B{}
if err := copier.CopyWithOption(&to, from, copier.Option{
DeepCopy: true,
}); nil != err {
t.Errorf("Unexpected error: %v", err)
return
}
from.X[0] = 3
from.X[1] = 4
from.Options[0].Value = 30
from.Options[1].Value = 40
if to.X[0] == from.X[0] {
t.Errorf("should be different")
}
if len(to.X) != len(from.X) {
t.Errorf("should be the same length, got len(from.X): %v, len(to.X): %v", len(from.X), len(to.X))
}
if to.Options[0].Value == from.Options[0].Value {
t.Errorf("should be different")
}
if len(to.Options) != len(from.Options) {
t.Errorf("should be the same")
}
})
}
func TestAnonymousFields(t *testing.T) {
t.Run("Should work with unexported ptr fields", func(t *testing.T) {
type nested struct {
A string
}
type parentA struct {
*nested
}
type parentB struct {
*nested
}
from := parentA{nested: &nested{A: "a"}}
to := parentB{}
err := copier.CopyWithOption(&to, &from, copier.Option{
DeepCopy: true,
})
if err != nil {
t.Errorf("Unexpected error: %v", err)
return
}
from.nested.A = "b"
if to.nested != nil {
t.Errorf("should be nil")
}
})
t.Run("Should work with unexported fields", func(t *testing.T) {
type nested struct {
A string
}
type parentA struct {
nested
}
type parentB struct {
nested
}
from := parentA{nested: nested{A: "a"}}
to := parentB{}
err := copier.CopyWithOption(&to, &from, copier.Option{
DeepCopy: true,
})
if err != nil {
t.Errorf("Unexpected error: %v", err)
return
}
from.nested.A = "b"
if to.nested.A == from.nested.A {
t.Errorf("should be different")
}
})
t.Run("Should work with exported ptr fields", func(t *testing.T) {
type Nested struct {
A string
}
type parentA struct {
*Nested
}
type parentB struct {
*Nested
}
fieldValue := "a"
from := parentA{Nested: &Nested{A: fieldValue}}
to := parentB{}
err := copier.CopyWithOption(&to, &from, copier.Option{
DeepCopy: true,
})
if err != nil {
t.Errorf("Unexpected error: %v", err)
return
}
from.Nested.A = "b"
if to.Nested.A != fieldValue {
t.Errorf("should not change")
}
})
t.Run("Should work with exported ptr fields with same name src field", func(t *testing.T) {
type Nested struct {
A string
}
type parentA struct {
A string
}
type parentB struct {
*Nested
}
fieldValue := "a"
from := parentA{A: fieldValue}
to := parentB{}
err := copier.CopyWithOption(&to, &from, copier.Option{
DeepCopy: true,
})
if err != nil {
t.Errorf("Unexpected error: %v", err)
return
}
from.A = "b"
if to.Nested.A != fieldValue {
t.Errorf("should not change")
}
})
t.Run("Should work with exported fields", func(t *testing.T) {
type Nested struct {
A string
}
type parentA struct {
Nested
}
type parentB struct {
Nested
}
fieldValue := "a"
from := parentA{Nested: Nested{A: fieldValue}}
to := parentB{}
err := copier.CopyWithOption(&to, &from, copier.Option{
DeepCopy: true,
})
if err != nil {
t.Errorf("Unexpected error: %v", err)
return
}
from.Nested.A = "b"
if to.Nested.A != fieldValue {
t.Errorf("should not change")
}
})
}
type someStruct struct {
IntField int
UIntField uint64
}
type structSameName1 struct {
A string
B int64
C time.Time
D string
E *someStruct
}
type structSameName2 struct {
A string
B time.Time
C int64
D string
E *someStruct
}
func TestCopyFieldsWithSameNameButDifferentTypes(t *testing.T) {
obj1 := structSameName1{A: "123", B: 2, C: time.Now()}
obj2 := &structSameName2{}
err := copier.Copy(obj2, &obj1)
if err != nil {
t.Error("Should not raise error")
}
if obj2.A != obj1.A {
t.Errorf("Field A should be copied")
}
}
type Foo1 struct {
Name string
Age int32
}
type Foo2 struct {
Name string
}
type StructWithMap1 struct {
Map map[int]Foo1
}
type StructWithMap2 struct {
Map map[int32]Foo2
}
func TestCopyMapOfStruct(t *testing.T) {
obj1 := StructWithMap1{Map: map[int]Foo1{2: {Name: "A pure foo"}}}
obj2 := &StructWithMap2{}
err := copier.Copy(obj2, obj1)
if err != nil {
t.Error("Should not raise error")
}
for k, v1 := range obj1.Map {
v2, ok := obj2.Map[int32(k)]
if !ok || v1.Name != v2.Name {
t.Errorf("Map should be copied")
}
}
}
func TestCopyMapOfInt(t *testing.T) {
map1 := map[int]int{3: 6, 4: 8}
map2 := map[int32]int8{}
err := copier.Copy(&map2, map1)
if err != nil {
t.Error("Should not raise error")
}
for k, v1 := range map1 {
v2, ok := map2[int32(k)]
if !ok || v1 != int(v2) {
t.Errorf("Map should be copied")
}
}
}
func TestCopyMapOfSliceValue(t *testing.T) {
// case1: map's value is a simple slice
key, value := 2, 3
src := map[int][]int{key: {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: {{key2: value}}}
d1 := map[int][]map[int]int{key1: {{key1: key2}}}
d2 := map[int][]map[int]int{key1: {}}
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}}
if err := copier.CopyWithOption(to, &from, copier.Option{IgnoreEmpty: true}); err != nil {
t.Error("Should not raise error")
}
if to.A == from.A {
t.Errorf("Field A should not be copied")
} else if to.D != from.D {
t.Errorf("Field D should be copied")
}
}
type ScannerValue struct {
V int
}
func (s *ScannerValue) Scan(src interface{}) error {
return errors.New("I failed")
}
type ScannerStruct struct {
V *ScannerValue
}
type ScannerStructTo struct {
V *ScannerValue
}
func TestScanner(t *testing.T) {
s := &ScannerStruct{
V: &ScannerValue{
V: 12,
},
}
s2 := &ScannerStructTo{}
err := copier.Copy(s2, s)
if err != nil {
t.Error("Should not raise error")
}
if s.V.V != s2.V.V {
t.Errorf("Field V should be copied")
}
}
func TestScanFromPtrToSqlNullable(t *testing.T) {
var (
from struct {
S string
Sptr *string
Snull sql.NullString
T1 sql.NullTime
T2 sql.NullTime
T3 *time.Time
}
to struct {
S sql.NullString
Sptr sql.NullString
Snull *string
T1 time.Time
T2 *time.Time
T3 sql.NullTime
}
s string
err error
)
s = "test"
from.S = s
from.Sptr = &s
if from.T1.Valid || from.T2.Valid {
t.Errorf("Must be not valid")
}
err = copier.Copy(&to, from)
if err != nil {
t.Error("Should not raise error")
}
if !to.T1.IsZero() {
t.Errorf("to.T1 should be Zero but %v", to.T1)
}
if to.T2 != nil {
t.Errorf("to.T2 should be nil but %v", to.T2)
}
if to.Snull != nil {
t.Errorf("to.Snull should be nil but %v", to.Snull)
}
now := time.Now()
from.T1.Scan(now)
from.T2.Scan(now)
err = copier.Copy(&to, from)
if err != nil {
t.Error("Should not raise error")
}
if to.S.String != from.S {
t.Errorf("Field S should be copied")
}
if to.Sptr.String != *from.Sptr {
t.Errorf("Field Sptr should be copied")
}
if from.T1.Time != to.T1 {
t.Errorf("Fields T1 fields should be equal")
}
if from.T2.Time != *to.T2 {
t.Errorf("Fields T2 fields should be equal")
}
}
func TestDeepCopyInterface(t *testing.T) {
m := make(map[string]string)
m["a"] = "ccc"
from := []interface{}{[]int{7, 8, 9}, 2, 3, m, errors.New("aaaa")}
var to []interface{}
copier.CopyWithOption(&to, &from, copier.Option{
IgnoreEmpty: false,
DeepCopy: true,
})
from[0].([]int)[0] = 10
from[1] = "3"
from[3].(map[string]string)["a"] = "bbb"
if fmt.Sprint(to[0]) != fmt.Sprint([]int{7, 8, 9}) {
t.Errorf("to value failed to be deep copied")
}
if fmt.Sprint(to[1]) != "2" {
t.Errorf("to value failed to be deep copied")
}
if to[3].(map[string]string)["a"] != "ccc" {
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)
}
}
func TestSqlNullFiled(t *testing.T) {
type sqlStruct struct {
MkId sql.NullInt64
MkExpiryDateType sql.NullInt32
MkExpiryDateStart sql.NullString
}
type dataStruct struct {
MkId int64
MkExpiryDateType int32
MkExpiryDateStart string
}
from := sqlStruct{
MkId: sql.NullInt64{Int64: 3, Valid: true},
MkExpiryDateType: sql.NullInt32{Int32: 4, Valid: true},
MkExpiryDateStart: sql.NullString{String: "5", Valid: true},
}
to := dataStruct{}
err := copier.Copy(&to, from)
if err != nil {
t.Error("should not error")
}
if from.MkId.Int64 != to.MkId {
t.Errorf("to (%v) value should equal from (%v) value", to.MkId, from.MkId.Int64)
}
if from.MkExpiryDateStart.String != to.MkExpiryDateStart {
t.Errorf("to (%v) value should equal from (%v) value", to.MkExpiryDateStart, from.MkExpiryDateStart.String)
}
if from.MkExpiryDateType.Int32 != to.MkExpiryDateType {
t.Errorf("to (%v) value should equal from (%v) value", to.MkExpiryDateType, from.MkExpiryDateType.Int32)
}
}
func TestEmptySlice(t *testing.T) {
type Str1 string
type Str2 string
type Input1 struct {
Val Str1
}
type Input2 struct {
Val Str2
}
to := []*Input1(nil)
from := []*Input2{}
err := copier.Copy(&to, &from)
if err != nil {
t.Error("should not error")
}
if from == nil {
t.Error("from should be empty slice not nil")
}
to = []*Input1(nil)
from = []*Input2(nil)
err = copier.Copy(&to, &from)
if err != nil {
t.Error("should not error")
}
if from != nil {
t.Error("from should be empty slice nil")
}
}
func TestNestedNilPointerStruct(t *testing.T) {
type destination struct {
Title string
}
type NestedSource struct {
ID int
}
type source struct {
Title string
*NestedSource
}
from := &source{
Title: "A title to be copied",
}
to := destination{}
err := copier.Copy(&to, from)
if err != nil {
t.Error("should not error")
}
if from.Title != to.Title {
t.Errorf("to (%v) value should equal from (%v) value", to.Title, from.Title)
}
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化