summaryrefslogtreecommitdiff
path: root/vendor/github.com/mitchellh/copystructure
diff options
context:
space:
mode:
authorFlavio Castelli <fcastelli@suse.com>2017-05-27 00:22:00 +0200
committerFlavio Castelli <fcastelli@suse.com>2017-05-27 00:22:00 +0200
commitdbb8832efb22cb69951d552cb71cef211390f64a (patch)
treeb8bbaa9f6bdf69efadca8622622c6454eebca33b /vendor/github.com/mitchellh/copystructure
parent392b153595f220abef45da262ec4ffab4fcb969a (diff)
downloadterraform-provider-libvirt-dbb8832efb22cb69951d552cb71cef211390f64a.tar
terraform-provider-libvirt-dbb8832efb22cb69951d552cb71cef211390f64a.tar.gz
Fix broken tests by changing the way we vendor code
When I configured the project to use vndr and I broke the unit tests. The tests were failing with these errors: ``` github.com/dmacvicar/terraform-provider-libvirt/vendor/github.com/hashicorp/terraform/builtin/providers/ignition vendor/github.com/hashicorp/terraform/builtin/providers/ignition/provider.go:92: undefined: types.SystemdUnit vendor/github.com/hashicorp/terraform/builtin/providers/ignition/provider.go:93: undefined: types.NetworkdUnit vendor/github.com/hashicorp/terraform/builtin/providers/ignition/provider.go:94: undefined: types.User vendor/github.com/hashicorp/terraform/builtin/providers/ignition/provider.go:95: undefined: types.Group ``` You can see the full log here: https://travis-ci.org/dmacvicar/terraform-provider-libvirt Terraform upstream doesn't have this problem because it vendors coreos ignition, which has all these types defined inside of `vendor/github.com/coreos/ignition/config/types/unit.go`. It turns out vndr is removing this file from our vendored terraform sources. I tried to use the whitelist option to prevent that from happening but it didn't work. Moreover, it looks like the whitelists are not stored into the `vendor.conf`, which means we would have to pass the flag every time we interact with the vendor code! With this commit we move from using vndr to use glide, which is not affected by this issue. Signed-off-by: Flavio Castelli <fcastelli@suse.com>
Diffstat (limited to 'vendor/github.com/mitchellh/copystructure')
-rw-r--r--vendor/github.com/mitchellh/copystructure/.travis.yml12
-rw-r--r--vendor/github.com/mitchellh/copystructure/copier_time_test.go17
-rw-r--r--vendor/github.com/mitchellh/copystructure/copystructure.go5
-rw-r--r--vendor/github.com/mitchellh/copystructure/copystructure_examples_test.go22
-rw-r--r--vendor/github.com/mitchellh/copystructure/copystructure_test.go1083
5 files changed, 1138 insertions, 1 deletions
diff --git a/vendor/github.com/mitchellh/copystructure/.travis.yml b/vendor/github.com/mitchellh/copystructure/.travis.yml
new file mode 100644
index 00000000..d7b9589a
--- /dev/null
+++ b/vendor/github.com/mitchellh/copystructure/.travis.yml
@@ -0,0 +1,12 @@
+language: go
+
+go:
+ - 1.7
+ - tip
+
+script:
+ - go test
+
+matrix:
+ allow_failures:
+ - go: tip
diff --git a/vendor/github.com/mitchellh/copystructure/copier_time_test.go b/vendor/github.com/mitchellh/copystructure/copier_time_test.go
new file mode 100644
index 00000000..5506a0ff
--- /dev/null
+++ b/vendor/github.com/mitchellh/copystructure/copier_time_test.go
@@ -0,0 +1,17 @@
+package copystructure
+
+import (
+ "testing"
+ "time"
+)
+
+func TestTimeCopier(t *testing.T) {
+ v := time.Now().UTC()
+ result, err := timeCopier(v)
+ if err != nil {
+ t.Fatalf("err: %s", err)
+ }
+ if result.(time.Time) != v {
+ t.Fatalf("bad: %#v\n\n%#v", v, result)
+ }
+}
diff --git a/vendor/github.com/mitchellh/copystructure/copystructure.go b/vendor/github.com/mitchellh/copystructure/copystructure.go
index ca658132..14043525 100644
--- a/vendor/github.com/mitchellh/copystructure/copystructure.go
+++ b/vendor/github.com/mitchellh/copystructure/copystructure.go
@@ -366,7 +366,10 @@ func (w *walker) Struct(s reflect.Value) error {
return err
}
- v = reflect.ValueOf(dup)
+ // We need to put a pointer to the value on the value stack,
+ // so allocate a new pointer and set it.
+ v = reflect.New(s.Type())
+ reflect.Indirect(v).Set(reflect.ValueOf(dup))
} else {
// No copier, we copy ourselves and allow reflectwalk to guide
// us deeper into the structure for copying.
diff --git a/vendor/github.com/mitchellh/copystructure/copystructure_examples_test.go b/vendor/github.com/mitchellh/copystructure/copystructure_examples_test.go
new file mode 100644
index 00000000..e094b862
--- /dev/null
+++ b/vendor/github.com/mitchellh/copystructure/copystructure_examples_test.go
@@ -0,0 +1,22 @@
+package copystructure
+
+import (
+ "fmt"
+)
+
+func ExampleCopy() {
+ input := map[string]interface{}{
+ "bob": map[string]interface{}{
+ "emails": []string{"a", "b"},
+ },
+ }
+
+ dup, err := Copy(input)
+ if err != nil {
+ panic(err)
+ }
+
+ fmt.Printf("%#v", dup)
+ // Output:
+ // map[string]interface {}{"bob":map[string]interface {}{"emails":[]string{"a", "b"}}}
+}
diff --git a/vendor/github.com/mitchellh/copystructure/copystructure_test.go b/vendor/github.com/mitchellh/copystructure/copystructure_test.go
new file mode 100644
index 00000000..93c8dd2a
--- /dev/null
+++ b/vendor/github.com/mitchellh/copystructure/copystructure_test.go
@@ -0,0 +1,1083 @@
+package copystructure
+
+import (
+ "fmt"
+ "reflect"
+ "sync"
+ "testing"
+ "time"
+)
+
+func TestCopy_complex(t *testing.T) {
+ v := map[string]interface{}{
+ "foo": []string{"a", "b"},
+ "bar": "baz",
+ }
+
+ result, err := Copy(v)
+ if err != nil {
+ t.Fatalf("err: %s", err)
+ }
+
+ if !reflect.DeepEqual(result, v) {
+ t.Fatalf("bad: %#v", result)
+ }
+}
+
+func TestCopy_interfacePointer(t *testing.T) {
+ type Nested struct {
+ Field string
+ }
+
+ type Test struct {
+ Value *interface{}
+ }
+
+ ifacePtr := func(v interface{}) *interface{} {
+ return &v
+ }
+
+ v := Test{
+ Value: ifacePtr(Nested{Field: "111"}),
+ }
+ result, err := Copy(v)
+ if err != nil {
+ t.Fatalf("err: %s", err)
+ }
+
+ if !reflect.DeepEqual(result, v) {
+ t.Fatalf("bad: %#v", result)
+ }
+}
+
+func TestCopy_primitive(t *testing.T) {
+ cases := []interface{}{
+ 42,
+ "foo",
+ 1.2,
+ }
+
+ for _, tc := range cases {
+ result, err := Copy(tc)
+ if err != nil {
+ t.Fatalf("err: %s", err)
+ }
+ if result != tc {
+ t.Fatalf("bad: %#v", result)
+ }
+ }
+}
+
+func TestCopy_primitivePtr(t *testing.T) {
+ i := 42
+ s := "foo"
+ f := 1.2
+ cases := []interface{}{
+ &i,
+ &s,
+ &f,
+ }
+
+ for i, tc := range cases {
+ result, err := Copy(tc)
+ if err != nil {
+ t.Fatalf("err: %s", err)
+ }
+
+ if !reflect.DeepEqual(result, tc) {
+ t.Fatalf("%d exptected: %#v\nbad: %#v", i, tc, result)
+ }
+ }
+}
+
+func TestCopy_map(t *testing.T) {
+ v := map[string]interface{}{
+ "bar": "baz",
+ }
+
+ result, err := Copy(v)
+ if err != nil {
+ t.Fatalf("err: %s", err)
+ }
+
+ if !reflect.DeepEqual(result, v) {
+ t.Fatalf("bad: %#v", result)
+ }
+}
+
+func TestCopy_array(t *testing.T) {
+ v := [2]string{"bar", "baz"}
+
+ result, err := Copy(v)
+ if err != nil {
+ t.Fatalf("err: %s", err)
+ }
+
+ if !reflect.DeepEqual(result, v) {
+ t.Fatalf("bad: %#v", result)
+ }
+}
+
+func TestCopy_pointerToArray(t *testing.T) {
+ v := &[2]string{"bar", "baz"}
+
+ result, err := Copy(v)
+ if err != nil {
+ t.Fatalf("err: %s", err)
+ }
+
+ if !reflect.DeepEqual(result, v) {
+ t.Fatalf("bad: %#v", result)
+ }
+}
+
+func TestCopy_slice(t *testing.T) {
+ v := []string{"bar", "baz"}
+
+ result, err := Copy(v)
+ if err != nil {
+ t.Fatalf("err: %s", err)
+ }
+
+ if !reflect.DeepEqual(result, v) {
+ t.Fatalf("bad: %#v", result)
+ }
+}
+
+func TestCopy_pointerToSlice(t *testing.T) {
+ v := &[]string{"bar", "baz"}
+
+ result, err := Copy(v)
+ if err != nil {
+ t.Fatalf("err: %s", err)
+ }
+
+ if !reflect.DeepEqual(result, v) {
+ t.Fatalf("bad: %#v", result)
+ }
+}
+
+func TestCopy_pointerToMap(t *testing.T) {
+ v := &map[string]string{"bar": "baz"}
+
+ result, err := Copy(v)
+ if err != nil {
+ t.Fatalf("err: %s", err)
+ }
+
+ if !reflect.DeepEqual(result, v) {
+ t.Fatalf("bad: %#v", result)
+ }
+}
+
+func TestCopy_struct(t *testing.T) {
+ type test struct {
+ Value string
+ }
+
+ v := test{Value: "foo"}
+
+ result, err := Copy(v)
+ if err != nil {
+ t.Fatalf("err: %s", err)
+ }
+
+ if !reflect.DeepEqual(result, v) {
+ t.Fatalf("bad: %#v", result)
+ }
+}
+
+func TestCopy_structPtr(t *testing.T) {
+ type test struct {
+ Value string
+ }
+
+ v := &test{Value: "foo"}
+
+ result, err := Copy(v)
+ if err != nil {
+ t.Fatalf("err: %s", err)
+ }
+
+ if !reflect.DeepEqual(result, v) {
+ t.Fatalf("bad: %#v", result)
+ }
+}
+
+func TestCopy_structNil(t *testing.T) {
+ type test struct {
+ Value string
+ }
+
+ var v *test
+ result, err := Copy(v)
+ if err != nil {
+ t.Fatalf("err: %s", err)
+ }
+ if v, ok := result.(*test); !ok {
+ t.Fatalf("bad: %#v", result)
+ } else if v != nil {
+ t.Fatalf("bad: %#v", v)
+ }
+}
+
+func TestCopy_structNested(t *testing.T) {
+ type TestInner struct{}
+
+ type Test struct {
+ Test *TestInner
+ }
+
+ v := Test{}
+
+ result, err := Copy(v)
+ if err != nil {
+ t.Fatalf("err: %s", err)
+ }
+
+ if !reflect.DeepEqual(result, v) {
+ t.Fatalf("bad: %#v", result)
+ }
+}
+
+func TestCopy_structWithNestedArray(t *testing.T) {
+ type TestInner struct {
+ Value string
+ }
+
+ type Test struct {
+ Value [2]TestInner
+ }
+
+ v := Test{
+ Value: [2]TestInner{
+ {Value: "bar"},
+ {Value: "baz"},
+ },
+ }
+
+ result, err := Copy(v)
+ if err != nil {
+ t.Fatalf("err: %s", err)
+ }
+
+ if !reflect.DeepEqual(result, v) {
+ t.Fatalf("bad: %#v", result)
+ }
+}
+
+func TestCopy_structWithPointerToSliceField(t *testing.T) {
+ type Test struct {
+ Value *[]string
+ }
+
+ v := Test{
+ Value: &[]string{"bar", "baz"},
+ }
+
+ result, err := Copy(v)
+ if err != nil {
+ t.Fatalf("err: %s", err)
+ }
+
+ if !reflect.DeepEqual(result, v) {
+ t.Fatalf("bad: %#v", result)
+ }
+}
+
+func TestCopy_structWithPointerToArrayField(t *testing.T) {
+ type Test struct {
+ Value *[2]string
+ }
+
+ v := Test{
+ Value: &[2]string{"bar", "baz"},
+ }
+
+ result, err := Copy(v)
+ if err != nil {
+ t.Fatalf("err: %s", err)
+ }
+
+ if !reflect.DeepEqual(result, v) {
+ t.Fatalf("bad: %#v", result)
+ }
+}
+
+func TestCopy_structWithPointerToMapField(t *testing.T) {
+ type Test struct {
+ Value *map[string]string
+ }
+
+ v := Test{
+ Value: &map[string]string{"bar": "baz"},
+ }
+
+ result, err := Copy(v)
+ if err != nil {
+ t.Fatalf("err: %s", err)
+ }
+
+ if !reflect.DeepEqual(result, v) {
+ t.Fatalf("bad: %#v", result)
+ }
+}
+
+func TestCopy_structUnexported(t *testing.T) {
+ type test struct {
+ Value string
+
+ private string
+ }
+
+ v := test{Value: "foo"}
+
+ result, err := Copy(v)
+ if err != nil {
+ t.Fatalf("err: %s", err)
+ }
+
+ if !reflect.DeepEqual(result, v) {
+ t.Fatalf("bad: %#v", result)
+ }
+}
+
+func TestCopy_structUnexportedMap(t *testing.T) {
+ type Sub struct {
+ Foo map[string]interface{}
+ }
+
+ type test struct {
+ Value string
+
+ private Sub
+ }
+
+ v := test{
+ Value: "foo",
+ private: Sub{
+ Foo: map[string]interface{}{
+ "yo": 42,
+ },
+ },
+ }
+
+ result, err := Copy(v)
+ if err != nil {
+ t.Fatalf("err: %s", err)
+ }
+
+ // private should not be copied
+ v.private = Sub{}
+ if !reflect.DeepEqual(result, v) {
+ t.Fatalf("bad:\n\n%#v\n\n%#v", result, v)
+ }
+}
+
+func TestCopy_structUnexportedArray(t *testing.T) {
+ type Sub struct {
+ Foo [2]string
+ }
+
+ type test struct {
+ Value string
+
+ private Sub
+ }
+
+ v := test{
+ Value: "foo",
+ private: Sub{
+ Foo: [2]string{"bar", "baz"},
+ },
+ }
+
+ result, err := Copy(v)
+ if err != nil {
+ t.Fatalf("err: %s", err)
+ }
+
+ // private should not be copied
+ v.private = Sub{}
+ if !reflect.DeepEqual(result, v) {
+ t.Fatalf("bad:\n\n%#v\n\n%#v", result, v)
+ }
+}
+
+// This is testing an unexported field containing a slice of pointers, which
+// was a crashing case found in Terraform.
+func TestCopy_structUnexportedPtrMap(t *testing.T) {
+ type Foo interface{}
+
+ type Sub struct {
+ List []Foo
+ }
+
+ type test struct {
+ Value string
+
+ private *Sub
+ }
+
+ v := test{
+ Value: "foo",
+ private: &Sub{
+ List: []Foo{&Sub{}},
+ },
+ }
+
+ result, err := Copy(v)
+ if err != nil {
+ t.Fatalf("err: %s", err)
+ }
+
+ // private should not be copied
+ v.private = nil
+ if !reflect.DeepEqual(result, v) {
+ t.Fatalf("bad:\n\n%#v\n\n%#v", result, v)
+ }
+}
+
+func TestCopy_nestedStructUnexported(t *testing.T) {
+ type subTest struct {
+ mine string
+ }
+
+ type test struct {
+ Value string
+ private subTest
+ }
+
+ v := test{Value: "foo"}
+
+ result, err := Copy(v)
+ if err != nil {
+ t.Fatalf("err: %s", err)
+ }
+
+ if !reflect.DeepEqual(result, v) {
+ t.Fatalf("bad: %#v", result)
+ }
+}
+
+func TestCopy_time(t *testing.T) {
+ type test struct {
+ Value time.Time
+ }
+
+ v := test{Value: time.Now().UTC()}
+
+ result, err := Copy(v)
+ if err != nil {
+ t.Fatalf("err: %s", err)
+ }
+
+ if !reflect.DeepEqual(result, v) {
+ t.Fatalf("bad: %#v", result)
+ }
+}
+
+func TestCopy_aliased(t *testing.T) {
+ type (
+ Int int
+ Str string
+ Map map[Int]interface{}
+ Slice []Str
+ )
+
+ v := Map{
+ 1: Map{10: 20},
+ 2: Map(nil),
+ 3: Slice{"a", "b"},
+ }
+
+ result, err := Copy(v)
+ if err != nil {
+ t.Fatalf("err: %s", err)
+ }
+
+ if !reflect.DeepEqual(result, v) {
+ t.Fatalf("bad: %#v", result)
+ }
+}
+
+type EmbeddedLocker struct {
+ sync.Mutex
+ Map map[int]int
+}
+
+func TestCopy_embeddedLocker(t *testing.T) {
+ v := &EmbeddedLocker{
+ Map: map[int]int{42: 111},
+ }
+ // start locked to prevent copying
+ v.Lock()
+
+ var result interface{}
+ var err error
+
+ copied := make(chan bool)
+
+ go func() {
+ result, err = Config{Lock: true}.Copy(v)
+ close(copied)
+ }()
+
+ // pause slightly to make sure copying is blocked
+ select {
+ case <-copied:
+ t.Fatal("copy completed while locked!")
+ case <-time.After(100 * time.Millisecond):
+ v.Unlock()
+ }
+
+ <-copied
+
+ // test that the mutex is in the correct state
+ result.(*EmbeddedLocker).Lock()
+ result.(*EmbeddedLocker).Unlock()
+
+ if err != nil {
+ t.Fatalf("err: %s", err)
+ }
+
+ if !reflect.DeepEqual(result, v) {
+ t.Fatalf("bad: %#v", result)
+ }
+}
+
+// this will trigger the race detector, and usually panic if the original
+// struct isn't properly locked during Copy
+func TestCopy_lockRace(t *testing.T) {
+ v := &EmbeddedLocker{
+ Map: map[int]int{},
+ }
+
+ var wg sync.WaitGroup
+ for i := 0; i < 100; i++ {
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ for i := 0; i < 100; i++ {
+ v.Lock()
+ v.Map[i] = i
+ v.Unlock()
+ }
+ }()
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ Config{Lock: true}.Copy(v)
+ }()
+ }
+
+ wg.Wait()
+ result, err := Config{Lock: true}.Copy(v)
+
+ // test that the mutex is in the correct state
+ result.(*EmbeddedLocker).Lock()
+ result.(*EmbeddedLocker).Unlock()
+
+ if err != nil {
+ t.Fatalf("err: %s", err)
+ }
+
+ if !reflect.DeepEqual(result, v) {
+ t.Fatalf("bad: %#v", result)
+ }
+}
+
+type LockedField struct {
+ String string
+ Locker *EmbeddedLocker
+ // this should not get locked or have its state copied
+ Mutex sync.Mutex
+ nilMutex *sync.Mutex
+}
+
+func TestCopy_lockedField(t *testing.T) {
+ v := &LockedField{
+ String: "orig",
+ Locker: &EmbeddedLocker{
+ Map: map[int]int{42: 111},
+ },
+ }
+
+ // start locked to prevent copying
+ v.Locker.Lock()
+ v.Mutex.Lock()
+
+ var result interface{}
+ var err error
+
+ copied := make(chan bool)
+
+ go func() {
+ result, err = Config{Lock: true}.Copy(v)
+ close(copied)
+ }()
+
+ // pause slightly to make sure copying is blocked
+ select {
+ case <-copied:
+ t.Fatal("copy completed while locked!")
+ case <-time.After(100 * time.Millisecond):
+ v.Locker.Unlock()
+ }
+
+ <-copied
+
+ // test that the mutexes are in the correct state
+ result.(*LockedField).Locker.Lock()
+ result.(*LockedField).Locker.Unlock()
+ result.(*LockedField).Mutex.Lock()
+ result.(*LockedField).Mutex.Unlock()
+
+ // this wasn't blocking, but should be unlocked for DeepEqual
+ v.Mutex.Unlock()
+
+ if err != nil {
+ t.Fatalf("err: %s", err)
+ }
+
+ if !reflect.DeepEqual(result, v) {
+ t.Fatalf("expected:\n%#v\nbad:\n%#v\n", v, result)
+ }
+}
+
+// test something that doesn't contain a lock internally
+type lockedMap map[int]int
+
+var mapLock sync.Mutex
+
+func (m lockedMap) Lock() { mapLock.Lock() }
+func (m lockedMap) Unlock() { mapLock.Unlock() }
+
+func TestCopy_lockedMap(t *testing.T) {
+ v := lockedMap{1: 2}
+ v.Lock()
+
+ var result interface{}
+ var err error
+
+ copied := make(chan bool)
+
+ go func() {
+ result, err = Config{Lock: true}.Copy(&v)
+ close(copied)
+ }()
+
+ // pause slightly to make sure copying is blocked
+ select {
+ case <-copied:
+ t.Fatal("copy completed while locked!")
+ case <-time.After(100 * time.Millisecond):
+ v.Unlock()
+ }
+
+ <-copied
+
+ // test that the mutex is in the correct state
+ result.(*lockedMap).Lock()
+ result.(*lockedMap).Unlock()
+
+ if err != nil {
+ t.Fatalf("err: %s", err)
+ }
+
+ if !reflect.DeepEqual(result, &v) {
+ t.Fatalf("bad: %#v", result)
+ }
+}
+
+// Use an RLock if available
+type RLocker struct {
+ sync.RWMutex
+ Map map[int]int
+}
+
+func TestCopy_rLocker(t *testing.T) {
+ v := &RLocker{
+ Map: map[int]int{1: 2},
+ }
+ v.Lock()
+
+ var result interface{}
+ var err error
+
+ copied := make(chan bool)
+
+ go func() {
+ result, err = Config{Lock: true}.Copy(v)
+ close(copied)
+ }()
+
+ // pause slightly to make sure copying is blocked
+ select {
+ case <-copied:
+ t.Fatal("copy completed while locked!")
+ case <-time.After(100 * time.Millisecond):
+ v.Unlock()
+ }
+
+ <-copied
+
+ // test that the mutex is in the correct state
+ vCopy := result.(*RLocker)
+ vCopy.Lock()
+ vCopy.Unlock()
+ vCopy.RLock()
+ vCopy.RUnlock()
+
+ // now make sure we can copy during an RLock
+ v.RLock()
+ result, err = Config{Lock: true}.Copy(v)
+ if err != nil {
+ t.Fatal(err)
+ }
+ v.RUnlock()
+
+ vCopy = result.(*RLocker)
+ vCopy.Lock()
+ vCopy.Unlock()
+ vCopy.RLock()
+ vCopy.RUnlock()
+
+ if !reflect.DeepEqual(result, v) {
+ t.Fatalf("bad: %#v", result)
+ }
+}
+
+// Test that we don't panic when encountering nil Lockers
+func TestCopy_missingLockedField(t *testing.T) {
+ v := &LockedField{
+ String: "orig",
+ }
+
+ result, err := Config{Lock: true}.Copy(v)
+
+ if err != nil {
+ t.Fatalf("err: %s", err)
+ }
+
+ if !reflect.DeepEqual(result, v) {
+ t.Fatalf("expected:\n%#v\nbad:\n%#v\n", v, result)
+ }
+}
+
+type PointerLocker struct {
+ Mu sync.Mutex
+}
+
+func (p *PointerLocker) Lock() { p.Mu.Lock() }
+func (p *PointerLocker) Unlock() { p.Mu.Unlock() }
+
+func TestCopy_pointerLockerNil(t *testing.T) {
+ v := struct {
+ P *PointerLocker
+ }{}
+
+ _, err := Config{Lock: true}.Copy(&v)
+ if err != nil {
+ t.Fatalf("err: %s", err)
+ }
+}
+
+func TestCopy_sliceWithNil(t *testing.T) {
+ v := [](*int){nil}
+
+ result, err := Copy(v)
+ if err != nil {
+ t.Fatalf("err: %s", err)
+ }
+
+ if !reflect.DeepEqual(result, v) {
+ t.Fatalf("expected:\n%#v\ngot:\n%#v", v, result)
+ }
+}
+
+func TestCopy_mapWithNil(t *testing.T) {
+ v := map[int](*int){0: nil}
+
+ result, err := Copy(v)
+ if err != nil {
+ t.Fatalf("err: %s", err)
+ }
+
+ if !reflect.DeepEqual(result, v) {
+ t.Fatalf("expected:\n%#v\ngot:\n%#v", v, result)
+ }
+}
+
+// While this is safe to lock and copy directly, copystructure requires a
+// pointer to reflect the value safely.
+func TestCopy_valueWithLockPointer(t *testing.T) {
+ v := struct {
+ *sync.Mutex
+ X int
+ }{
+ Mutex: &sync.Mutex{},
+ X: 3,
+ }
+
+ _, err := Config{Lock: true}.Copy(v)
+
+ if err != errPointerRequired {
+ t.Fatalf("expected errPointerRequired, got: %v", err)
+ }
+}
+
+func TestCopy_mapWithPointers(t *testing.T) {
+ type T struct {
+ S string
+ }
+ v := map[string]interface{}{
+ "a": &T{S: "hello"},
+ }
+
+ result, err := Copy(v)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if !reflect.DeepEqual(v, result) {
+ t.Fatalf("%#v", result)
+ }
+}
+
+func TestCopy_structWithMapWithPointers(t *testing.T) {
+ type T struct {
+ S string
+ M map[string]interface{}
+ }
+ v := &T{
+ S: "a",
+ M: map[string]interface{}{
+ "b": &T{
+ S: "b",
+ },
+ },
+ }
+
+ result, err := Copy(v)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if !reflect.DeepEqual(v, result) {
+ t.Fatal(result)
+ }
+}
+
+type testT struct {
+ N int
+ Spp **string
+ X testX
+ Xp *testX
+ Xpp **testX
+}
+
+type testX struct {
+ Tp *testT
+ Tpp **testT
+ Ip *interface{}
+ Ep *error
+ S fmt.Stringer
+}
+
+type stringer struct{}
+
+func (s *stringer) String() string {
+ return "test string"
+}
+
+func TestCopy_structWithPointersAndInterfaces(t *testing.T) {
+ // test that we can copy various nested and chained pointers and interfaces
+ s := "val"
+ sp := &s
+ spp := &sp
+ i := interface{}(11)
+
+ tp := &testT{
+ N: 2,
+ }
+
+ xp := &testX{
+ Tp: tp,
+ Tpp: &tp,
+ Ip: &i,
+ S: &stringer{},
+ }
+
+ v := &testT{
+ N: 1,
+ Spp: spp,
+ X: testX{},
+ Xp: xp,
+ Xpp: &xp,
+ }
+
+ result, err := Copy(v)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if !reflect.DeepEqual(v, result) {
+ t.Fatal(result)
+ }
+}
+
+func Test_pointerInterfacePointer(t *testing.T) {
+ s := "hi"
+ si := interface{}(&s)
+ sip := &si
+
+ result, err := Copy(sip)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if !reflect.DeepEqual(sip, result) {
+ t.Fatalf("%#v != %#v\n", sip, result)
+ }
+}
+
+func Test_pointerInterfacePointer2(t *testing.T) {
+ type T struct {
+ I *interface{}
+ J **fmt.Stringer
+ }
+
+ x := 1
+ y := &stringer{}
+
+ i := interface{}(&x)
+ j := fmt.Stringer(y)
+ jp := &j
+
+ v := &T{
+ I: &i,
+ J: &jp,
+ }
+ result, err := Copy(v)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if !reflect.DeepEqual(v, result) {
+ t.Fatalf("%#v != %#v\n", v, result)
+ }
+}
+
+// This test catches a bug that happened when unexported fields were
+// first their subsequent fields wouldn't be copied.
+func TestCopy_unexportedFieldFirst(t *testing.T) {
+ type P struct {
+ mu sync.Mutex
+ Old, New string
+ }
+
+ type T struct {
+ M map[string]*P
+ }
+
+ v := &T{
+ M: map[string]*P{
+ "a": &P{Old: "", New: "2"},
+ },
+ }
+
+ result, err := Copy(v)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if !reflect.DeepEqual(v, result) {
+ t.Fatalf("\n%#v\n\n%#v", v, result)
+ }
+}
+
+func TestCopy_nilPointerInSlice(t *testing.T) {
+ type T struct {
+ Ps []*int
+ }
+
+ v := &T{
+ Ps: []*int{nil},
+ }
+
+ result, err := Copy(v)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if !reflect.DeepEqual(v, result) {
+ t.Fatalf("\n%#v\n\n%#v", v, result)
+ }
+}
+
+//-------------------------------------------------------------------
+// The tests below all tests various pointer cases around copying
+// a structure that uses a defined Copier. This was originally raised
+// around issue #26.
+
+func TestCopy_timePointer(t *testing.T) {
+ type T struct {
+ Value *time.Time
+ }
+
+ now := time.Now()
+ v := &T{
+ Value: &now,
+ }
+
+ result, err := Copy(v)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if !reflect.DeepEqual(v, result) {
+ t.Fatalf("\n%#v\n\n%#v", v, result)
+ }
+}
+
+func TestCopy_timeNonPointer(t *testing.T) {
+ type T struct {
+ Value time.Time
+ }
+
+ v := &T{
+ Value: time.Now(),
+ }
+
+ result, err := Copy(v)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if !reflect.DeepEqual(v, result) {
+ t.Fatalf("\n%#v\n\n%#v", v, result)
+ }
+}
+
+func TestCopy_timeDoublePointer(t *testing.T) {
+ type T struct {
+ Value **time.Time
+ }
+
+ now := time.Now()
+ nowP := &now
+ nowPP := &nowP
+ v := &T{
+ Value: nowPP,
+ }
+
+ result, err := Copy(v)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if !reflect.DeepEqual(v, result) {
+ t.Fatalf("\n%#v\n\n%#v", v, result)
+ }
+}