436 lines
7.6 KiB
Go
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")
|
|
}
|
|
}
|