...

Source file src/github.com/mitchellh/copystructure/copystructure_test.go

Documentation: github.com/mitchellh/copystructure

     1  package copystructure
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  	"sync"
     7  	"testing"
     8  	"time"
     9  	"unsafe"
    10  )
    11  
    12  func TestCopy_complex(t *testing.T) {
    13  	v := map[string]interface{}{
    14  		"foo": []string{"a", "b"},
    15  		"bar": "baz",
    16  	}
    17  
    18  	result, err := Copy(v)
    19  	if err != nil {
    20  		t.Fatalf("err: %s", err)
    21  	}
    22  
    23  	if !reflect.DeepEqual(result, v) {
    24  		t.Fatalf("bad: %#v", result)
    25  	}
    26  }
    27  
    28  func TestCopy_interfacePointer(t *testing.T) {
    29  	type Nested struct {
    30  		Field string
    31  	}
    32  
    33  	type Test struct {
    34  		Value *interface{}
    35  	}
    36  
    37  	ifacePtr := func(v interface{}) *interface{} {
    38  		return &v
    39  	}
    40  
    41  	v := Test{
    42  		Value: ifacePtr(Nested{Field: "111"}),
    43  	}
    44  	result, err := Copy(v)
    45  	if err != nil {
    46  		t.Fatalf("err: %s", err)
    47  	}
    48  
    49  	if !reflect.DeepEqual(result, v) {
    50  		t.Fatalf("bad: %#v", result)
    51  	}
    52  }
    53  
    54  func TestCopy_primitive(t *testing.T) {
    55  	cases := []interface{}{
    56  		42,
    57  		"foo",
    58  		1.2,
    59  	}
    60  
    61  	for _, tc := range cases {
    62  		result, err := Copy(tc)
    63  		if err != nil {
    64  			t.Fatalf("err: %s", err)
    65  		}
    66  		if result != tc {
    67  			t.Fatalf("bad: %#v", result)
    68  		}
    69  	}
    70  }
    71  
    72  func TestCopy_primitivePtr(t *testing.T) {
    73  	i := 42
    74  	s := "foo"
    75  	f := 1.2
    76  	cases := []interface{}{
    77  		&i,
    78  		&s,
    79  		&f,
    80  	}
    81  
    82  	for i, tc := range cases {
    83  		result, err := Copy(tc)
    84  		if err != nil {
    85  			t.Fatalf("err: %s", err)
    86  		}
    87  
    88  		if !reflect.DeepEqual(result, tc) {
    89  			t.Fatalf("%d exptected: %#v\nbad: %#v", i, tc, result)
    90  		}
    91  	}
    92  }
    93  
    94  func TestCopy_map(t *testing.T) {
    95  	v := map[string]interface{}{
    96  		"bar": "baz",
    97  	}
    98  
    99  	result, err := Copy(v)
   100  	if err != nil {
   101  		t.Fatalf("err: %s", err)
   102  	}
   103  
   104  	if !reflect.DeepEqual(result, v) {
   105  		t.Fatalf("bad: %#v", result)
   106  	}
   107  }
   108  
   109  func TestCopy_array(t *testing.T) {
   110  	v := [2]string{"bar", "baz"}
   111  
   112  	result, err := Copy(v)
   113  	if err != nil {
   114  		t.Fatalf("err: %s", err)
   115  	}
   116  
   117  	if !reflect.DeepEqual(result, v) {
   118  		t.Fatalf("bad: %#v", result)
   119  	}
   120  }
   121  
   122  func TestCopy_pointerToArray(t *testing.T) {
   123  	v := &[2]string{"bar", "baz"}
   124  
   125  	result, err := Copy(v)
   126  	if err != nil {
   127  		t.Fatalf("err: %s", err)
   128  	}
   129  
   130  	if !reflect.DeepEqual(result, v) {
   131  		t.Fatalf("bad: %#v", result)
   132  	}
   133  }
   134  
   135  func TestCopy_slice(t *testing.T) {
   136  	v := []string{"bar", "baz"}
   137  
   138  	result, err := Copy(v)
   139  	if err != nil {
   140  		t.Fatalf("err: %s", err)
   141  	}
   142  
   143  	if !reflect.DeepEqual(result, v) {
   144  		t.Fatalf("bad: %#v", result)
   145  	}
   146  }
   147  
   148  func TestCopy_pointerToSlice(t *testing.T) {
   149  	v := &[]string{"bar", "baz"}
   150  
   151  	result, err := Copy(v)
   152  	if err != nil {
   153  		t.Fatalf("err: %s", err)
   154  	}
   155  
   156  	if !reflect.DeepEqual(result, v) {
   157  		t.Fatalf("bad: %#v", result)
   158  	}
   159  }
   160  
   161  func TestCopy_pointerToMap(t *testing.T) {
   162  	v := &map[string]string{"bar": "baz"}
   163  
   164  	result, err := Copy(v)
   165  	if err != nil {
   166  		t.Fatalf("err: %s", err)
   167  	}
   168  
   169  	if !reflect.DeepEqual(result, v) {
   170  		t.Fatalf("bad: %#v", result)
   171  	}
   172  }
   173  
   174  func TestCopy_struct(t *testing.T) {
   175  	type test struct {
   176  		Value string
   177  	}
   178  
   179  	v := test{Value: "foo"}
   180  
   181  	result, err := Copy(v)
   182  	if err != nil {
   183  		t.Fatalf("err: %s", err)
   184  	}
   185  
   186  	if !reflect.DeepEqual(result, v) {
   187  		t.Fatalf("bad: %#v", result)
   188  	}
   189  }
   190  
   191  func TestCopy_structPtr(t *testing.T) {
   192  	type test struct {
   193  		Value string
   194  	}
   195  
   196  	v := &test{Value: "foo"}
   197  
   198  	result, err := Copy(v)
   199  	if err != nil {
   200  		t.Fatalf("err: %s", err)
   201  	}
   202  
   203  	if !reflect.DeepEqual(result, v) {
   204  		t.Fatalf("bad: %#v", result)
   205  	}
   206  }
   207  
   208  func TestCopy_structNil(t *testing.T) {
   209  	type test struct {
   210  		Value string
   211  	}
   212  
   213  	var v *test
   214  	result, err := Copy(v)
   215  	if err != nil {
   216  		t.Fatalf("err: %s", err)
   217  	}
   218  	if v, ok := result.(*test); !ok {
   219  		t.Fatalf("bad: %#v", result)
   220  	} else if v != nil {
   221  		t.Fatalf("bad: %#v", v)
   222  	}
   223  }
   224  
   225  func TestCopy_structShallow(t *testing.T) {
   226  	type test struct {
   227  		Value  string
   228  		Value2 *string `copy:"shallow"`
   229  	}
   230  
   231  	value2 := "bar"
   232  	value2ptr := &value2
   233  	v := test{Value: "foo", Value2: value2ptr}
   234  
   235  	result, err := Copy(v)
   236  	if err != nil {
   237  		t.Fatalf("err: %s", err)
   238  	}
   239  	if !reflect.DeepEqual(result, v) {
   240  		t.Fatalf("bad: %#v", result)
   241  	}
   242  
   243  	vcopy := result.(test)
   244  	if vcopy.Value2 != v.Value2 {
   245  		t.Fatal("should shallow copy the pointer")
   246  	}
   247  }
   248  
   249  func TestCopy_structShallowWithUnsafe(t *testing.T) {
   250  	type nested struct {
   251  		v unsafe.Pointer
   252  	}
   253  
   254  	type test struct {
   255  		Value  string
   256  		Value2 *nested `copy:"shallow"`
   257  	}
   258  
   259  	value2 := &nested{}
   260  	v := test{Value: "foo", Value2: value2}
   261  
   262  	result, err := Copy(v)
   263  	if err != nil {
   264  		t.Fatalf("err: %s", err)
   265  	}
   266  	if !reflect.DeepEqual(result, v) {
   267  		t.Fatalf("bad: %#v", result)
   268  	}
   269  
   270  	vcopy := result.(test)
   271  	if vcopy.Value2 != v.Value2 {
   272  		t.Fatal("should shallow copy the pointer")
   273  	}
   274  }
   275  
   276  func TestCopy_structIgnore(t *testing.T) {
   277  	type test struct {
   278  		Value  string
   279  		Value2 *string `copy:"ignore"`
   280  	}
   281  
   282  	value2 := "bar"
   283  	value2ptr := &value2
   284  	v := test{Value: "foo", Value2: value2ptr}
   285  
   286  	result, err := Copy(v)
   287  	if err != nil {
   288  		t.Fatalf("err: %s", err)
   289  	}
   290  	vcopy := result.(test)
   291  	if vcopy.Value2 != nil {
   292  		t.Fatal("should be nil")
   293  	}
   294  }
   295  
   296  func TestCopy_structNested(t *testing.T) {
   297  	type TestInner struct{}
   298  
   299  	type Test struct {
   300  		Test *TestInner
   301  	}
   302  
   303  	v := Test{}
   304  
   305  	result, err := Copy(v)
   306  	if err != nil {
   307  		t.Fatalf("err: %s", err)
   308  	}
   309  
   310  	if !reflect.DeepEqual(result, v) {
   311  		t.Fatalf("bad: %#v", result)
   312  	}
   313  }
   314  
   315  func TestCopy_structWithNestedArray(t *testing.T) {
   316  	type TestInner struct {
   317  		Value string
   318  	}
   319  
   320  	type Test struct {
   321  		Value [2]TestInner
   322  	}
   323  
   324  	v := Test{
   325  		Value: [2]TestInner{
   326  			{Value: "bar"},
   327  			{Value: "baz"},
   328  		},
   329  	}
   330  
   331  	result, err := Copy(v)
   332  	if err != nil {
   333  		t.Fatalf("err: %s", err)
   334  	}
   335  
   336  	if !reflect.DeepEqual(result, v) {
   337  		t.Fatalf("bad: %#v", result)
   338  	}
   339  }
   340  
   341  func TestCopy_structWithPointerToSliceField(t *testing.T) {
   342  	type Test struct {
   343  		Value *[]string
   344  	}
   345  
   346  	v := Test{
   347  		Value: &[]string{"bar", "baz"},
   348  	}
   349  
   350  	result, err := Copy(v)
   351  	if err != nil {
   352  		t.Fatalf("err: %s", err)
   353  	}
   354  
   355  	if !reflect.DeepEqual(result, v) {
   356  		t.Fatalf("bad: %#v", result)
   357  	}
   358  }
   359  
   360  func TestCopy_structWithPointerToArrayField(t *testing.T) {
   361  	type Test struct {
   362  		Value *[2]string
   363  	}
   364  
   365  	v := Test{
   366  		Value: &[2]string{"bar", "baz"},
   367  	}
   368  
   369  	result, err := Copy(v)
   370  	if err != nil {
   371  		t.Fatalf("err: %s", err)
   372  	}
   373  
   374  	if !reflect.DeepEqual(result, v) {
   375  		t.Fatalf("bad: %#v", result)
   376  	}
   377  }
   378  
   379  func TestCopy_structWithPointerToMapField(t *testing.T) {
   380  	type Test struct {
   381  		Value *map[string]string
   382  	}
   383  
   384  	v := Test{
   385  		Value: &map[string]string{"bar": "baz"},
   386  	}
   387  
   388  	result, err := Copy(v)
   389  	if err != nil {
   390  		t.Fatalf("err: %s", err)
   391  	}
   392  
   393  	if !reflect.DeepEqual(result, v) {
   394  		t.Fatalf("bad: %#v", result)
   395  	}
   396  }
   397  
   398  func TestCopy_structUnexported(t *testing.T) {
   399  	type test struct {
   400  		Value string
   401  
   402  		private string
   403  	}
   404  
   405  	v := test{Value: "foo"}
   406  
   407  	result, err := Copy(v)
   408  	if err != nil {
   409  		t.Fatalf("err: %s", err)
   410  	}
   411  
   412  	if !reflect.DeepEqual(result, v) {
   413  		t.Fatalf("bad: %#v", result)
   414  	}
   415  }
   416  
   417  func TestCopy_structUnexportedMap(t *testing.T) {
   418  	type Sub struct {
   419  		Foo map[string]interface{}
   420  	}
   421  
   422  	type test struct {
   423  		Value string
   424  
   425  		private Sub
   426  	}
   427  
   428  	v := test{
   429  		Value: "foo",
   430  		private: Sub{
   431  			Foo: map[string]interface{}{
   432  				"yo": 42,
   433  			},
   434  		},
   435  	}
   436  
   437  	result, err := Copy(v)
   438  	if err != nil {
   439  		t.Fatalf("err: %s", err)
   440  	}
   441  
   442  	// private should not be copied
   443  	v.private = Sub{}
   444  	if !reflect.DeepEqual(result, v) {
   445  		t.Fatalf("bad:\n\n%#v\n\n%#v", result, v)
   446  	}
   447  }
   448  
   449  func TestCopy_structUnexportedArray(t *testing.T) {
   450  	type Sub struct {
   451  		Foo [2]string
   452  	}
   453  
   454  	type test struct {
   455  		Value string
   456  
   457  		private Sub
   458  	}
   459  
   460  	v := test{
   461  		Value: "foo",
   462  		private: Sub{
   463  			Foo: [2]string{"bar", "baz"},
   464  		},
   465  	}
   466  
   467  	result, err := Copy(v)
   468  	if err != nil {
   469  		t.Fatalf("err: %s", err)
   470  	}
   471  
   472  	// private should not be copied
   473  	v.private = Sub{}
   474  	if !reflect.DeepEqual(result, v) {
   475  		t.Fatalf("bad:\n\n%#v\n\n%#v", result, v)
   476  	}
   477  }
   478  
   479  // This is testing an unexported field containing a slice of pointers, which
   480  // was a crashing case found in Terraform.
   481  func TestCopy_structUnexportedPtrMap(t *testing.T) {
   482  	type Foo interface{}
   483  
   484  	type Sub struct {
   485  		List []Foo
   486  	}
   487  
   488  	type test struct {
   489  		Value string
   490  
   491  		private *Sub
   492  	}
   493  
   494  	v := test{
   495  		Value: "foo",
   496  		private: &Sub{
   497  			List: []Foo{&Sub{}},
   498  		},
   499  	}
   500  
   501  	result, err := Copy(v)
   502  	if err != nil {
   503  		t.Fatalf("err: %s", err)
   504  	}
   505  
   506  	// private should not be copied
   507  	v.private = nil
   508  	if !reflect.DeepEqual(result, v) {
   509  		t.Fatalf("bad:\n\n%#v\n\n%#v", result, v)
   510  	}
   511  }
   512  
   513  func TestCopy_nestedStructUnexported(t *testing.T) {
   514  	type subTest struct {
   515  		mine string
   516  	}
   517  
   518  	type test struct {
   519  		Value   string
   520  		private subTest
   521  	}
   522  
   523  	v := test{Value: "foo"}
   524  
   525  	result, err := Copy(v)
   526  	if err != nil {
   527  		t.Fatalf("err: %s", err)
   528  	}
   529  
   530  	if !reflect.DeepEqual(result, v) {
   531  		t.Fatalf("bad: %#v", result)
   532  	}
   533  }
   534  
   535  func TestCopy_time(t *testing.T) {
   536  	type test struct {
   537  		Value time.Time
   538  	}
   539  
   540  	v := test{Value: time.Now().UTC()}
   541  
   542  	result, err := Copy(v)
   543  	if err != nil {
   544  		t.Fatalf("err: %s", err)
   545  	}
   546  
   547  	if !reflect.DeepEqual(result, v) {
   548  		t.Fatalf("bad: %#v", result)
   549  	}
   550  }
   551  
   552  func TestCopy_aliased(t *testing.T) {
   553  	type (
   554  		Int   int
   555  		Str   string
   556  		Map   map[Int]interface{}
   557  		Slice []Str
   558  	)
   559  
   560  	v := Map{
   561  		1: Map{10: 20},
   562  		2: Map(nil),
   563  		3: Slice{"a", "b"},
   564  	}
   565  
   566  	result, err := Copy(v)
   567  	if err != nil {
   568  		t.Fatalf("err: %s", err)
   569  	}
   570  
   571  	if !reflect.DeepEqual(result, v) {
   572  		t.Fatalf("bad: %#v", result)
   573  	}
   574  }
   575  
   576  type EmbeddedLocker struct {
   577  	sync.Mutex
   578  	Map map[int]int
   579  }
   580  
   581  func TestCopy_embeddedLocker(t *testing.T) {
   582  	v := &EmbeddedLocker{
   583  		Map: map[int]int{42: 111},
   584  	}
   585  	// start locked to prevent copying
   586  	v.Lock()
   587  
   588  	var result interface{}
   589  	var err error
   590  
   591  	copied := make(chan bool)
   592  
   593  	go func() {
   594  		result, err = Config{Lock: true}.Copy(v)
   595  		close(copied)
   596  	}()
   597  
   598  	// pause slightly to make sure copying is blocked
   599  	select {
   600  	case <-copied:
   601  		t.Fatal("copy completed while locked!")
   602  	case <-time.After(100 * time.Millisecond):
   603  		v.Unlock()
   604  	}
   605  
   606  	<-copied
   607  
   608  	// test that the mutex is in the correct state
   609  	result.(*EmbeddedLocker).Lock()
   610  	result.(*EmbeddedLocker).Unlock()
   611  
   612  	if err != nil {
   613  		t.Fatalf("err: %s", err)
   614  	}
   615  
   616  	if !reflect.DeepEqual(result, v) {
   617  		t.Fatalf("bad: %#v", result)
   618  	}
   619  }
   620  
   621  // this will trigger the race detector, and usually panic if the original
   622  // struct isn't properly locked during Copy
   623  func TestCopy_lockRace(t *testing.T) {
   624  	v := &EmbeddedLocker{
   625  		Map: map[int]int{},
   626  	}
   627  
   628  	var wg sync.WaitGroup
   629  	for i := 0; i < 100; i++ {
   630  		wg.Add(1)
   631  		go func() {
   632  			defer wg.Done()
   633  			for i := 0; i < 100; i++ {
   634  				v.Lock()
   635  				v.Map[i] = i
   636  				v.Unlock()
   637  			}
   638  		}()
   639  		wg.Add(1)
   640  		go func() {
   641  			defer wg.Done()
   642  			Config{Lock: true}.Copy(v)
   643  		}()
   644  	}
   645  
   646  	wg.Wait()
   647  	result, err := Config{Lock: true}.Copy(v)
   648  
   649  	// test that the mutex is in the correct state
   650  	result.(*EmbeddedLocker).Lock()
   651  	result.(*EmbeddedLocker).Unlock()
   652  
   653  	if err != nil {
   654  		t.Fatalf("err: %s", err)
   655  	}
   656  
   657  	if !reflect.DeepEqual(result, v) {
   658  		t.Fatalf("bad: %#v", result)
   659  	}
   660  }
   661  
   662  type LockedField struct {
   663  	String string
   664  	Locker *EmbeddedLocker
   665  	// this should not get locked or have its state copied
   666  	Mutex    sync.Mutex
   667  	nilMutex *sync.Mutex
   668  }
   669  
   670  func TestCopy_lockedField(t *testing.T) {
   671  	v := &LockedField{
   672  		String: "orig",
   673  		Locker: &EmbeddedLocker{
   674  			Map: map[int]int{42: 111},
   675  		},
   676  	}
   677  
   678  	// start locked to prevent copying
   679  	v.Locker.Lock()
   680  	v.Mutex.Lock()
   681  
   682  	var result interface{}
   683  	var err error
   684  
   685  	copied := make(chan bool)
   686  
   687  	go func() {
   688  		result, err = Config{Lock: true}.Copy(v)
   689  		close(copied)
   690  	}()
   691  
   692  	// pause slightly to make sure copying is blocked
   693  	select {
   694  	case <-copied:
   695  		t.Fatal("copy completed while locked!")
   696  	case <-time.After(100 * time.Millisecond):
   697  		v.Locker.Unlock()
   698  	}
   699  
   700  	<-copied
   701  
   702  	// test that the mutexes are in the correct state
   703  	result.(*LockedField).Locker.Lock()
   704  	result.(*LockedField).Locker.Unlock()
   705  	result.(*LockedField).Mutex.Lock()
   706  	result.(*LockedField).Mutex.Unlock()
   707  
   708  	// this wasn't  blocking, but should be unlocked for DeepEqual
   709  	v.Mutex.Unlock()
   710  
   711  	if err != nil {
   712  		t.Fatalf("err: %s", err)
   713  	}
   714  
   715  	if !reflect.DeepEqual(result, v) {
   716  		t.Fatalf("expected:\n%#v\nbad:\n%#v\n", v, result)
   717  	}
   718  }
   719  
   720  // test something that doesn't contain a lock internally
   721  type lockedMap map[int]int
   722  
   723  var mapLock sync.Mutex
   724  
   725  func (m lockedMap) Lock()   { mapLock.Lock() }
   726  func (m lockedMap) Unlock() { mapLock.Unlock() }
   727  
   728  func TestCopy_lockedMap(t *testing.T) {
   729  	v := lockedMap{1: 2}
   730  	v.Lock()
   731  
   732  	var result interface{}
   733  	var err error
   734  
   735  	copied := make(chan bool)
   736  
   737  	go func() {
   738  		result, err = Config{Lock: true}.Copy(&v)
   739  		close(copied)
   740  	}()
   741  
   742  	// pause slightly to make sure copying is blocked
   743  	select {
   744  	case <-copied:
   745  		t.Fatal("copy completed while locked!")
   746  	case <-time.After(100 * time.Millisecond):
   747  		v.Unlock()
   748  	}
   749  
   750  	<-copied
   751  
   752  	// test that the mutex is in the correct state
   753  	result.(*lockedMap).Lock()
   754  	result.(*lockedMap).Unlock()
   755  
   756  	if err != nil {
   757  		t.Fatalf("err: %s", err)
   758  	}
   759  
   760  	if !reflect.DeepEqual(result, &v) {
   761  		t.Fatalf("bad: %#v", result)
   762  	}
   763  }
   764  
   765  // Use an RLock if available
   766  type RLocker struct {
   767  	sync.RWMutex
   768  	Map map[int]int
   769  }
   770  
   771  func TestCopy_rLocker(t *testing.T) {
   772  	v := &RLocker{
   773  		Map: map[int]int{1: 2},
   774  	}
   775  	v.Lock()
   776  
   777  	var result interface{}
   778  	var err error
   779  
   780  	copied := make(chan bool)
   781  
   782  	go func() {
   783  		result, err = Config{Lock: true}.Copy(v)
   784  		close(copied)
   785  	}()
   786  
   787  	// pause slightly to make sure copying is blocked
   788  	select {
   789  	case <-copied:
   790  		t.Fatal("copy completed while locked!")
   791  	case <-time.After(100 * time.Millisecond):
   792  		v.Unlock()
   793  	}
   794  
   795  	<-copied
   796  
   797  	// test that the mutex is in the correct state
   798  	vCopy := result.(*RLocker)
   799  	vCopy.Lock()
   800  	vCopy.Unlock()
   801  	vCopy.RLock()
   802  	vCopy.RUnlock()
   803  
   804  	// now make sure we can copy during an RLock
   805  	v.RLock()
   806  	result, err = Config{Lock: true}.Copy(v)
   807  	if err != nil {
   808  		t.Fatal(err)
   809  	}
   810  	v.RUnlock()
   811  
   812  	vCopy = result.(*RLocker)
   813  	vCopy.Lock()
   814  	vCopy.Unlock()
   815  	vCopy.RLock()
   816  	vCopy.RUnlock()
   817  
   818  	if !reflect.DeepEqual(result, v) {
   819  		t.Fatalf("bad: %#v", result)
   820  	}
   821  }
   822  
   823  // Test that we don't panic when encountering nil Lockers
   824  func TestCopy_missingLockedField(t *testing.T) {
   825  	v := &LockedField{
   826  		String: "orig",
   827  	}
   828  
   829  	result, err := Config{Lock: true}.Copy(v)
   830  
   831  	if err != nil {
   832  		t.Fatalf("err: %s", err)
   833  	}
   834  
   835  	if !reflect.DeepEqual(result, v) {
   836  		t.Fatalf("expected:\n%#v\nbad:\n%#v\n", v, result)
   837  	}
   838  }
   839  
   840  type PointerLocker struct {
   841  	Mu sync.Mutex
   842  }
   843  
   844  func (p *PointerLocker) Lock()   { p.Mu.Lock() }
   845  func (p *PointerLocker) Unlock() { p.Mu.Unlock() }
   846  
   847  func TestCopy_pointerLockerNil(t *testing.T) {
   848  	v := struct {
   849  		P *PointerLocker
   850  	}{}
   851  
   852  	_, err := Config{Lock: true}.Copy(&v)
   853  	if err != nil {
   854  		t.Fatalf("err: %s", err)
   855  	}
   856  }
   857  
   858  func TestCopy_sliceWithNil(t *testing.T) {
   859  	v := [](*int){nil}
   860  
   861  	result, err := Copy(v)
   862  	if err != nil {
   863  		t.Fatalf("err: %s", err)
   864  	}
   865  
   866  	if !reflect.DeepEqual(result, v) {
   867  		t.Fatalf("expected:\n%#v\ngot:\n%#v", v, result)
   868  	}
   869  }
   870  
   871  func TestCopy_mapWithNil(t *testing.T) {
   872  	v := map[int](*int){0: nil}
   873  
   874  	result, err := Copy(v)
   875  	if err != nil {
   876  		t.Fatalf("err: %s", err)
   877  	}
   878  
   879  	if !reflect.DeepEqual(result, v) {
   880  		t.Fatalf("expected:\n%#v\ngot:\n%#v", v, result)
   881  	}
   882  }
   883  
   884  // While this is safe to lock and copy directly, copystructure requires a
   885  // pointer to reflect the value safely.
   886  func TestCopy_valueWithLockPointer(t *testing.T) {
   887  	v := struct {
   888  		*sync.Mutex
   889  		X int
   890  	}{
   891  		Mutex: &sync.Mutex{},
   892  		X:     3,
   893  	}
   894  
   895  	_, err := Config{Lock: true}.Copy(v)
   896  
   897  	if err != errPointerRequired {
   898  		t.Fatalf("expected errPointerRequired, got: %v", err)
   899  	}
   900  }
   901  
   902  func TestCopy_mapWithPointers(t *testing.T) {
   903  	type T struct {
   904  		S string
   905  	}
   906  	v := map[string]interface{}{
   907  		"a": &T{S: "hello"},
   908  	}
   909  
   910  	result, err := Copy(v)
   911  	if err != nil {
   912  		t.Fatal(err)
   913  	}
   914  
   915  	if !reflect.DeepEqual(v, result) {
   916  		t.Fatalf("%#v", result)
   917  	}
   918  }
   919  
   920  func TestCopy_structWithMapWithPointers(t *testing.T) {
   921  	type T struct {
   922  		S string
   923  		M map[string]interface{}
   924  	}
   925  	v := &T{
   926  		S: "a",
   927  		M: map[string]interface{}{
   928  			"b": &T{
   929  				S: "b",
   930  			},
   931  		},
   932  	}
   933  
   934  	result, err := Copy(v)
   935  	if err != nil {
   936  		t.Fatal(err)
   937  	}
   938  
   939  	if !reflect.DeepEqual(v, result) {
   940  		t.Fatal(result)
   941  	}
   942  }
   943  
   944  type testT struct {
   945  	N   int
   946  	Spp **string
   947  	X   testX
   948  	Xp  *testX
   949  	Xpp **testX
   950  }
   951  
   952  type testX struct {
   953  	Tp  *testT
   954  	Tpp **testT
   955  	Ip  *interface{}
   956  	Ep  *error
   957  	S   fmt.Stringer
   958  }
   959  
   960  type stringer struct{}
   961  
   962  func (s *stringer) String() string {
   963  	return "test string"
   964  }
   965  
   966  func TestCopy_structWithPointersAndInterfaces(t *testing.T) {
   967  	// test that we can copy various nested and chained pointers and interfaces
   968  	s := "val"
   969  	sp := &s
   970  	spp := &sp
   971  	i := interface{}(11)
   972  
   973  	tp := &testT{
   974  		N: 2,
   975  	}
   976  
   977  	xp := &testX{
   978  		Tp:  tp,
   979  		Tpp: &tp,
   980  		Ip:  &i,
   981  		S:   &stringer{},
   982  	}
   983  
   984  	v := &testT{
   985  		N:   1,
   986  		Spp: spp,
   987  		X:   testX{},
   988  		Xp:  xp,
   989  		Xpp: &xp,
   990  	}
   991  
   992  	result, err := Copy(v)
   993  	if err != nil {
   994  		t.Fatal(err)
   995  	}
   996  
   997  	if !reflect.DeepEqual(v, result) {
   998  		t.Fatal(result)
   999  	}
  1000  }
  1001  
  1002  func Test_pointerInterfacePointer(t *testing.T) {
  1003  	s := "hi"
  1004  	si := interface{}(&s)
  1005  	sip := &si
  1006  
  1007  	result, err := Copy(sip)
  1008  	if err != nil {
  1009  		t.Fatal(err)
  1010  	}
  1011  
  1012  	if !reflect.DeepEqual(sip, result) {
  1013  		t.Fatalf("%#v != %#v\n", sip, result)
  1014  	}
  1015  }
  1016  
  1017  func Test_pointerInterfacePointer2(t *testing.T) {
  1018  	type T struct {
  1019  		I *interface{}
  1020  		J **fmt.Stringer
  1021  	}
  1022  
  1023  	x := 1
  1024  	y := &stringer{}
  1025  
  1026  	i := interface{}(&x)
  1027  	j := fmt.Stringer(y)
  1028  	jp := &j
  1029  
  1030  	v := &T{
  1031  		I: &i,
  1032  		J: &jp,
  1033  	}
  1034  	result, err := Copy(v)
  1035  	if err != nil {
  1036  		t.Fatal(err)
  1037  	}
  1038  
  1039  	if !reflect.DeepEqual(v, result) {
  1040  		t.Fatalf("%#v != %#v\n", v, result)
  1041  	}
  1042  }
  1043  
  1044  // This test catches a bug that happened when unexported fields were
  1045  // first their subsequent fields wouldn't be copied.
  1046  func TestCopy_unexportedFieldFirst(t *testing.T) {
  1047  	type P struct {
  1048  		mu       sync.Mutex
  1049  		Old, New string
  1050  	}
  1051  
  1052  	type T struct {
  1053  		M map[string]*P
  1054  	}
  1055  
  1056  	v := &T{
  1057  		M: map[string]*P{
  1058  			"a": &P{Old: "", New: "2"},
  1059  		},
  1060  	}
  1061  
  1062  	result, err := Copy(v)
  1063  	if err != nil {
  1064  		t.Fatal(err)
  1065  	}
  1066  
  1067  	if !reflect.DeepEqual(v, result) {
  1068  		t.Fatalf("\n%#v\n\n%#v", v, result)
  1069  	}
  1070  }
  1071  
  1072  func TestCopy_nilPointerInSlice(t *testing.T) {
  1073  	type T struct {
  1074  		Ps []*int
  1075  	}
  1076  
  1077  	v := &T{
  1078  		Ps: []*int{nil},
  1079  	}
  1080  
  1081  	result, err := Copy(v)
  1082  	if err != nil {
  1083  		t.Fatal(err)
  1084  	}
  1085  
  1086  	if !reflect.DeepEqual(v, result) {
  1087  		t.Fatalf("\n%#v\n\n%#v", v, result)
  1088  	}
  1089  }
  1090  
  1091  //-------------------------------------------------------------------
  1092  // The tests below all tests various pointer cases around copying
  1093  // a structure that uses a defined Copier. This was originally raised
  1094  // around issue #26.
  1095  
  1096  func TestCopy_timePointer(t *testing.T) {
  1097  	type T struct {
  1098  		Value *time.Time
  1099  	}
  1100  
  1101  	now := time.Now()
  1102  	v := &T{
  1103  		Value: &now,
  1104  	}
  1105  
  1106  	result, err := Copy(v)
  1107  	if err != nil {
  1108  		t.Fatal(err)
  1109  	}
  1110  
  1111  	if !reflect.DeepEqual(v, result) {
  1112  		t.Fatalf("\n%#v\n\n%#v", v, result)
  1113  	}
  1114  }
  1115  
  1116  func TestCopy_timeNonPointer(t *testing.T) {
  1117  	type T struct {
  1118  		Value time.Time
  1119  	}
  1120  
  1121  	v := &T{
  1122  		Value: time.Now(),
  1123  	}
  1124  
  1125  	result, err := Copy(v)
  1126  	if err != nil {
  1127  		t.Fatal(err)
  1128  	}
  1129  
  1130  	if !reflect.DeepEqual(v, result) {
  1131  		t.Fatalf("\n%#v\n\n%#v", v, result)
  1132  	}
  1133  }
  1134  
  1135  func TestCopy_timeDoublePointer(t *testing.T) {
  1136  	type T struct {
  1137  		Value **time.Time
  1138  	}
  1139  
  1140  	now := time.Now()
  1141  	nowP := &now
  1142  	nowPP := &nowP
  1143  	v := &T{
  1144  		Value: nowPP,
  1145  	}
  1146  
  1147  	result, err := Copy(v)
  1148  	if err != nil {
  1149  		t.Fatal(err)
  1150  	}
  1151  
  1152  	if !reflect.DeepEqual(v, result) {
  1153  		t.Fatalf("\n%#v\n\n%#v", v, result)
  1154  	}
  1155  }
  1156  
  1157  type nestedValue struct {
  1158  	v string
  1159  }
  1160  
  1161  func TestCopy_customCopierConfig(t *testing.T) {
  1162  	type T struct {
  1163  		Val *nestedValue
  1164  	}
  1165  
  1166  	v := &T{
  1167  		Val: &nestedValue{v: "original"},
  1168  	}
  1169  
  1170  	cfg := Config{
  1171  		Copiers: map[reflect.Type]CopierFunc{
  1172  			reflect.TypeOf(nestedValue{}): customCopier,
  1173  		},
  1174  	}
  1175  	result, err := cfg.Copy(v)
  1176  	if err != nil {
  1177  		t.Fatal(err)
  1178  	}
  1179  
  1180  	copiedVal := result.(*T)
  1181  
  1182  	if !reflect.DeepEqual(v.Val.v, copiedVal.Val.v) {
  1183  		t.Fatalf("\nexpected: %#v\ngiven: %#v", v.Val.v, copiedVal.Val.v)
  1184  	}
  1185  }
  1186  
  1187  func customCopier(v interface{}) (interface{}, error) {
  1188  	return v.(nestedValue), nil
  1189  }
  1190  
  1191  func TestCopy_customCopierShallowValue(t *testing.T) {
  1192  	type T struct{}
  1193  	v := &T{}
  1194  
  1195  	cfg := Config{
  1196  		ShallowCopiers: map[reflect.Type]struct{}{
  1197  			reflect.TypeOf(T{}): struct{}{},
  1198  		},
  1199  	}
  1200  	result, err := cfg.Copy(v)
  1201  	if err != nil {
  1202  		t.Fatal(err)
  1203  	}
  1204  
  1205  	copiedVal := result.(*T)
  1206  
  1207  	if v != copiedVal {
  1208  		t.Fatal("value not shallow copied")
  1209  	}
  1210  }
  1211  

View as plain text