github.com/sandwich-go/boost@v1.3.29/xcopy/deep_test.go (about) 1 package xcopy 2 3 import ( 4 proto1 "github.com/golang/protobuf/proto" 5 "github.com/sandwich-go/boost/xrand" 6 "github.com/sandwich-go/boost/z" 7 . "github.com/smartystreets/goconvey/convey" 8 proto2 "google.golang.org/protobuf/proto" 9 "google.golang.org/protobuf/reflect/protoreflect" 10 "reflect" 11 "strconv" 12 "testing" 13 ) 14 15 type withDeepCopy struct { 16 stringF string 17 intF uint32 18 cloneF int 19 } 20 21 func randWithDeepCopy() *withDeepCopy { 22 return &withDeepCopy{intF: z.FastRand(), stringF: xrand.String(20)} 23 } 24 25 func (w withDeepCopy) getCloneFlag() int { return w.cloneF } 26 func (w *withDeepCopy) DeepCopy() interface{} { 27 if w == nil { 28 return nil 29 } 30 return &withDeepCopy{stringF: w.stringF, intF: w.intF, cloneF: cloneFlagDeep} 31 } 32 33 func (w *withDeepCopy) equal(w1 *withDeepCopy) bool { 34 if w == nil && w1 == nil { 35 return true 36 } 37 if (w == nil && w1 != nil) || (w1 == nil && w != nil) { 38 return false 39 } 40 return w.intF == w1.intF && w.stringF == w1.stringF 41 } 42 43 func copyMap(in map[string]string) (out map[string]string) { 44 if in != nil { 45 out = make(map[string]string) 46 for k, v := range in { 47 out[k] = v 48 } 49 } 50 return 51 } 52 53 func equalMap(a, b map[string]string) bool { 54 if a == nil && b == nil { 55 return true 56 } 57 if (a == nil && b != nil) || (b == nil && a != nil) || len(a) != len(b) { 58 return false 59 } 60 for k, v := range a { 61 v1, ok := b[k] 62 if !ok || v != v1 { 63 return false 64 } 65 } 66 return true 67 } 68 69 func randMap() map[string]string { 70 n := z.FastRandUint32n(101) 71 out := make(map[string]string) 72 var i uint32 73 for i = 0; i < n; i++ { 74 out[strconv.FormatUint(uint64(i), 10)] = xrand.String(20) 75 } 76 return out 77 } 78 79 func copySlice(in []string) (out []string) { 80 if in != nil { 81 out = make([]string, len(in)) 82 copy(out, in) 83 } 84 return 85 } 86 87 func equalSlice(a, b []string) bool { 88 if a == nil && b == nil { 89 return true 90 } 91 if (a == nil && b != nil) || (b == nil && a != nil) || len(a) != len(b) { 92 return false 93 } 94 for k, v := range a { 95 if v != b[k] { 96 return false 97 } 98 } 99 return true 100 } 101 102 func randSlice() []string { 103 n := z.FastRandUint32n(101) 104 out := make([]string, n) 105 for k := range out { 106 out[k] = xrand.String(20) 107 } 108 return out 109 } 110 111 const ( 112 cloneFlag = iota 113 cloneFlag1 114 cloneFlag2 115 cloneFlagDeep 116 ) 117 118 type withClone1 struct { 119 stringF string 120 intF uint32 121 mapF map[string]string 122 sliceF []string 123 pointerF *withDeepCopy 124 cloneF int 125 } 126 127 func randWithClone1() *withClone1 { 128 return &withClone1{ 129 intF: z.FastRand(), stringF: xrand.String(20), 130 mapF: randMap(), sliceF: randSlice(), 131 pointerF: randWithDeepCopy(), 132 } 133 } 134 135 func (w withClone1) getCloneFlag() int { return w.cloneF } 136 func (*withClone1) Reset() {} 137 func (*withClone1) String() string { return "" } 138 func (*withClone1) ProtoMessage() {} 139 func (w *withClone1) Clone() proto1.Message { 140 c := &withClone1{ 141 stringF: w.stringF, 142 intF: w.intF, 143 mapF: copyMap(w.mapF), 144 sliceF: copySlice(w.sliceF), 145 cloneF: cloneFlag1, 146 } 147 if w.pointerF != nil { 148 c.pointerF = w.pointerF.DeepCopy().(*withDeepCopy) 149 } 150 return c 151 } 152 func (w *withClone1) equal(w1 *withClone1) bool { 153 if w == nil && w1 == nil { 154 return true 155 } 156 if (w == nil && w1 != nil) || (w1 == nil && w != nil) { 157 return false 158 } 159 if w.stringF != w1.stringF || w.intF != w1.intF || 160 !equalMap(w.mapF, w1.mapF) || !equalSlice(w.sliceF, w1.sliceF) || !w.pointerF.equal(w1.pointerF) { 161 return false 162 } 163 return true 164 } 165 166 type withClone2 struct { 167 stringF string 168 intF uint32 169 mapF map[string]string 170 sliceF []string 171 pointerF *withDeepCopy 172 cloneF int 173 } 174 175 func randWithClone2() *withClone2 { 176 return &withClone2{ 177 intF: z.FastRand(), stringF: xrand.String(20), 178 mapF: randMap(), sliceF: randSlice(), 179 pointerF: randWithDeepCopy(), 180 } 181 } 182 183 func (w withClone2) getCloneFlag() int { return w.cloneF } 184 func (withClone2) ProtoReflect() protoreflect.Message { return nil } 185 func (w *withClone2) Clone() proto2.Message { 186 c := &withClone2{ 187 stringF: w.stringF, 188 intF: w.intF, 189 mapF: copyMap(w.mapF), 190 sliceF: copySlice(w.sliceF), 191 cloneF: cloneFlag2, 192 } 193 if w.pointerF != nil { 194 c.pointerF = w.pointerF.DeepCopy().(*withDeepCopy) 195 } 196 return c 197 } 198 func (w *withClone2) equal(w1 *withClone2) bool { 199 if w == nil && w1 == nil { 200 return true 201 } 202 if (w == nil && w1 != nil) || (w1 == nil && w != nil) { 203 return false 204 } 205 if w.stringF != w1.stringF || w.intF != w1.intF || 206 !equalMap(w.mapF, w1.mapF) || !equalSlice(w.sliceF, w1.sliceF) || !w.pointerF.equal(w1.pointerF) { 207 return false 208 } 209 return true 210 } 211 212 func equal(a, b interface{}) bool { 213 if a == nil && b == nil { 214 return true 215 } 216 if (a == nil && b != nil) || (b == nil && a != nil) { 217 return false 218 } 219 if reflect.ValueOf(a).Type().String() != reflect.ValueOf(b).Type().String() { 220 return false 221 } 222 switch aa := a.(type) { 223 case *withClone1: 224 return aa.equal(b.(*withClone1)) 225 case *withClone2: 226 return aa.equal(b.(*withClone2)) 227 case *withDeepCopy: 228 return aa.equal(b.(*withDeepCopy)) 229 case *common: 230 return aa.equal(b.(*common)) 231 } 232 return false 233 } 234 235 type common struct { 236 I uint32 237 B *subMap 238 C *subSlice 239 D subStruct 240 E getter 241 F *withDeepCopy 242 G *withClone1 243 H *withClone2 244 } 245 246 func randCommon() *common { 247 return &common{ 248 I: z.FastRand(), B: randSubMap(), C: randSubSlice(), 249 D: randSubStruct(), E: randSubInterface(), F: randWithDeepCopy(), 250 G: randWithClone1(), H: randWithClone2(), 251 } 252 } 253 254 func (c *common) equal(c1 *common) bool { 255 if c == nil && c1 == nil { 256 return true 257 } 258 if (c == nil && c1 != nil) || (c1 == nil && c != nil) { 259 return false 260 } 261 if c.I != c1.I || !c.B.equal(c1.B) || !c.C.equal(c1.C) || !c.E.equal(c1.E) || !c.F.equal(c1.F) || !c.G.equal(c1.G) || !c.H.equal(c1.H) { 262 return false 263 } 264 return true 265 } 266 267 type getter interface { 268 get() uint32 269 equal(getter) bool 270 } 271 272 type subInterface struct { 273 I uint32 274 } 275 276 func randSubInterface() *subInterface { 277 return &subInterface{I: z.FastRand()} 278 } 279 280 func (s subInterface) get() uint32 { return s.I } 281 282 func (s *subInterface) equal(s1 getter) bool { 283 if s == nil && s1 == nil { 284 return true 285 } 286 if (s == nil && s1 != nil) || (s1 == nil && s != nil) { 287 return false 288 } 289 return s.get() == s1.get() 290 } 291 292 type subStruct struct { 293 I uint32 294 } 295 296 func randSubStruct() subStruct { 297 return subStruct{I: z.FastRand()} 298 } 299 300 func (s subStruct) equal(s1 subStruct) bool { 301 return s.I == s1.I 302 } 303 304 type subSlice struct { 305 B []string 306 } 307 308 func randSubSlice() *subSlice { 309 return &subSlice{B: randSlice()} 310 } 311 312 func (s *subSlice) equal(s1 *subSlice) bool { 313 if s == nil && s1 == nil { 314 return true 315 } 316 if (s == nil && s1 != nil) || (s1 == nil && s != nil) { 317 return false 318 } 319 return equalSlice(s.B, s1.B) 320 } 321 322 type subMap struct { 323 B map[string]string 324 } 325 326 func (s *subMap) equal(s1 *subMap) bool { 327 if s == nil && s1 == nil { 328 return true 329 } 330 if (s == nil && s1 != nil) || (s1 == nil && s != nil) { 331 return false 332 } 333 return equalMap(s.B, s1.B) 334 } 335 336 func randSubMap() *subMap { 337 return &subMap{B: randMap()} 338 } 339 340 type sub struct { 341 i uint32 342 } 343 344 func randSub() *sub { 345 return &sub{i: z.FastRand()} 346 } 347 348 func (s *sub) equal(s1 *sub) bool { 349 if s == nil && s1 == nil { 350 return true 351 } 352 if (s == nil && s1 != nil) || (s1 == nil && s != nil) { 353 return false 354 } 355 return s.i == s1.i 356 } 357 358 func TestDeepCopy(t *testing.T) { 359 Convey("deep copy", t, func() { 360 for _, test := range []struct { 361 src interface{} 362 cloneFlag int 363 notEqual bool 364 }{ 365 {src: nil, cloneFlag: cloneFlag}, 366 {src: randWithClone1(), cloneFlag: cloneFlag1}, 367 {src: randWithClone2(), cloneFlag: cloneFlag2}, 368 {src: randWithDeepCopy(), cloneFlag: cloneFlagDeep}, 369 {src: randCommon()}, 370 {src: randSub(), notEqual: true}, 371 } { 372 dest := DeepCopy(test.src) 373 if test.notEqual { 374 So(equal(test.src, dest), ShouldBeFalse) 375 } else { 376 So(equal(test.src, dest), ShouldBeTrue) 377 } 378 if v, ok := dest.(interface{ getCloneFlag() int }); ok { 379 So(v.getCloneFlag(), ShouldEqual, test.cloneFlag) 380 } 381 } 382 }) 383 }