Files
copier/copier_test.go
2025-09-30 18:41:21 +08:00

436 lines
7.6 KiB
Go

package copier
import (
"fmt"
"reflect"
"testing"
"time"
)
type Person struct {
Age int ``
Name string ``
Address Address ``
}
type Address struct {
Country string
City string
}
type Person2 struct {
Name string
Age int
}
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 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 TestCopySameStruct(t *testing.T) {
src := &Person{
Name: "John",
Age: 30,
Address: Address{
Country: "USA",
City: "New York",
},
}
var dst Person
if err := Copy(&dst, src); err != nil {
t.Fatal(err)
}
if dst.Name != src.Name || dst.Age != src.Age {
t.Errorf("Expected %v, got %v", src, dst)
}
fmt.Println("src,dst:", src, dst)
}
func TestCopyToNamedStruct(t *testing.T) {
type Person3 struct {
Name string `copier:"toname=Name2"`
Age int
}
type Person4 struct {
Name2 string
Age int
}
src := &Person3{
Name: "John",
Age: 30,
}
var dst Person4
if err := Copy(&dst, src); err != nil {
t.Fatal(err)
}
t.Log("src,dst:", src, dst)
}
func TestCopyDiffStruct(t *testing.T) {
src := &Person{
Name: "John",
Age: 30,
Address: Address{
Country: "USA",
City: "New York",
},
}
var dst Person2
if err := Copy(&dst, src); err != nil {
t.Fatal(err)
}
t.Log("src,dst:", src, dst)
}
func TestCopyPtrStruct(t *testing.T) {
type User struct {
Name string
Age int
Address *Address
}
src := User{
Name: "John",
Age: 30,
Address: &Address{
Country: "USA",
City: "New York",
},
}
var dst User
if err := Copy(&dst, src); err != nil {
t.Fatal(err)
}
if dst.Name != src.Name || dst.Age != src.Age {
t.Errorf("Expected %v, got %v", src, dst)
}
t.Log("src,dst:", src, dst)
}
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 := Copy(&to, &from)
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 := Copy(&to, &from)
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 := Copy(&to, &from)
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 := Copy(&to, &from)
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 := Copy(&to, &from)
if err != nil {
t.Errorf("Unexpected error: %v", err)
return
}
from.Nested.A = "b"
if to.Nested.A != fieldValue {
t.Errorf("should not change")
}
})
}
func TestTypeConvert(t *testing.T) {
type Book struct {
Name string
Date time.Time
}
type Book2 struct {
Name string
Date string
}
var src = Book{
Name: "Book1",
Date: time.Now(),
}
var dst Book2
if err := Copy(&dst, &src, WithTypeConvertByName("Date", func(src any) (dst any, err error) {
return src.(time.Time).Format("2006-01-02"), nil
})); err != nil {
t.Fatal(err)
}
t.Log("src,dst:", src, dst)
}
func TestDeepFileds(t *testing.T) {
var emp = Employee{}
typ := reflect.TypeOf(emp)
copier := New()
wrapper := copier.deepFields(typ)
for _, v := range wrapper {
t.Log(v)
}
}
func BenchmarkCopy(b *testing.B) {
var emp = Employee{
Name: "John",
Age: 30,
}
for b.Loop() {
var dst Employee
if err := Copy(&dst, &emp); err != nil {
b.Fatal(err)
}
}
}
func BenchmarkDeepFields(b *testing.B) {
var emp = Employee{}
typ := reflect.TypeOf(emp)
for b.Loop() {
copier := New()
copier.deepFields(typ)
}
}
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
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
Copy(&embedded, &base)
if embedded.BaseField1 != 11 || embedded.User.Name != "testName1" {
t.Error("base fields not copied")
}
}