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  }