github.com/hedzr/evendeep@v0.4.8/deepcopy_test.go (about) 1 package evendeep_test 2 3 import ( 4 "fmt" 5 "reflect" 6 "testing" 7 "time" 8 "unsafe" 9 10 "github.com/hedzr/evendeep" 11 "github.com/hedzr/evendeep/flags" 12 "github.com/hedzr/evendeep/flags/cms" 13 "github.com/hedzr/evendeep/typ" 14 ) 15 16 type FF interface { 17 Flags() flags.Flags 18 } 19 20 func TestFlagsRevert(t *testing.T) { 21 var saved = evendeep.DefaultCopyController.Flags().Clone() 22 evendeep.DefaultCopyController.Flags().WithFlags(cms.SliceCopyAppend) 23 evendeep.DefaultCopyController.SetFlags(saved) 24 25 if c, ok := evendeep.New().(FF); ok { 26 nf := c.Flags() 27 b := reflect.DeepEqual(evendeep.DefaultCopyController.Flags(), nf) 28 evendeep.HelperAssertYes(t, b, nf, evendeep.DefaultCopyController.Flags()) 29 } 30 } 31 32 func TestWithXXX(t *testing.T) { 33 34 copier := evendeep.NewForTest() 35 36 type AA struct { 37 TestString string 38 X string 39 } 40 type BB struct { 41 X string 42 } 43 44 t.Run("string to duration", func(t *testing.T) { 45 46 var dur time.Duration 47 var src = "9h71ms" 48 // var svv = reflect.ValueOf(src) 49 // var tvv = reflect.ValueOf(&dur) // .Elem() 50 51 err := copier.CopyTo(src, &dur) 52 if err != nil { 53 t.Fatalf("err: %v", err) 54 } 55 t.Logf("res: %v", dur) 56 57 }) 58 59 t.Run("ignore names test", func(t *testing.T) { 60 61 src1 := &AA{TestString: "well", X: "ok"} 62 tgt1 := &BB{X: "no"} 63 err := copier.CopyTo(src1, &tgt1) 64 t.Logf("res bb: %+v", tgt1) 65 if err != nil { 66 t.Fatalf("err: %v", err) 67 } 68 if tgt1.X != src1.X { 69 t.Fatalf("err: after 'TestString' field was ignored, AA.X should be copied as BB.X") 70 } 71 72 }) 73 74 t.Run("non-ignore names test", func(t *testing.T) { 75 76 copier = evendeep.New() 77 78 src1 := &AA{TestString: "well", X: "ok"} 79 tgt1 := &BB{X: "no"} 80 err := copier.CopyTo(src1, &tgt1) 81 if err != nil { 82 t.Fatalf("err: %v", err) 83 } 84 if tgt1.X != src1.TestString { 85 t.Fatalf("err: if 'TestString' field was not ignored, AA.TestString should be copied as BB.X") 86 } 87 t.Logf("res bb: %+v", tgt1) 88 89 }) 90 91 t.Run("ignore field test", func(t *testing.T) { 92 copier = evendeep.New() 93 94 type AAA struct { 95 X1 string `copy:"-"` 96 X2 string `copy:",-"` 97 Y int 98 } 99 type BBB struct { 100 X1 string 101 X2 string 102 Y int 103 } 104 src1 := &AAA{X1: "ok", X2: "well", Y: 1} 105 tgt1 := &BBB{X1: "no", X2: "longer", Y: -1} 106 err := copier.CopyTo(src1, &tgt1, evendeep.WithSyncAdvancing(true)) 107 if err != nil { 108 t.Fatalf("err: %v", err) 109 } 110 111 t.Logf("res bb: %+v", tgt1) 112 113 if tgt1.X1 == src1.X1 || tgt1.X2 == src1.X2 { 114 t.Fatalf("err: 'X1','X2' fields should be ignored, the fact is bad") 115 } 116 if tgt1.Y != src1.Y { 117 t.Fatalf("err: 'Y' field should be copied.") 118 } 119 120 }) 121 122 t.Run("ignore field test - no sync advance", func(t *testing.T) { 123 copier = evendeep.New() 124 125 type AAA struct { 126 X1 string `copy:"-"` 127 X2 string `copy:",-"` 128 Y int 129 } 130 type BBB struct { 131 Y int 132 } 133 src1 := &AAA{X1: "ok", X2: "well", Y: 1} 134 tgt1 := &BBB{Y: -1} 135 err := copier.CopyTo(src1, &tgt1) 136 if err != nil { 137 t.Fatalf("err: %v", err) 138 } 139 140 t.Logf("res bb: %+v", tgt1) 141 142 if tgt1.Y != src1.Y { 143 t.Fatalf("err: 'Y' field should be copied.") 144 } 145 146 }) 147 148 t.Run("earlier valid test", func(t *testing.T) { 149 150 var from *AA 151 var to *BB 152 ret := evendeep.DeepCopy(from, &to) 153 t.Logf("to = %v, ret = %v", to, ret) 154 155 ret = evendeep.DeepCopy(nil, &to) 156 t.Logf("to = %v, ret = %v", to, ret) 157 158 ret = evendeep.MakeClone(from) 159 t.Logf("ret = %v", ret) 160 161 ret = evendeep.MakeClone(nil) 162 t.Logf("ret = %v", ret) 163 164 }) 165 166 t.Run("return error test", func(t *testing.T) { 167 168 type AAA struct { 169 X1 string `copy:"-"` 170 X2 string `copy:",-"` 171 Y int 172 } 173 type BBB struct { 174 X1 string 175 X2 string 176 Y int 177 } 178 src1 := &AAA{X1: "ok", X2: "well", Y: 1} 179 tgt1 := &BBB{X1: "no", X2: "longer", Y: -1} 180 181 copier = evendeep.NewForTest() 182 err := copier.CopyTo(&src1, tgt1) 183 if err != nil { 184 t.Fatalf("err: %v", err) 185 } 186 187 }) 188 189 } 190 191 func TestIgnoreSourceField(t *testing.T) { 192 type AA struct { 193 A bool `copy:",ignore"` 194 B int 195 } 196 src := &AA{A: false, B: 9} 197 dst := &AA{A: true, B: 19} 198 err := evendeep.New().CopyTo(src, dst, evendeep.WithSyncAdvancingOpt) 199 if err != nil { 200 t.Fatalf("err: %v", err) 201 } 202 t.Logf("got: %v", *dst) 203 if !dst.A || dst.B != 9 { 204 t.FailNow() 205 } 206 } 207 208 func TestOmitEmptySourceField(t *testing.T) { 209 type AA struct { 210 A int `copy:",omitempty"` 211 B int 212 } 213 src := &AA{A: 0, B: 9} 214 dst := &AA{A: 11, B: 19} 215 err := evendeep.New().CopyTo(src, dst, evendeep.WithOmitEmptyOpt) 216 if err != nil { 217 t.Fatalf("err: %v", err) 218 } 219 t.Logf("got: %v", *dst) 220 if dst.A != 11 || dst.B != 9 { 221 t.FailNow() 222 } 223 } 224 225 func TestDeepCopyGenerally(t *testing.T) { 226 // defer dbglog.NewCaptureLog(t).Release() 227 228 nn := []int{2, 9, 77, 111, 23, 29} 229 var a [2]string 230 a[0] = "Hello" 231 a[1] = "World" 232 233 x0 := evendeep.X0{} 234 x1 := evendeep.X1{ 235 A: uintptr(unsafe.Pointer(&x0)), 236 H: make(chan int, 5), 237 M: unsafe.Pointer(&x0), 238 // E: []*X0{&x0}, 239 N: nn[1:3], 240 O: a, 241 Q: a, 242 } 243 244 t.Run("MakeClone()", func(t *testing.T) { 245 var ret typ.Any // nolint:gosimple 246 // x2 := &X2{N: nn[1:3]} 247 248 ret = evendeep.MakeClone(&x1) 249 x1.K = &x0 250 testIfBadCopy(t, x1, ret, ret, "MakeClone x1 -> new") 251 t.Log("MakeClone is done.") 252 }) 253 254 t.Run("DeepCopy()", func(t *testing.T) { 255 var ret typ.Any 256 x2 := &evendeep.X2{N: nn[1:3]} 257 258 ret = evendeep.DeepCopy(&x1, &x2, evendeep.WithIgnoreNames("Shit", "Memo", "Name")) 259 testIfBadCopy(t, x1, *x2, ret, "DeepCopy x1 -> x2", true) 260 }) 261 262 t.Run("NewDeepCopier().CopyTo()", func(t *testing.T) { 263 var ret typ.Any 264 x2 := &evendeep.X2{N: nn[1:3]} 265 266 ret = evendeep.New().CopyTo(&x1, &x2, evendeep.WithIgnoreNames("Shit", "Memo", "Name")) 267 testIfBadCopy(t, x1, *x2, ret, "NewDeepCopier().CopyTo() - DeepCopy x1 -> x2", true) 268 }) 269 270 } 271 272 func TestDeepCopy(t *testing.T) { 273 type AA struct { 274 A bool 275 B int32 276 C string 277 } 278 type BB struct { 279 A int 280 B int16 281 C *string 282 } 283 284 var aa = AA{A: true, B: 16, C: helloString} 285 var bb BB 286 var ret = evendeep.DeepCopy(aa, &bb, 287 evendeep.WithIgnoreNames("Shit", "Memo", "Name")) 288 t.Logf("ret = %v", ret) 289 // ret = &{0 16 &"hello"} 290 if *bb.C != helloString { 291 t.FailNow() 292 } 293 } 294 295 func TestMakeClone(t *testing.T) { 296 type AA struct { 297 A bool 298 B int32 299 C string 300 } 301 302 var aa = AA{A: true, B: 16, C: helloString} 303 var ret = evendeep.MakeClone(aa) 304 var aaCopy = ret.(AA) 305 t.Logf("ret = %v", aaCopy) 306 // ret = {true 16 hello} 307 } 308 309 func TestNew(t *testing.T) { 310 type AA struct { 311 A bool 312 B int32 313 C string 314 } 315 type BB struct { 316 A int 317 B int16 318 C *string 319 } 320 321 var aa = AA{A: true, B: 16, C: helloString} 322 var bb BB 323 var ret typ.Any = evendeep.New().CopyTo(aa, &bb, 324 evendeep.WithIgnoreNames("Shit", "Memo", "Name")) 325 t.Logf("ret = %v", ret) 326 // ret = &{0 16 &"hello"} 327 if *bb.C != helloString { 328 t.FailNow() 329 } 330 } 331 332 func TestWithIgnoreNames(t *testing.T) { 333 type AA struct { 334 A bool 335 B int32 336 C string 337 D string 338 } 339 type BB struct { 340 A int 341 B int16 342 C *string 343 } 344 345 var aa = AA{A: true, B: 16, C: helloString, D: worldString} 346 var bb BB 347 var ret = evendeep.DeepCopy(aa, &bb, 348 evendeep.WithIgnoreNames("C*"), 349 evendeep.WithSyncAdvancing(false), 350 evendeep.WithByOrdinalStrategyOpt, 351 ) 352 t.Logf("ret = %v, .C = %v", ret, *bb.C) 353 // ret = &{0 16 &"world"} 354 if *bb.C != worldString { 355 t.FailNow() 356 } 357 358 var cc BB 359 ret = evendeep.DeepCopy(aa, &cc, 360 evendeep.WithIgnoreNames("C*"), 361 evendeep.WithSyncAdvancing(true), 362 evendeep.WithByOrdinalStrategyOpt, 363 ) 364 t.Logf("ret = %v, .C = %v", ret, *cc.C) 365 // ret = &{0 16 &""} 366 if *cc.C != "" { 367 t.FailNow() 368 } 369 } 370 371 func TestPlainCopyFuncField(t *testing.T) { 372 373 type AA struct { 374 Fn func() 375 } 376 377 t.Run("copy func field", func(t *testing.T) { 378 379 var a = AA{func() { 380 println("yes") 381 }} 382 var b AA 383 384 err := evendeep.New().CopyTo(&a, &b, evendeep.WithIgnoreNames("Shit", "Memo", "Name")) 385 if err != nil { 386 t.Fatalf("err: %v", err) 387 } 388 if b.Fn != nil { 389 b.Fn() 390 } else { 391 t.Fatalf("bad") 392 } 393 394 }) 395 396 type BB struct { 397 fn func() 398 } 399 400 t.Run("copy private func field", func(t *testing.T) { 401 402 var a = BB{func() { 403 println("yes") 404 }} 405 var b BB 406 407 err := evendeep.New().CopyTo(&a, &b, evendeep.WithIgnoreNames("Shit", "Memo", "Name")) 408 if err != nil { 409 t.Fatalf("err: %v", err) 410 } 411 if b.fn != nil { 412 b.fn() 413 } else { 414 t.Fatalf("bad") 415 } 416 417 }) 418 419 type CC struct { 420 Jx func(i1, i2 int) (i3 string) 421 } 422 423 t.Run("copy private func field (complex)", func(t *testing.T) { 424 var a = CC{func(i1, i2 int) (i3 string) { 425 return fmt.Sprintf("%v+%v", i1, i2) 426 }} 427 428 var v = reflect.ValueOf(&a) 429 var vf = v.Elem().Field(0) 430 var vft = vf.Type() 431 t.Logf("out: %v, %v", vft.NumOut(), vft.Out(0)) 432 }) 433 434 }