github.com/hedzr/evendeep@v0.4.8/ctrl_test.go (about)

     1  package evendeep_test
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"encoding/json"
     7  	"fmt"
     8  	"io"
     9  	"math"
    10  	"reflect"
    11  	"strings"
    12  	"testing"
    13  	"time"
    14  	"unsafe"
    15  
    16  	"gopkg.in/hedzr/errors.v3"
    17  
    18  	"github.com/hedzr/evendeep"
    19  	"github.com/hedzr/evendeep/dbglog"
    20  	"github.com/hedzr/evendeep/diff"
    21  	"github.com/hedzr/evendeep/flags/cms"
    22  	"github.com/hedzr/evendeep/internal/tool"
    23  	"github.com/hedzr/evendeep/typ"
    24  )
    25  
    26  const (
    27  	helloString  = "hello"
    28  	worldString  = "world"
    29  	aHelloString = "Hello"
    30  	aWorldString = "World"
    31  )
    32  
    33  func TestDeepCopyForInvalidSourceOrTarget(t *testing.T) {
    34  	invalidObj := func() typ.Any {
    35  		var x *evendeep.X0
    36  		return x
    37  	}
    38  	t.Run("invalid source", func(t *testing.T) {
    39  		src := invalidObj()
    40  		tgt := invalidObj()
    41  		evendeep.DeepCopy(src, &tgt)
    42  		t.Logf("tgt: %+v", tgt)
    43  	})
    44  	t.Run("valid ptr to invalid source", func(t *testing.T) {
    45  		src := invalidObj()
    46  		tgt := invalidObj()
    47  		evendeep.DeepCopy(&src, &tgt)
    48  		t.Logf("tgt: %+v", tgt)
    49  	})
    50  
    51  	nilmap := func() typ.Any {
    52  		var mm []map[string]struct{}
    53  		return mm
    54  	}
    55  	t.Run("nil map", func(t *testing.T) {
    56  		src := nilmap()
    57  		tgt := nilmap()
    58  		evendeep.DeepCopy(src, &tgt)
    59  		t.Logf("tgt: %+v", tgt)
    60  	})
    61  	t.Run("valid ptr to nil map", func(t *testing.T) {
    62  		src := nilmap()
    63  		tgt := nilmap()
    64  		evendeep.DeepCopy(&src, &tgt)
    65  		t.Logf("tgt: %+v", tgt)
    66  	})
    67  
    68  	nilslice := func() typ.Any {
    69  		var mm []map[string]struct{}
    70  		return mm
    71  	}
    72  	t.Run("nil slice", func(t *testing.T) {
    73  		src := nilslice()
    74  		tgt := nilslice()
    75  		evendeep.DeepCopy(src, &tgt)
    76  		t.Logf("tgt: %+v", tgt)
    77  	})
    78  	t.Run("valid ptr to nil slice", func(t *testing.T) {
    79  		src := nilslice()
    80  		tgt := nilslice()
    81  		evendeep.DeepCopy(&src, &tgt)
    82  		t.Logf("tgt: %+v", tgt)
    83  	})
    84  }
    85  
    86  type ccs struct {
    87  	string
    88  	int
    89  	*float64
    90  }
    91  
    92  func (s *ccs) Clone() interface{} {
    93  	return &ccs{
    94  		string:  s.string,
    95  		int:     s.int,
    96  		float64: &(*s.float64), // nolint:staticcheck
    97  	}
    98  }
    99  
   100  func TestCloneableSource(t *testing.T) {
   101  	cloneable := func() *ccs {
   102  		f := evendeep.Randtool.NextFloat64()
   103  		return &ccs{
   104  			string:  evendeep.Randtool.NextStringSimple(13),
   105  			int:     evendeep.Randtool.NextIn(300),
   106  			float64: &f,
   107  		}
   108  	}
   109  
   110  	t.Run("invoke Cloneable interface", func(t *testing.T) {
   111  		src := cloneable()
   112  		tgt := cloneable()
   113  		sav := *tgt
   114  		evendeep.DeepCopy(&src, &tgt)
   115  		t.Logf("src: %v, old: %v, new tgt: %v", src, sav, tgt)
   116  		if reflect.DeepEqual(src, tgt) == false {
   117  			var err error
   118  			dif, equal := diff.New(src, tgt)
   119  			if !equal {
   120  				fmt.Println(dif)
   121  				err = errors.New("diff.PrettyDiff identified its not equal:\ndifferent:\n%v", dif)
   122  			}
   123  			t.Fatalf("not equal. %v", err)
   124  		}
   125  	})
   126  }
   127  
   128  type dcs struct {
   129  	string
   130  	int
   131  	*float64
   132  }
   133  
   134  func (s *dcs) DeepCopy() interface{} {
   135  	return &dcs{
   136  		string:  s.string,
   137  		int:     s.int,
   138  		float64: &(*s.float64), // nolint:staticcheck
   139  	}
   140  }
   141  
   142  func TestDeepCopyableSource(t *testing.T) {
   143  	copyable := func() *dcs {
   144  		f := evendeep.Randtool.NextFloat64()
   145  		return &dcs{
   146  			string:  evendeep.Randtool.NextStringSimple(13),
   147  			int:     evendeep.Randtool.NextIn(300),
   148  			float64: &f,
   149  		}
   150  	}
   151  
   152  	t.Run("invoke DeepCopyable interface", func(t *testing.T) {
   153  		src := copyable()
   154  		tgt := copyable()
   155  		sav := *tgt
   156  		evendeep.DeepCopy(&src, &tgt)
   157  		t.Logf("src: %v, old: %v, new tgt: %v", src, sav, tgt)
   158  		if reflect.DeepEqual(src, tgt) == false {
   159  			var err error
   160  			dif, equal := diff.New(src, tgt)
   161  			if !equal {
   162  				fmt.Println(dif)
   163  				err = errors.New("diff.PrettyDiff identified its not equal:\ndifferent:\n%v", dif)
   164  			}
   165  			t.Fatalf("not equal. %v", err)
   166  		}
   167  	}) // NewTasskks creates a
   168  }
   169  
   170  func TestSimple(t *testing.T) {
   171  
   172  	// var dInt = 9
   173  	// var dStr = worldString
   174  
   175  	for _, tc := range []evendeep.TestCase{
   176  		evendeep.NewTestCase(
   177  			"primitive - int",
   178  			8, 9, 8,
   179  			nil,
   180  			nil,
   181  		),
   182  		evendeep.NewTestCase(
   183  			"primitive - string",
   184  			helloString, worldString, helloString,
   185  			[]evendeep.Opt{
   186  				evendeep.WithStrategiesReset(cms.Default),
   187  			},
   188  			nil,
   189  		),
   190  		evendeep.NewTestCase(
   191  			"primitive - string slice",
   192  			[]string{helloString, worldString},
   193  			&[]string{"andy"},                   // target needn't addressof
   194  			&[]string{helloString, worldString}, // SliceCopy: copy to target; SliceCopyAppend: append to target; SliceMerge: merge into slice
   195  			[]evendeep.Opt{
   196  				evendeep.WithStrategiesReset(),
   197  			},
   198  			nil,
   199  		),
   200  		evendeep.NewTestCase(
   201  			"primitive - string slice - merge",
   202  			[]string{helloString, helloString, worldString}, // elements in source will be merged into target with uniqueness.
   203  			&[]string{"andy", "andy"},                       // target needn't addressof
   204  			&[]string{"andy", helloString, worldString},     // In merge mode, any dup elems will be removed.
   205  			[]evendeep.Opt{
   206  				evendeep.WithMergeStrategyOpt,
   207  			},
   208  			nil,
   209  		),
   210  		evendeep.NewTestCase(
   211  			"primitive - int slice",
   212  			[]int{7, 99},
   213  			&[]int{5},
   214  			&[]int{7, 99},
   215  			[]evendeep.Opt{
   216  				evendeep.WithStrategiesReset(),
   217  			},
   218  			nil,
   219  		),
   220  		evendeep.NewTestCase(
   221  			"primitive - int slice - merge",
   222  			[]int{7, 99},
   223  			&[]int{5},
   224  			&[]int{5, 7, 99},
   225  			[]evendeep.Opt{
   226  				evendeep.WithStrategies(cms.SliceMerge),
   227  			},
   228  			nil,
   229  		),
   230  		evendeep.NewTestCase(
   231  			"primitive types - int slice - merge for dup",
   232  			[]int{99, 7}, &[]int{125, 99}, &[]int{125, 99, 7},
   233  			[]evendeep.Opt{
   234  				evendeep.WithStrategies(cms.SliceMerge),
   235  			},
   236  			nil,
   237  		),
   238  		// NEED REVIEW: what is copyenh strategy
   239  		// evendeep.NewTestCase(
   240  		//	"primitive types - int slice - copyenh(overwrite and extend)",
   241  		//	[]int{13, 7, 99}, []int{125, 99}, []int{7, 99, 7},
   242  		//	[]evendeep.Opt{
   243  		//		evendeep.WithStrategies(evendeep.SliceCopyOverwrite),
   244  		//	},
   245  		//	nil,
   246  		// ),
   247  	} {
   248  		t.Run(evendeep.RunTestCasesWith(&tc)) // nolint:gosec // G601: Implicit memory aliasing in for loop
   249  	}
   250  
   251  }
   252  
   253  func TestTypeConvert(t *testing.T) {
   254  
   255  	var i9 = 9
   256  	var i5 = 5
   257  	var ui6 = uint(6)
   258  	var i64 int64 = 10
   259  	var f64 = 9.1
   260  
   261  	cases := []evendeep.TestCase{
   262  		evendeep.NewTestCase(
   263  			"int -> int64",
   264  			8, i64, int64(8),
   265  			nil,
   266  			nil,
   267  		),
   268  		evendeep.NewTestCase(
   269  			"int64 -> int",
   270  			int64(8), i5, 8,
   271  			nil,
   272  			nil,
   273  		),
   274  		evendeep.NewTestCase(
   275  			"int64 -> uint",
   276  			int64(8), ui6, uint(8),
   277  			nil,
   278  			nil,
   279  		),
   280  		evendeep.NewTestCase(
   281  			"float32 -> float64",
   282  			float32(8.1), f64, float64(8.100000381469727),
   283  			nil,
   284  			nil,
   285  		),
   286  		evendeep.NewTestCase(
   287  			"complex -> complex128",
   288  			complex64(8.1+3i), complex128(9.1), complex128(8.100000381469727+3i),
   289  			nil,
   290  			nil,
   291  		),
   292  		evendeep.NewTestCase(
   293  			"complex -> int - ErrCannotConvertTo test",
   294  			complex64(8.1+3i), &i5, int(8),
   295  			nil,
   296  			func(src, dst, expect typ.Any, e error) (err error) {
   297  				if errors.IsDescended(evendeep.ErrCannotConvertTo, e) {
   298  					return
   299  				}
   300  				return e
   301  			},
   302  		),
   303  		evendeep.NewTestCase(
   304  			"int -> intptr",
   305  			8, &i9, 8,
   306  			nil,
   307  			func(src, dst, expect typ.Any, e error) (err error) {
   308  				if d, ok := dst.(*int); ok && e == nil {
   309  					if *d == src {
   310  						return
   311  					}
   312  				}
   313  				return errors.DataLoss
   314  			},
   315  		),
   316  	}
   317  
   318  	for ix, tc := range cases {
   319  		if !t.Run(fmt.Sprintf("%3d. %s", ix, tc.Description), evendeep.DefaultDeepCopyTestRunner(ix, tc)) {
   320  			break
   321  		}
   322  	}
   323  }
   324  
   325  func TestTypeConvert2Slice(t *testing.T) {
   326  
   327  	var i9 = 9
   328  	var i5 = 5
   329  	// var ui6 = uint(6)
   330  	// var i64 int64 = 10
   331  	// var f64 float64 = 9.1
   332  
   333  	// slice
   334  
   335  	var si64 = []int64{9}
   336  	var si = []int{9}
   337  	var sui = []uint{9}
   338  	var sf64 = []float64{9.1}
   339  	var sc128 = []complex128{9.1}
   340  
   341  	opts := []evendeep.Opt{
   342  		evendeep.WithStrategies(cms.SliceMerge),
   343  	}
   344  
   345  	cases := []evendeep.TestCase{
   346  		evendeep.NewTestCase(
   347  			"[]int -> []int64",
   348  			[]int{8}, &si64, &[]int64{9, 8},
   349  			opts,
   350  			nil,
   351  		),
   352  		evendeep.NewTestCase(
   353  			"int -> []int64",
   354  			7, &si64, &[]int64{9, 8, 7},
   355  			opts,
   356  			nil,
   357  		),
   358  		evendeep.NewTestCase(
   359  			"[]int64 -> []int",
   360  			[]int64{8}, &si, &[]int{9, 8},
   361  			opts,
   362  			nil,
   363  		),
   364  		evendeep.NewTestCase(
   365  			"int64 -> []int",
   366  			int64(7), &si, &[]int{9, 8, 7},
   367  			opts,
   368  			nil,
   369  		),
   370  		evendeep.NewTestCase(
   371  			"[]int64 -> []int (truncate the overflowed input)",
   372  			[]int64{math.MaxInt64}, &si, &[]int{9, 8, 7, cms.MaxInt},
   373  			opts,
   374  			nil,
   375  		),
   376  		evendeep.NewTestCase(
   377  			"int64 -> []uint",
   378  			int64(8), sui, []uint{9, 8},
   379  			opts,
   380  			nil,
   381  		),
   382  		evendeep.NewTestCase(
   383  			"int64 -> *[]uint",
   384  			int64(8), &sui, &[]uint{9, 8},
   385  			opts,
   386  			nil,
   387  		),
   388  		evendeep.NewTestCase(
   389  			"float32 -> []float64",
   390  			float32(8.1), &sf64, &[]float64{9.1, 8.100000381469727},
   391  			opts,
   392  			nil,
   393  		),
   394  		evendeep.NewTestCase(
   395  			"[]float32 -> []float64",
   396  			[]float32{8.1}, &sf64, &[]float64{9.1, 8.100000381469727},
   397  			opts,
   398  			nil,
   399  		),
   400  		evendeep.NewTestCase(
   401  			"complex64 -> []complex128",
   402  			complex64(8.1+3i), &sc128, &[]complex128{9.1, 8.100000381469727 + 3i},
   403  			opts,
   404  			nil,
   405  		),
   406  		evendeep.NewTestCase(
   407  			"[]complex64 -> []complex128",
   408  			[]complex64{8.1 + 3i}, &sc128, &[]complex128{9.1 + 0i, 8.100000381469727 + 3i},
   409  			opts,
   410  			nil,
   411  		),
   412  		evendeep.NewTestCase(
   413  			"complex -> int - ErrCannotConvertTo test",
   414  			complex64(8.1+3i), &i5, int(8),
   415  			opts,
   416  			func(src, dst, expect typ.Any, e error) (err error) {
   417  				if errors.IsDescended(evendeep.ErrCannotConvertTo, e) {
   418  					return
   419  				}
   420  				return e
   421  			},
   422  		),
   423  		evendeep.NewTestCase(
   424  			"int -> intptr",
   425  			8, &i9, 8,
   426  			opts,
   427  			func(src, dst, expect typ.Any, e error) (err error) {
   428  				if d, ok := dst.(*int); ok && e == nil {
   429  					if *d == src {
   430  						return
   431  					}
   432  				}
   433  				return errors.DataLoss
   434  			},
   435  		),
   436  	}
   437  
   438  	for ix, tc := range cases {
   439  		if !t.Run(fmt.Sprintf("%3d. %s", ix, tc.Description), evendeep.DefaultDeepCopyTestRunner(ix, tc)) {
   440  			break
   441  		}
   442  	}
   443  }
   444  
   445  func TestTypeConvert3Func(t *testing.T) {
   446  	// type B struct {
   447  	//	F func(int) (int, error)
   448  	// }
   449  	// b1 := B{F: func(i int) (int, error) { i1 = i * 2; return i1, nil }}
   450  
   451  	opts := []evendeep.Opt{
   452  		evendeep.WithPassSourceToTargetFunctionOpt,
   453  	}
   454  
   455  	i1 := 0
   456  	b1 := func(i []int) (int, error) { i1 = i[0] * 2; return i1, nil }
   457  	// var e1 error
   458  	b2 := func(i int) (int, error) {
   459  		if i > 0 {
   460  			return 0, errors.BadRequest
   461  		}
   462  		return i, nil
   463  	}
   464  
   465  	cases := []evendeep.TestCase{
   466  		evendeep.NewTestCase(
   467  			"[]int -> func(int)(int,error)",
   468  			[]int{8}, &b1, nil,
   469  			opts,
   470  			func(src, dst, expect typ.Any, e error) (err error) {
   471  				if i1 != 16 {
   472  					err = errors.BadRequest
   473  				}
   474  				return
   475  			},
   476  		),
   477  		evendeep.NewTestCase(
   478  			"int -> func(int)(int,error)",
   479  			8, &b2, nil,
   480  			opts,
   481  			func(src, dst, expect typ.Any, e error) (err error) {
   482  				if !errors.Is(e, errors.BadRequest) {
   483  					err = errors.BadRequest
   484  				}
   485  				return
   486  			},
   487  		),
   488  	}
   489  
   490  	for ix, tc := range cases {
   491  		if !t.Run(fmt.Sprintf("%3d. %s", ix, tc.Description), evendeep.DefaultDeepCopyTestRunner(ix, tc)) {
   492  			break
   493  		}
   494  	}
   495  }
   496  
   497  func TestErrorCodeIs(t *testing.T) {
   498  	var err error = errors.BadRequest
   499  	if !errors.Is(err, errors.BadRequest) {
   500  		t.Fatalf("want is")
   501  	}
   502  	err = io.ErrClosedPipe
   503  	if errors.Is(err, errors.BadRequest) {
   504  		t.Fatalf("want not is")
   505  	}
   506  	err = errors.NotFound
   507  	if errors.Is(err, errors.BadRequest) {
   508  		t.Fatalf("want not is (code)")
   509  	}
   510  }
   511  
   512  func TestStructStdlib(t *testing.T) {
   513  
   514  	// timeZone, _ := time.LoadLocation("America/Phoenix")
   515  	timeZone2, _ := time.LoadLocation("Asia/Chongqing")
   516  	tm1 := time.Date(1979, 1, 29, 13, 3, 49, 19730313, timeZone2)
   517  	var tgt time.Time
   518  	var dur time.Duration
   519  	var dur1 = 13*time.Second + 3*time.Nanosecond
   520  	var bb, bb1 bytes.Buffer
   521  	bb1.WriteString("hellp world")
   522  	var b, be []byte
   523  	be = bb1.Bytes()
   524  
   525  	var bbn *bytes.Buffer = nil
   526  
   527  	for _, tc := range []evendeep.TestCase{
   528  		evendeep.NewTestCase(
   529  			"stdlib - time.Time 1",
   530  			tm1, &tgt, &tm1,
   531  			nil,
   532  			nil,
   533  		),
   534  		evendeep.NewTestCase(
   535  			"stdlib - time.Duration 1",
   536  			dur1, &dur, &dur1,
   537  			nil,
   538  			nil,
   539  		),
   540  		evendeep.NewTestCase(
   541  			"stdlib - bytes.Buffer 1",
   542  			bb1, &bb, &bb1,
   543  			nil,
   544  			nil,
   545  		),
   546  		evendeep.NewTestCase(
   547  			"stdlib - bytes.Buffer 2",
   548  			bb1, &b, &be,
   549  			nil,
   550  			nil,
   551  		),
   552  		evendeep.NewTestCase(
   553  			"stdlib - bytes.Buffer 2 - target is nil",
   554  			bb1, &bbn, &bb1,
   555  			nil,
   556  			func(src, dst, expect typ.Any, e error) (err error) {
   557  				if err = e; e != nil {
   558  					return
   559  				}
   560  				if p, ok := dst.(**bytes.Buffer); ok && *p == nil {
   561  					return
   562  				} else {
   563  					dbglog.Log("p = %v, ok = %v, dst = %v/%v", p, ok, dst, &bbn)
   564  				}
   565  				err = errors.InvalidArgument
   566  				return
   567  			},
   568  		),
   569  	} {
   570  		t.Run(evendeep.RunTestCasesWith(&tc)) // nolint:gosec // G601: Implicit memory aliasing in for loop
   571  	}
   572  
   573  }
   574  
   575  func TestStructSimple(t *testing.T) {
   576  	// defer dbglog.NewCaptureLog(t).Release()
   577  
   578  	nn := []int{2, 9, 77, 111, 23, 29}
   579  	var a [2]string
   580  	a[0] = aHelloString
   581  	a[1] = aWorldString
   582  	var a3 = [3]string{aHelloString, aWorldString}
   583  
   584  	x0 := evendeep.X0{}
   585  	x1 := evendeep.X1{
   586  		A: uintptr(unsafe.Pointer(&x0)),
   587  		H: make(chan int, 5),
   588  		M: unsafe.Pointer(&x0),
   589  		// E: []*X0{&x0},
   590  		N: nn[1:5],
   591  		O: a,
   592  		Q: a,
   593  	}
   594  
   595  	expect1 := &evendeep.X2{
   596  		A: uintptr(unsafe.Pointer(&x0)),
   597  		// D: []string{},
   598  		// E: []*evendeep.X0{},
   599  		H: make(chan int, 5),
   600  		K: &x0,
   601  		M: unsafe.Pointer(&x0),
   602  		// E: []*X0{&x0},
   603  		N: nn[1:5],
   604  		O: a,
   605  		Q: a3,
   606  	}
   607  	x2 := evendeep.X2{N: []int{23, 8}}
   608  	expect2 := &evendeep.X2{
   609  		A: uintptr(unsafe.Pointer(&x0)),
   610  		H: x1.H,
   611  		K: &x0,
   612  		M: unsafe.Pointer(&x0),
   613  		// E: []*X0{&x0},
   614  		N: []int{23, 8, 9, 77, 111}, // Note: [23,8] + [9,77,111,23] -> [23,8,9,77,111]
   615  		O: a,
   616  		Q: a3,
   617  	}
   618  	t.Logf("expect.Q: %v", expect1.Q)
   619  
   620  	t.Logf("   src: %+v", x1)
   621  	t.Logf("   tgt: %+v", evendeep.X2{N: nn[1:3]})
   622  
   623  	cases := []evendeep.TestCase{
   624  		evendeep.NewTestCase(
   625  			"struct - 1",
   626  			x1, &evendeep.X2{N: nn[1:3]}, expect1,
   627  			[]evendeep.Opt{
   628  				evendeep.WithStrategiesReset(),
   629  				// evendeep.WithStrategies(cms.OmitIfEmpty),
   630  				evendeep.WithAutoNewForStructFieldOpt,
   631  			},
   632  			nil,
   633  			// func(src, dst, expect typ.Any) (err error) {
   634  			//	dif, equal := diff.New(expect, dst)
   635  			//	if !equal {
   636  			//		fmt.Println(dif)
   637  			//	}
   638  			//	return
   639  			// },
   640  		),
   641  		evendeep.NewTestCase(
   642  			"struct - 2 - merge",
   643  			x1, &x2,
   644  			expect2,
   645  			[]evendeep.Opt{
   646  				evendeep.WithStrategies(cms.SliceMerge),
   647  				evendeep.WithAutoNewForStructFieldOpt,
   648  			},
   649  			nil,
   650  		),
   651  	}
   652  
   653  	for ix, tc := range cases {
   654  		if !t.Run(fmt.Sprintf("%3d. %s", ix, tc.Description), evendeep.DefaultDeepCopyTestRunner(ix, tc)) {
   655  			break
   656  		}
   657  	}
   658  }
   659  
   660  func TestStructEmbedded(t *testing.T) {
   661  
   662  	timeZone, _ := time.LoadLocation("America/Phoenix")
   663  	tm := time.Date(1999, 3, 13, 5, 57, 11, 1901, timeZone)
   664  	tm2 := time.Date(2003, 9, 1, 23, 59, 59, 3579, timeZone)
   665  
   666  	src := evendeep.Employee2{
   667  		Base: evendeep.Base{
   668  			Name:      "Bob",
   669  			Birthday:  &tm,
   670  			Age:       24,
   671  			EmployeID: 7,
   672  		},
   673  		Avatar: "https://tse4-mm.cn.bing.net/th/id/OIP-C.SAy__OKoxrIqrXWAb7Tj1wHaEC?pid=ImgDet&rs=1",
   674  		Image:  []byte{95, 27, 43, 66, 0, 21, 210},
   675  		Attr:   &evendeep.Attr{Attrs: []string{helloString, worldString}},
   676  		Valid:  true,
   677  	}
   678  
   679  	tgt := evendeep.User{
   680  		Name:      "Frank",
   681  		Birthday:  &tm2,
   682  		Age:       18,
   683  		EmployeID: 9,
   684  		Attr:      &evendeep.Attr{Attrs: []string{"baby"}},
   685  		Deleted:   true,
   686  	}
   687  
   688  	expect1 := &evendeep.User{
   689  		Name:      "Bob",
   690  		Birthday:  &tm,
   691  		Age:       24,
   692  		EmployeID: 7,
   693  		Avatar:    "https://tse4-mm.cn.bing.net/th/id/OIP-C.SAy__OKoxrIqrXWAb7Tj1wHaEC?pid=ImgDet&rs=1",
   694  		Image:     []byte{95, 27, 43, 66, 0, 21, 210},
   695  		Attr:      &evendeep.Attr{Attrs: []string{"baby", helloString, worldString}},
   696  		Valid:     true,
   697  	}
   698  
   699  	cases := []evendeep.TestCase{
   700  		evendeep.NewTestCase(
   701  			"struct - 1",
   702  			src, &tgt,
   703  			expect1,
   704  			[]evendeep.Opt{
   705  				evendeep.WithMergeStrategyOpt,
   706  				evendeep.WithAutoExpandStructOpt,
   707  			},
   708  			nil,
   709  			// func(src, dst, expect typ.Any) (err error) {
   710  			//	dif, equal := diff.New(expect, dst)
   711  			//	if !equal {
   712  			//		fmt.Println(dif)
   713  			//	}
   714  			//	return
   715  			// },
   716  		),
   717  	}
   718  
   719  	for ix, tc := range cases {
   720  		if !t.Run(fmt.Sprintf("%3d. %s", ix, tc.Description), evendeep.DefaultDeepCopyTestRunner(ix, tc)) {
   721  			break
   722  		}
   723  	}
   724  }
   725  
   726  func TestStructToSliceOrMap(t *testing.T) {
   727  
   728  	timeZone, _ := time.LoadLocation("America/Phoenix")
   729  	tm := time.Date(1999, 3, 13, 5, 57, 11, 1901, timeZone)
   730  	// timeZone2, _ := time.LoadLocation("Asia/Chongqing")
   731  	// tm1 := time.Date(2021, 2, 28, 13, 1, 23, 800, timeZone2)
   732  	// tm2 := time.Date(2003, 9, 1, 23, 59, 59, 3579, timeZone)
   733  	// tm3 := time.Date(2015, 1, 29, 19, 31, 37, 77, timeZone2)
   734  
   735  	src := evendeep.Employee2{
   736  		Base: evendeep.Base{
   737  			Name:      "Bob",
   738  			Birthday:  &tm,
   739  			Age:       24,
   740  			EmployeID: 7,
   741  		},
   742  		Avatar: "https://tse4-mm.cn.bing.net/th/id/OIP-C.SAy__OKoxrIqrXWAb7Tj1wHaEC?pid=ImgDet&rs=1",
   743  		Image:  []byte{95, 27, 43, 66, 0, 21, 210},
   744  		Attr:   &evendeep.Attr{Attrs: []string{helloString, worldString}},
   745  		Valid:  true,
   746  	}
   747  
   748  	var slice1 []evendeep.User
   749  	var slice2 []*evendeep.User
   750  
   751  	var map1 = make(map[string]typ.Any)
   752  
   753  	expect1 := evendeep.User{
   754  		Name:      "Bob",
   755  		Birthday:  &tm,
   756  		Age:       24,
   757  		EmployeID: 7,
   758  		Avatar:    "https://tse4-mm.cn.bing.net/th/id/OIP-C.SAy__OKoxrIqrXWAb7Tj1wHaEC?pid=ImgDet&rs=1",
   759  		Image:     []byte{95, 27, 43, 66, 0, 21, 210},
   760  		Attr:      &evendeep.Attr{Attrs: []string{helloString, worldString}},
   761  		Valid:     true,
   762  	}
   763  
   764  	expect3 := map[string]typ.Any{
   765  		"Name":      "Bob",
   766  		"Birthday":  tm,
   767  		"Age":       24,
   768  		"EmployeID": int64(7),
   769  		"Avatar":    "https://tse4-mm.cn.bing.net/th/id/OIP-C.SAy__OKoxrIqrXWAb7Tj1wHaEC?pid=ImgDet&rs=1",
   770  		"Image":     []byte{95, 27, 43, 66, 0, 21, 210},
   771  		"Attrs":     []string{helloString, worldString},
   772  		"Valid":     true,
   773  		"Deleted":   false,
   774  	}
   775  
   776  	t.Run("struct - slice - 1", func(t *testing.T) {
   777  		//
   778  	})
   779  
   780  	var str string
   781  	expectJSON := `{
   782    "Name": "Bob",
   783    "Birthday": "1999-03-13T05:57:11.000001901-07:00",
   784    "Age": 24,
   785    "EmployeID": 7,
   786    "Avatar": "https://tse4-mm.cn.bing.net/th/id/OIP-C.SAy__OKoxrIqrXWAb7Tj1wHaEC?pid=ImgDet\u0026rs=1",
   787    "Image": "XxsrQgAV0g==",
   788    "Attr": {
   789      "Attrs": [
   790        "hello",
   791        "world"
   792      ]
   793    },
   794    "Valid": true,
   795    "Deleted": false
   796  }`
   797  
   798  	cases := []evendeep.TestCase{
   799  		evendeep.NewTestCase(
   800  			"struct -> slice []obj",
   801  			src, &slice1, &[]evendeep.User{expect1},
   802  			[]evendeep.Opt{evendeep.WithMergeStrategyOpt, evendeep.WithAutoExpandStructOpt, evendeep.WithAutoNewForStructFieldOpt},
   803  			nil,
   804  		),
   805  
   806  		evendeep.NewTestCase(
   807  			"struct -> string",
   808  			src, &str, &expectJSON,
   809  			[]evendeep.Opt{
   810  				evendeep.WithStringMarshaller(func(v interface{}) ([]byte, error) {
   811  					return json.MarshalIndent(v, "", "  ")
   812  				}),
   813  				evendeep.WithMergeStrategyOpt,
   814  				evendeep.WithAutoExpandStructOpt,
   815  				evendeep.WithAutoNewForStructFieldOpt},
   816  			nil,
   817  		),
   818  
   819  		evendeep.NewTestCase(
   820  			"struct -> map[string]Any",
   821  			src, &map1, &expect3,
   822  			[]evendeep.Opt{evendeep.WithMergeStrategyOpt, evendeep.WithAutoExpandStructOpt, evendeep.WithAutoNewForStructFieldOpt},
   823  			nil,
   824  		),
   825  
   826  		evendeep.NewTestCase(
   827  			"struct -> slice []obj",
   828  			src, &slice1, &[]evendeep.User{expect1},
   829  			[]evendeep.Opt{evendeep.WithMergeStrategyOpt, evendeep.WithAutoExpandStructOpt, evendeep.WithAutoNewForStructFieldOpt},
   830  			nil,
   831  		),
   832  		evendeep.NewTestCase(
   833  			"struct -> slice []*obj",
   834  			src, &slice2, &[]*evendeep.User{&expect1},
   835  			[]evendeep.Opt{evendeep.WithMergeStrategyOpt, evendeep.WithAutoExpandStructOpt, evendeep.WithAutoNewForStructFieldOpt},
   836  			nil,
   837  		),
   838  	}
   839  
   840  	for ix, tc := range cases {
   841  		if !t.Run(fmt.Sprintf("%3d. %s", ix, tc.Description), evendeep.DefaultDeepCopyTestRunner(ix, tc)) {
   842  			break
   843  		}
   844  	}
   845  }
   846  
   847  func TestStructWithSourceExtractor(t *testing.T) {
   848  	type MyValue map[string]typ.Any
   849  	type MyKey string
   850  	const key MyKey = "data-in-sess"
   851  	c := context.WithValue(context.TODO(), key, MyValue{
   852  		"A": 12,
   853  	})
   854  
   855  	tgt := struct {
   856  		A int
   857  	}{}
   858  
   859  	err := evendeep.New().CopyTo(c, &tgt,
   860  		evendeep.WithSourceValueExtractor(func(targetName string) typ.Any {
   861  			if m, ok := c.Value(key).(MyValue); ok {
   862  				return m[targetName]
   863  			}
   864  			return nil
   865  		}),
   866  	)
   867  
   868  	if tgt.A != 12 || err != nil {
   869  		t.Fatalf(`err: %+v`, err)
   870  	}
   871  }
   872  
   873  func TestStructWithTargetSetter_struct2struct(t *testing.T) {
   874  	type srcS struct {
   875  		A int64
   876  		B bool
   877  		C string
   878  		D float64
   879  	}
   880  	type dstS struct {
   881  		MoA int32
   882  		MoB bool
   883  		MoC string
   884  		MoZ string
   885  	}
   886  	src := &srcS{
   887  		A: 5,
   888  		B: true,
   889  		C: helloString,
   890  	}
   891  	tgt := &dstS{
   892  		MoA: 1,
   893  		MoB: false,
   894  		MoZ: worldString,
   895  	}
   896  
   897  	setStructByName := func(s reflect.Value, fld string, val reflect.Value) {
   898  		var f = s.FieldByName(fld)
   899  		if f.IsValid() {
   900  			if val.Type().ConvertibleTo(f.Type()) {
   901  				f.Set(val.Convert(f.Type()))
   902  			} else {
   903  				f.Set(val)
   904  			}
   905  		}
   906  	}
   907  	err := evendeep.New().CopyTo(src, &tgt,
   908  		evendeep.WithTargetValueSetter(func(value *reflect.Value, sourceNames ...string) (err error) {
   909  			if value != nil {
   910  				name := "Mo" + strings.Join(sourceNames, ".")
   911  				setStructByName(reflect.ValueOf(tgt).Elem(), name, *value)
   912  			}
   913  			return // ErrShouldFallback to call the evendeep standard processing
   914  		}),
   915  	)
   916  
   917  	if err != nil || tgt.MoA != 5 || !tgt.MoB || tgt.MoC != helloString || tgt.MoZ != worldString {
   918  		t.Errorf("err: %v, tgt: %v", err, tgt)
   919  		t.FailNow()
   920  	} else {
   921  		t.Logf("new map got: %v", tgt)
   922  	}
   923  }
   924  
   925  func TestStructWithTargetSetter_struct2map(t *testing.T) {
   926  	type srcS struct {
   927  		A int
   928  		B bool
   929  		C string
   930  	}
   931  
   932  	src := &srcS{
   933  		A: 5,
   934  		B: true,
   935  		C: helloString,
   936  	}
   937  	tgt := map[string]typ.Any{
   938  		"Z": worldString,
   939  	}
   940  
   941  	err := evendeep.New().CopyTo(src, &tgt,
   942  		evendeep.WithTargetValueSetter(func(value *reflect.Value, sourceNames ...string) (err error) {
   943  			if value != nil {
   944  				name := "Mo" + strings.Join(sourceNames, ".")
   945  				tgt[name] = value.Interface()
   946  			}
   947  			return // ErrShouldFallback to call the evendeep standard processing
   948  		}),
   949  	)
   950  
   951  	if err != nil || tgt["MoA"] != 5 || tgt["MoB"] != true || tgt["MoC"] != helloString || tgt["Z"] != worldString {
   952  		t.Errorf("err: %v, tgt: %v", err, tgt)
   953  		t.FailNow()
   954  	} else if _, ok := tgt["A"]; ok {
   955  		t.Errorf("err: key 'A' shouldn't exists, tgt: %v", tgt)
   956  		t.FailNow()
   957  	} else {
   958  		t.Logf("new map got: %v", tgt)
   959  	}
   960  }
   961  
   962  func TestStructWithTargetSetter_map2struct(t *testing.T) {
   963  	type dstS struct {
   964  		MoA int32
   965  		MoB bool
   966  		MoC string
   967  		MoZ string
   968  	}
   969  	src := map[string]typ.Any{
   970  		"A": 5,
   971  		"B": true,
   972  		"C": helloString,
   973  	}
   974  	tgt := &dstS{
   975  		MoA: 1,
   976  		MoB: false,
   977  		MoZ: worldString,
   978  	}
   979  
   980  	setStructByName := func(s reflect.Value, fldName string, value reflect.Value) {
   981  		var f = s.FieldByName(fldName)
   982  		if f.IsValid() {
   983  			if value.Type().ConvertibleTo(f.Type()) {
   984  				dbglog.Log("struct.%q <- %v", fldName, tool.Valfmt(&value))
   985  				f.Set(value.Convert(f.Type()))
   986  			} else {
   987  				dbglog.Log("struct.%q <- %v", fldName, tool.Valfmt(&value))
   988  				f.Set(value)
   989  			}
   990  		}
   991  	}
   992  	err := evendeep.New().CopyTo(src, &tgt,
   993  		evendeep.WithTargetValueSetter(func(value *reflect.Value, sourceNames ...string) (err error) {
   994  			if value != nil {
   995  				name := "Mo" + strings.Join(sourceNames, ".")
   996  				setStructByName(reflect.ValueOf(tgt).Elem(), name, *value)
   997  				dbglog.Log("struct.%q <- %v", name, tool.Valfmt(value))
   998  			}
   999  			return // ErrShouldFallback to call the evendeep standard processing
  1000  		}),
  1001  	)
  1002  
  1003  	if err != nil || tgt.MoA != 5 || !tgt.MoB || tgt.MoC != helloString || tgt.MoZ != worldString {
  1004  		t.Errorf("err: %v, tgt: %v", err, tgt)
  1005  		t.FailNow()
  1006  	} else {
  1007  		t.Logf("new map got: %v", tgt)
  1008  	}
  1009  }
  1010  
  1011  func TestStructWithTargetSetter_map2map(t *testing.T) {
  1012  	src := map[string]typ.Any{
  1013  		"A": 5,
  1014  		"B": true,
  1015  		"C": helloString,
  1016  	}
  1017  	tgt := map[string]typ.Any{
  1018  		"Z": worldString,
  1019  	}
  1020  
  1021  	err := evendeep.New().CopyTo(src, &tgt,
  1022  		evendeep.WithTargetValueSetter(func(value *reflect.Value, sourceNames ...string) (err error) {
  1023  			if value != nil {
  1024  				name := "Mo" + strings.Join(sourceNames, ".")
  1025  				tgt[name] = value.Interface()
  1026  			}
  1027  			return // ErrShouldFallback to call the evendeep standard processing
  1028  		}),
  1029  	)
  1030  
  1031  	if err != nil || tgt["MoA"] != 5 || tgt["MoB"] != true || tgt["MoC"] != helloString || tgt["Z"] != worldString {
  1032  		t.Errorf("err: %v, tgt: %v", err, tgt)
  1033  		t.FailNow()
  1034  	} else if _, ok := tgt["A"]; ok {
  1035  		t.Errorf("err: key 'A' shouldn't exists, tgt: %v", tgt)
  1036  		t.FailNow()
  1037  	} else {
  1038  		t.Logf("new map got: %v", tgt)
  1039  	}
  1040  }
  1041  
  1042  func TestStructWithSSS(t *testing.T) {
  1043  	//
  1044  }
  1045  
  1046  type aS struct {
  1047  	A int
  1048  	b bool
  1049  	C string
  1050  }
  1051  
  1052  func (s aS) B() bool { return s.b }
  1053  
  1054  func TestStructWithCmsByNameStrategy(t *testing.T) {
  1055  	type bS struct {
  1056  		Z int
  1057  		B bool
  1058  		C string
  1059  	}
  1060  
  1061  	src := &aS{A: 6, b: true, C: helloString}
  1062  	var tgt = bS{Z: 1}
  1063  
  1064  	// use ByName strategy,
  1065  	// use copyFunctionResultsToTarget
  1066  	err := evendeep.New().CopyTo(src, &tgt, evendeep.WithByNameStrategyOpt)
  1067  
  1068  	if tgt.Z != 1 || !tgt.B || tgt.C != helloString || err != nil {
  1069  		t.Fatalf("BAD COPY, tgt: %+v", tgt)
  1070  	}
  1071  }
  1072  
  1073  func TestStructWithNameConversions(t *testing.T) {
  1074  	type srcS struct {
  1075  		A int    `copy:"A1"`
  1076  		B bool   `copy:"B1,std"`
  1077  		C string `copy:"C1,"`
  1078  	}
  1079  
  1080  	type dstS struct {
  1081  		A1 int
  1082  		B1 bool
  1083  		C1 string
  1084  	}
  1085  
  1086  	src := &srcS{A: 6, B: true, C: helloString}
  1087  	var tgt = dstS{A1: 1}
  1088  
  1089  	// use ByName strategy,
  1090  	err := evendeep.New().CopyTo(src, &tgt, evendeep.WithByNameStrategyOpt)
  1091  
  1092  	if tgt.A1 != 6 || !tgt.B1 || tgt.C1 != helloString || err != nil {
  1093  		t.Fatalf("BAD COPY, tgt: %+v", tgt)
  1094  	}
  1095  }
  1096  
  1097  func TestStructWithNameConverter(t *testing.T) {
  1098  	// TODO enable name converter for each field, and TestStructWithNameConverter()
  1099  }
  1100  
  1101  func TestSliceSimple(t *testing.T) {
  1102  
  1103  	tgt := []float32{3.1, 4.5, 9.67}
  1104  	itgt := []int{13, 5}
  1105  
  1106  	cases := []evendeep.TestCase{
  1107  		evendeep.NewTestCase(
  1108  			"slice (float64 -> float32)",
  1109  			[]float64{9.123, 5.2}, &tgt, &[]float32{3.1, 4.5, 9.67, 9.123, 5.2},
  1110  			[]evendeep.Opt{evendeep.WithMergeStrategyOpt},
  1111  			nil,
  1112  		),
  1113  		evendeep.NewTestCase(
  1114  			"slice (uint64 -> int)",
  1115  			[]uint64{9, 5}, &itgt, &[]int{13, 5, 9},
  1116  			[]evendeep.Opt{evendeep.WithMergeStrategyOpt},
  1117  			nil,
  1118  		),
  1119  	}
  1120  
  1121  	for ix, tc := range cases {
  1122  		if !t.Run(fmt.Sprintf("%3d. %s", ix, tc.Description), evendeep.DefaultDeepCopyTestRunner(ix, tc)) {
  1123  			break
  1124  		}
  1125  	}
  1126  }
  1127  
  1128  func TestSliceTypeConvert(t *testing.T) {
  1129  
  1130  	// tgt := []float32{3.1, 4.5, 9.67}
  1131  	// itgt := []int{13, 5}
  1132  	stgt := []string{"-", "2.718280076980591"}
  1133  	stgt2 := []string{"-", "2.718280076980591", "9", "5", "3.1415927410125732"}
  1134  	itgt := []int{17}
  1135  	itgt2 := []int{13}
  1136  
  1137  	// itgt2 := []int{17}
  1138  	// ftgt2 := []float64{17}
  1139  
  1140  	cases := []evendeep.TestCase{
  1141  		evendeep.NewTestCase(
  1142  			"slice (uint64 -> string)",
  1143  			[]uint64{9, 5}, &stgt,
  1144  			&[]string{"-", "2.718280076980591", "9", "5"},
  1145  			[]evendeep.Opt{evendeep.WithMergeStrategyOpt},
  1146  			nil,
  1147  		),
  1148  		evendeep.NewTestCase(
  1149  			"slice (float32 -> string)",
  1150  			[]float32{math.Pi, 2.71828}, &stgt,
  1151  			// NOTE that stgt kept the new result in last subtest
  1152  			&stgt2,
  1153  			[]evendeep.Opt{evendeep.WithMergeStrategyOpt},
  1154  			nil,
  1155  		),
  1156  		evendeep.NewTestCase(
  1157  			"slice (string(with floats) -> int)",
  1158  			stgt2, &itgt,
  1159  			&[]int{17, 3, 9, 5},
  1160  			[]evendeep.Opt{evendeep.WithMergeStrategyOpt},
  1161  			nil,
  1162  		),
  1163  		evendeep.NewTestCase(
  1164  			"slice (string(with floats) -> int)",
  1165  			[]string{"-", "9.718280076980591", "9", "5", "3.1415927410125732"},
  1166  			&itgt2,
  1167  			&[]int{13, 10, 9, 5, 3},
  1168  			[]evendeep.Opt{evendeep.WithMergeStrategyOpt},
  1169  			nil,
  1170  		),
  1171  
  1172  		// needs complexToAnythingConverter
  1173  
  1174  		// evendeep.NewTestCase(
  1175  		//	"slice (complex -> float64)",
  1176  		//	[]complex64{math.Pi + 3i, 2.71828 + 4.19i},
  1177  		//	&ftgt2,
  1178  		//	// NOTE that stgt kept the new result in last subtest
  1179  		//	&[]float64{2.718280076980591, 17, 3.1415927410125732},
  1180  		//	[]evendeep.Opt{evendeep.WithMergeStrategy},
  1181  		//	nil,
  1182  		// ),
  1183  		// evendeep.NewTestCase(
  1184  		//	"slice (complex -> int)",
  1185  		//	[]complex64{math.Pi + 3i, 2.71828 + 4.19i},
  1186  		//	&itgt2,
  1187  		//	// NOTE that stgt kept the new result in last subtest
  1188  		//	&[]float64{3, 17},
  1189  		//	[]evendeep.Opt{evendeep.WithMergeStrategy},
  1190  		//	nil,
  1191  		// ),
  1192  	}
  1193  
  1194  	for ix, tc := range cases {
  1195  		if !t.Run(fmt.Sprintf("%3d. %s", ix, tc.Description), evendeep.DefaultDeepCopyTestRunner(ix, tc)) {
  1196  			break
  1197  		}
  1198  	}
  1199  }
  1200  
  1201  func TestMapSimple(t *testing.T) {
  1202  
  1203  	src := map[int64]float64{7: 0, 3: 7.18}
  1204  	tgt := map[int]float32{1: 3.1, 2: 4.5, 3: 9.67}
  1205  	exp := map[int]float32{1: 3.1, 2: 4.5, 3: 7.18, 7: 0}
  1206  
  1207  	cases := []evendeep.TestCase{
  1208  		evendeep.NewTestCase(
  1209  			"map (map[int64]float64 -> map[int]float32)",
  1210  			src, &tgt, &exp,
  1211  			[]evendeep.Opt{evendeep.WithMergeStrategyOpt, evendeep.WithAutoExpandStructOpt},
  1212  			nil,
  1213  		),
  1214  		// evendeep.NewTestCase(
  1215  		//	"slice (uint64 -> int)",
  1216  		//	[]uint64{9, 5}, &itgt, &[]int{13, 5, 9},
  1217  		//	[]evendeep.Opt{evendeep.WithMergeStrategy},
  1218  		//	nil,
  1219  		// ),
  1220  	}
  1221  
  1222  	for ix, tc := range cases {
  1223  		if !t.Run(fmt.Sprintf("%3d. %s", ix, tc.Description), evendeep.DefaultDeepCopyTestRunner(ix, tc)) {
  1224  			break
  1225  		}
  1226  	}
  1227  }
  1228  
  1229  func TestMapAndStruct(t *testing.T) {
  1230  
  1231  	timeZone, _ := time.LoadLocation("America/Phoenix")
  1232  	timeZone2, _ := time.LoadLocation("Asia/Chongqing")
  1233  	tm := time.Date(1999, 3, 13, 5, 57, 11, 1901, timeZone)
  1234  	tm2 := time.Date(2003, 9, 1, 23, 59, 59, 3579, timeZone)
  1235  	tm1 := time.Date(2021, 2, 28, 13, 1, 23, 800, timeZone2)
  1236  	tm3 := time.Date(2015, 1, 29, 19, 31, 37, 77, timeZone2)
  1237  
  1238  	src := evendeep.Employee2{
  1239  		Base: evendeep.Base{
  1240  			Name:      "Bob",
  1241  			Birthday:  &tm,
  1242  			Age:       24,
  1243  			EmployeID: 7,
  1244  		},
  1245  		Avatar: "https://tse4-mm.cn.bing.net/th/id/OIP-C.SAy__OKoxrIqrXWAb7Tj1wHaEC?pid=ImgDet&rs=1",
  1246  		Image:  []byte{95, 27, 43, 66, 0, 21, 210},
  1247  		Attr:   &evendeep.Attr{Attrs: []string{helloString, worldString}},
  1248  		Valid:  true,
  1249  	}
  1250  
  1251  	src3 := evendeep.Employee2{
  1252  		Base: evendeep.Base{
  1253  			Name:      "Ellen",
  1254  			Birthday:  &tm2,
  1255  			Age:       55,
  1256  			EmployeID: 9,
  1257  		},
  1258  		Avatar:  "https://placeholder.com/225x168",
  1259  		Image:   []byte{181, 130, 23},
  1260  		Attr:    &evendeep.Attr{Attrs: []string{"god", "bless"}},
  1261  		Valid:   false,
  1262  		Deleted: true,
  1263  	}
  1264  
  1265  	tgt := evendeep.User{
  1266  		Name:      "Mathews",
  1267  		Birthday:  &tm3,
  1268  		Age:       3,
  1269  		EmployeID: 92,
  1270  		Attr:      &evendeep.Attr{Attrs: []string{"get"}},
  1271  		Deleted:   false,
  1272  	}
  1273  
  1274  	tgt2 := evendeep.User{
  1275  		Name:      "Frank",
  1276  		Birthday:  &tm2,
  1277  		Age:       18,
  1278  		EmployeID: 9,
  1279  		Attr:      &evendeep.Attr{Attrs: []string{"baby"}},
  1280  	}
  1281  
  1282  	tgt3 := evendeep.User{
  1283  		Name:      "Zeuth",
  1284  		Birthday:  &tm1,
  1285  		Age:       31,
  1286  		EmployeID: 17,
  1287  		Image:     []byte{181, 130, 29},
  1288  		Attr:      &evendeep.Attr{Attrs: []string{"you"}},
  1289  	}
  1290  
  1291  	expect1 := evendeep.User{
  1292  		Name:      "Bob",
  1293  		Birthday:  &tm,
  1294  		Age:       24,
  1295  		EmployeID: 7,
  1296  		Avatar:    "https://tse4-mm.cn.bing.net/th/id/OIP-C.SAy__OKoxrIqrXWAb7Tj1wHaEC?pid=ImgDet&rs=1",
  1297  		Image:     []byte{95, 27, 43, 66, 0, 21, 210},
  1298  		Attr:      &evendeep.Attr{Attrs: []string{"get", helloString, worldString}},
  1299  		Valid:     true,
  1300  	}
  1301  
  1302  	expect3 := evendeep.User{
  1303  		Name:      "Ellen",
  1304  		Birthday:  &tm2,
  1305  		Age:       55,
  1306  		EmployeID: 9,
  1307  		Avatar:    "https://placeholder.com/225x168",
  1308  		Image:     []byte{181, 130, 29, 23},
  1309  		Attr:      &evendeep.Attr{Attrs: []string{"you", "god", "bless"}},
  1310  		Deleted:   true,
  1311  	}
  1312  
  1313  	srcmap := map[int64]*evendeep.Employee2{
  1314  		7: &src,
  1315  		3: &src3,
  1316  	}
  1317  	tgtmap := map[float32]*evendeep.User{
  1318  		7: &tgt,
  1319  		2: &tgt2,
  1320  		3: &tgt3,
  1321  	}
  1322  	expmap := map[float32]*evendeep.User{
  1323  		7: &expect1,
  1324  		2: &tgt2,
  1325  		3: &expect3,
  1326  	}
  1327  
  1328  	cases := []evendeep.TestCase{
  1329  		evendeep.NewTestCase(
  1330  			"map (map[int64]Employee2 -> map[int]User)",
  1331  			srcmap, &tgtmap, &expmap,
  1332  			[]evendeep.Opt{
  1333  				evendeep.WithMergeStrategyOpt,
  1334  				evendeep.WithAutoExpandStructOpt,
  1335  				evendeep.WithAutoNewForStructFieldOpt,
  1336  			},
  1337  			nil,
  1338  		),
  1339  		// evendeep.NewTestCase(
  1340  		//	"slice (uint64 -> int)",
  1341  		//	[]uint64{9, 5}, &itgt, &[]int{13, 5, 9},
  1342  		//	[]evendeep.Opt{evendeep.WithMergeStrategy},
  1343  		//	nil,
  1344  		// ),
  1345  	}
  1346  
  1347  	for ix, tc := range cases {
  1348  		if !t.Run(fmt.Sprintf("%3d. %s", ix, tc.Description), evendeep.DefaultDeepCopyTestRunner(ix, tc)) {
  1349  			break
  1350  		}
  1351  	}
  1352  }
  1353  
  1354  func TestMapToString(t *testing.T) {
  1355  
  1356  	timeZone, _ := time.LoadLocation("America/Phoenix")
  1357  	tm := time.Date(1999, 3, 13, 5, 57, 11, 1901, timeZone)
  1358  	// timeZone2, _ := time.LoadLocation("Asia/Chongqing")
  1359  	// tm1 := time.Date(2021, 2, 28, 13, 1, 23, 800, timeZone2)
  1360  	// tm2 := time.Date(2003, 9, 1, 23, 59, 59, 3579, timeZone)
  1361  	// tm3 := time.Date(2015, 1, 29, 19, 31, 37, 77, timeZone2)
  1362  
  1363  	expect2 := evendeep.User{
  1364  		Name:      "Bob",
  1365  		Birthday:  &tm,
  1366  		Age:       24,
  1367  		EmployeID: 7,
  1368  		Avatar:    "https://tse4-mm.cn.bing.net/th/id/OIP-C.SAy__OKoxrIqrXWAb7Tj1wHaEC?pid=ImgDet&rs=1",
  1369  		Image:     []byte{95, 27, 43, 66, 0, 21, 210},
  1370  		Attr:      &evendeep.Attr{Attrs: []string{helloString, worldString}},
  1371  		Valid:     true,
  1372  	}
  1373  
  1374  	expect3 := evendeep.Employee2{
  1375  		Base: evendeep.Base{
  1376  			Name:      "Bob",
  1377  			Birthday:  &tm,
  1378  			Age:       24,
  1379  			EmployeID: 7,
  1380  		},
  1381  		Avatar: "https://tse4-mm.cn.bing.net/th/id/OIP-C.SAy__OKoxrIqrXWAb7Tj1wHaEC?pid=ImgDet&rs=1",
  1382  		Image:  []byte{95, 27, 43, 66, 0, 21, 210},
  1383  		Attr:   &evendeep.Attr{Attrs: []string{helloString, worldString}},
  1384  		Valid:  true,
  1385  	}
  1386  
  1387  	var s2 evendeep.User
  1388  	var s3 evendeep.Employee2
  1389  	var str1 string
  1390  
  1391  	// var map1 = make(map[string]interface{})
  1392  	var map1 = map[string]interface{}{
  1393  		"Name":      "Bob",
  1394  		"Birthday":  tm,
  1395  		"Age":       24,
  1396  		"EmployeID": int64(7),
  1397  		"Avatar":    "https://tse4-mm.cn.bing.net/th/id/OIP-C.SAy__OKoxrIqrXWAb7Tj1wHaEC?pid=ImgDet&rs=1",
  1398  		"Image":     []byte{95, 27, 43, 66, 0, 21, 210},
  1399  		"Attr":      map[string]interface{}{"Attrs": []string{helloString, worldString}},
  1400  		"Valid":     true,
  1401  		"Deleted":   false,
  1402  	}
  1403  
  1404  	expect1 := `{
  1405    "Age": 24,
  1406    "Attr": {
  1407      "Attrs": [
  1408        "hello",
  1409        "world"
  1410      ]
  1411    },
  1412    "Avatar": "https://tse4-mm.cn.bing.net/th/id/OIP-C.SAy__OKoxrIqrXWAb7Tj1wHaEC?pid=ImgDet\u0026rs=1",
  1413    "Birthday": "1999-03-13T05:57:11.000001901-07:00",
  1414    "Deleted": false,
  1415    "EmployeID": 7,
  1416    "Image": "XxsrQgAV0g==",
  1417    "Name": "Bob",
  1418    "Valid": true
  1419  }`
  1420  
  1421  	cases := []evendeep.TestCase{
  1422  		evendeep.NewTestCase(
  1423  			"map -> string [json]",
  1424  			map1, &str1, &expect1,
  1425  			[]evendeep.Opt{
  1426  				evendeep.WithStringMarshaller(func(v interface{}) ([]byte, error) {
  1427  					return json.MarshalIndent(v, "", "  ")
  1428  				}),
  1429  				evendeep.WithMergeStrategyOpt,
  1430  				evendeep.WithAutoExpandStructOpt},
  1431  			nil,
  1432  		),
  1433  
  1434  		evendeep.NewTestCase(
  1435  			"map -> struct User",
  1436  			map1, &s2, &expect2,
  1437  			[]evendeep.Opt{evendeep.WithMergeStrategyOpt, evendeep.WithAutoExpandStructOpt},
  1438  			nil,
  1439  		),
  1440  		evendeep.NewTestCase(
  1441  			"map -> struct Employee2",
  1442  			map1, &s3, &expect3,
  1443  			[]evendeep.Opt{evendeep.WithMergeStrategyOpt, evendeep.WithAutoExpandStructOpt},
  1444  			nil,
  1445  		),
  1446  	}
  1447  
  1448  	for ix, tc := range cases {
  1449  		if !t.Run(fmt.Sprintf("%3d. %s", ix, tc.Description), evendeep.DefaultDeepCopyTestRunner(ix, tc)) {
  1450  			break
  1451  		}
  1452  	}
  1453  }
  1454  
  1455  func testIfBadCopy(t *testing.T, src, tgt, result interface{}, title string, notFailed ...interface{}) {
  1456  
  1457  	t.Logf("checking result ...")
  1458  
  1459  	// if diff := deep.Equal(src, tgt); diff == nil {
  1460  	//	return
  1461  	// } else {
  1462  	//	t.Fatalf("testIfBadCopy - BAD COPY (%v):\n  SRC: %+v\n  TGT: %+v\n\n DIFF: \n%v", title, src, tgt, diff)
  1463  	// }
  1464  
  1465  	// dd := deepdiff.New()
  1466  	// diff, err := dd.Diff(context.Background(), src, tgt)
  1467  	// if err != nil {
  1468  	//	return
  1469  	// }
  1470  	// if diff.Len() > 0 {
  1471  	//	t.Fatalf("testIfBadCopy - BAD COPY (%v):\n SRC: %+v\n TGT: %+v\n\n DIFF: \n%v", title, src, tgt, diff)
  1472  	// } else {
  1473  	//	return
  1474  	// }
  1475  
  1476  	dif, equal := diff.New(src, tgt)
  1477  	if equal {
  1478  		return
  1479  	}
  1480  
  1481  	fmt.Println(dif)
  1482  	err := errors.New("diff.PrettyDiff identified its not equal:\ndifferent:\n%v", dif)
  1483  
  1484  	for _, b := range notFailed {
  1485  		if yes, ok := b.(bool); yes && ok {
  1486  			return
  1487  		}
  1488  	}
  1489  
  1490  	t.Fatal(err)
  1491  
  1492  	// if !reflect.DeepEqual(src, tgt) {
  1493  	//
  1494  	//	var b1, b2 []byte
  1495  	//	var err error
  1496  	//	if b1, err = json.MarshalIndent(src, "", "  "); err == nil {
  1497  	//		if b2, err = json.MarshalIndent(src, "", "  "); err == nil {
  1498  	//			if string(b1) == string(b2) {
  1499  	//				return
  1500  	//			}
  1501  	//			t.Logf("testIfBadCopy - src: %v\ntgt: %v\n", string(b1), string(b2))
  1502  	//		}
  1503  	//	}
  1504  	//	if err != nil {
  1505  	//		t.Logf("testIfBadCopy - json marshal not ok (just a warning): %v", err)
  1506  	//
  1507  	//		//if b1, err = yaml.Marshal(src); err == nil {
  1508  	//		//	if b2, err = yaml.Marshal(src); err == nil {
  1509  	//		//		if string(b1) == string(b2) {
  1510  	//		//			return
  1511  	//		//		}
  1512  	//		//	}
  1513  	//		//}
  1514  	//
  1515  	//		//gob.Register(X1{})
  1516  	//		//
  1517  	//		//buf1 := new(bytes.Buffer)
  1518  	//		//enc1 := gob.NewEncoder(buf1)
  1519  	//		//if err = enc1.Encode(&src); err != nil {
  1520  	//		//	t.Fatal(err)
  1521  	//		//}
  1522  	//		//
  1523  	//		//buf2 := new(bytes.Buffer)
  1524  	//		//enc2 := gob.NewEncoder(buf2)
  1525  	//		//if err = enc2.Encode(&tgt); err != nil {
  1526  	//		//	t.Fatal(err)
  1527  	//		//}
  1528  	//		//
  1529  	//		//s1, s2 := buf1.String(), buf2.String()
  1530  	//		//if s1 == s2 {
  1531  	//		//	return
  1532  	//		//}
  1533  	//	}
  1534  	//
  1535  	//	for _, b := range notFailed {
  1536  	//		if yes, ok := b.(bool); yes && ok {
  1537  	//			return
  1538  	//		}
  1539  	//	}
  1540  	//
  1541  	//	t.Fatalf("testIfBadCopy - BAD COPY (%v):\n SRC: %+v\n TGT: %+v\n RES: %v", title, src, tgt, result)
  1542  	// }
  1543  }
  1544  
  1545  func TestExample1(t *testing.T) {
  1546  	timeZone, _ := time.LoadLocation("America/Phoenix")
  1547  	tm := time.Date(1999, 3, 13, 5, 57, 11, 1901, timeZone)
  1548  	var src = evendeep.Employee2{
  1549  		Base: evendeep.Base{
  1550  			Name:      "Bob",
  1551  			Birthday:  &tm,
  1552  			Age:       24,
  1553  			EmployeID: 7,
  1554  		},
  1555  		Avatar: "https://tse4-mm.cn.bing.net/th/id/OIP-C.SAy__OKoxrIqrXWAb7Tj1wHaEC?pid=ImgDet&rs=1",
  1556  		Image:  []byte{95, 27, 43, 66, 0, 21, 210},
  1557  		Attr:   &evendeep.Attr{Attrs: []string{helloString, worldString}},
  1558  		Valid:  true,
  1559  	}
  1560  	var dst evendeep.User
  1561  
  1562  	// direct way but no error report: evendeep.DeepCopy(src, &dst)
  1563  	c := evendeep.New()
  1564  	if err := c.CopyTo(src, &dst); err != nil {
  1565  		t.Fatal(err)
  1566  	}
  1567  	if !reflect.DeepEqual(dst, evendeep.User{
  1568  		Name:      "Bob",
  1569  		Birthday:  &tm,
  1570  		Age:       24,
  1571  		EmployeID: 7,
  1572  		Avatar:    "https://tse4-mm.cn.bing.net/th/id/OIP-C.SAy__OKoxrIqrXWAb7Tj1wHaEC?pid=ImgDet&rs=1",
  1573  		Image:     []byte{95, 27, 43, 66, 0, 21, 210},
  1574  		Attr:      &evendeep.Attr{Attrs: []string{helloString, worldString}},
  1575  		Valid:     true,
  1576  	}) {
  1577  		t.Fatalf("bad, got %v", dst)
  1578  	}
  1579  }
  1580  
  1581  type MyType struct {
  1582  	I int
  1583  }
  1584  
  1585  type MyTypeToStringConverter struct{}
  1586  
  1587  // Uncomment this line if you wanna take a ValueCopier implementation too:
  1588  // func (c *MyTypeToStringConverter) CopyTo(ctx *evendeep.ValueConverterContext, source, target reflect.Value) (err error) { return }
  1589  
  1590  func (c *MyTypeToStringConverter) Transform(ctx *evendeep.ValueConverterContext, source reflect.Value, targetType reflect.Type) (target reflect.Value, err error) {
  1591  	if source.IsValid() && targetType.Kind() == reflect.String {
  1592  		var str string
  1593  		if str, err = evendeep.FallbackToBuiltinStringMarshalling(source); err == nil {
  1594  			target = reflect.ValueOf(str)
  1595  		}
  1596  	}
  1597  	return
  1598  }
  1599  
  1600  func (c *MyTypeToStringConverter) Match(params *evendeep.Params, source, target reflect.Type) (ctx *evendeep.ValueConverterContext, yes bool) {
  1601  	sn, sp := source.Name(), source.PkgPath()
  1602  	sk, tk := source.Kind(), target.Kind()
  1603  	if yes = sk == reflect.Struct && tk == reflect.String &&
  1604  		sn == "MyType" && sp == "github.com/hedzr/evendeep_test"; yes {
  1605  		ctx = &evendeep.ValueConverterContext{Params: params}
  1606  	}
  1607  	return
  1608  }
  1609  
  1610  func TestExample2(t *testing.T) {
  1611  	var myData = MyType{I: 9}
  1612  	var dst string
  1613  	c := evendeep.NewForTest()
  1614  	_ = c.CopyTo(myData, &dst,
  1615  		evendeep.WithValueConverters(&MyTypeToStringConverter{}),
  1616  		evendeep.WithStringMarshaller(json.Marshal),
  1617  	)
  1618  	if dst != `{"I":9}` {
  1619  		t.Fatalf("bad 1, got %v", dst)
  1620  	}
  1621  
  1622  	// a stub call for coverage
  1623  	evendeep.RegisterDefaultCopiers()
  1624  
  1625  	var dst1 string
  1626  	evendeep.RegisterDefaultConverters(&MyTypeToStringConverter{})
  1627  	c = evendeep.NewForTest()
  1628  	_ = c.CopyTo(myData, &dst1,
  1629  		evendeep.WithStringMarshaller(json.Marshal),
  1630  	)
  1631  	if dst1 != `{"I":9}` {
  1632  		t.Fatalf("bad 2, got %v", dst)
  1633  	}
  1634  
  1635  }
  1636  
  1637  func TestExample3(t *testing.T) {
  1638  	timeZone, _ := time.LoadLocation("America/Phoenix")
  1639  	tm := time.Date(1999, 3, 13, 5, 57, 11, 1901, timeZone)
  1640  	var originRec = evendeep.User{
  1641  		Name:      "Bob",
  1642  		Birthday:  &tm,
  1643  		Age:       24,
  1644  		EmployeID: 7,
  1645  		Avatar:    "https://tse4-mm.cn.bing.net/th/id/OIP-C.SAy__OKoxrIqrXWAb7Tj1wHaEC?pid=ImgDet&rs=1",
  1646  		Image:     []byte{95, 27, 43, 66, 0, 21, 210},
  1647  		Attr:      &evendeep.Attr{Attrs: []string{helloString, worldString}},
  1648  		Valid:     true,
  1649  	}
  1650  	var newRecord evendeep.User
  1651  	var t0 = time.Unix(0, 0)
  1652  	var expectRec = evendeep.User{Name: "Barbara", Birthday: &t0, Attr: &evendeep.Attr{}}
  1653  
  1654  	_ = evendeep.New().CopyTo(originRec, &newRecord)
  1655  	t.Logf("newRecord: %v", newRecord)
  1656  
  1657  	newRecord.Name = "Barbara"
  1658  	_ = evendeep.New().CopyTo(originRec, &newRecord, evendeep.WithORMDiffOpt)
  1659  	if len(newRecord.Attr.Attrs) == len(expectRec.Attr.Attrs) {
  1660  		newRecord.Attr = expectRec.Attr
  1661  	}
  1662  	if newRecord.Birthday == nil || newRecord.Birthday.Nanosecond() == 0 {
  1663  		newRecord.Birthday = &t0
  1664  	}
  1665  	if !reflect.DeepEqual(newRecord, expectRec) {
  1666  		t.Fatalf("bad, got %v | %v", newRecord, newRecord.Birthday.Nanosecond())
  1667  	}
  1668  	t.Logf("newRecord: %v", newRecord)
  1669  
  1670  }
  1671  
  1672  func TestExample4(t *testing.T) {
  1673  	timeZone, _ := time.LoadLocation("America/Phoenix")
  1674  	attr := &evendeep.Attr{Attrs: []string{helloString, worldString}}
  1675  	tm := time.Date(1999, 3, 13, 5, 57, 11, 1901, timeZone)
  1676  	var originRec = evendeep.User{
  1677  		Name:      "Bob",
  1678  		Birthday:  &tm,
  1679  		Age:       24,
  1680  		EmployeID: 7,
  1681  		Avatar:    "https://tse4-mm.cn.bing.net/th/id/OIP-C.SAy__OKoxrIqrXWAb7Tj1wHaEC?pid=ImgDet&rs=1",
  1682  		Image:     []byte{95, 27, 43, 66, 0, 21, 210},
  1683  		Attr:      attr,
  1684  		Valid:     true,
  1685  	}
  1686  	var dstRecord = new(evendeep.User)
  1687  	var t0 = time.Unix(0, 0)
  1688  	var emptyRecord = evendeep.User{Name: "Barbara", Birthday: &t0}
  1689  	var expectRecord = &evendeep.User{Name: "Barbara", Birthday: &t0,
  1690  		Age:       24,
  1691  		EmployeID: 7,
  1692  		Avatar:    "https://tse4-mm.cn.bing.net/th/id/OIP-C.SAy__OKoxrIqrXWAb7Tj1wHaEC?pid=ImgDet&rs=1",
  1693  		Image:     []byte{95, 27, 43, 66, 0, 21, 210},
  1694  		Attr:      attr,
  1695  		Valid:     true,
  1696  	}
  1697  	// var expectRecordZero = evendeep.User{Name: "Barbara", Birthday: &t0,
  1698  	// 	// Image: []byte{95, 27, 43, 66, 0, 21, 210},
  1699  	// 	Attr: &evendeep.Attr{},
  1700  	// 	// Attr:  &evendeep.Attr{Attrs: []string{"hello", worldString},
  1701  	// 	// Valid: true,
  1702  	// }
  1703  
  1704  	evendeep.ResetDefaultCopyController()
  1705  
  1706  	// prepare a hard copy at first
  1707  	evendeep.DeepCopy(originRec, &dstRecord)
  1708  	t.Logf("dstRecord: %v", dstRecord)
  1709  	dbglog.Log("---- dstRecord: %v", dstRecord)
  1710  	if !evendeep.DeepEqual(dstRecord, &originRec) {
  1711  		t.Fatalf("bad, \n   got: %v\nexpect: %v\n   got.Attr: %v\nexpect.Attr: %v", dstRecord, originRec, dstRecord.Attr, originRec.Attr)
  1712  	}
  1713  
  1714  	// now update dstRecord with the non-empty fields.
  1715  	evendeep.DeepCopy(emptyRecord, &dstRecord, evendeep.WithOmitEmptyOpt)
  1716  	t.Logf("dstRecord (WithOmitEmptyOpt): %v", dstRecord)
  1717  	// if !evendeep.DeepEqual(dstRecord, expectRecord) {
  1718  	// 	t.Fatalf("bad, \n   got: %v\nexpect: %v\n   got.Attr: %v\nexpect.Attr: %v", dstRecord, expectRecord, dstRecord.Attr, expectRecord.Attr)
  1719  	// }
  1720  	if delta, equal := evendeep.DeepDiff(dstRecord, expectRecord); !equal {
  1721  		t.Fatalf("bad, \n   got: %v\nexpect: %v\n delta:\n%v", dstRecord, expectRecord, delta)
  1722  	}
  1723  
  1724  	// evendeep.ResetDefaultCopyController()
  1725  	// // now update dstRecord with the non-empty fields.
  1726  	// evendeep.DeepCopy(emptyRecord, &dstRecord, evendeep.WithStrategies(cms.OmitIfEmpty))
  1727  	// t.Logf("dstRecord (ClearIfInvalid): %v", dstRecord)
  1728  	// if delta, equal := evendeep.DeepDiff(dstRecord, expectRecordZero); !equal {
  1729  	// 	t.Fatalf("bad, \n   got: %v\nexpect: %v\n delta:\n%v", dstRecord, expectRecordZero, delta)
  1730  	// }
  1731  }