12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289 |
- package deepcopy
- import (
- "fmt"
- "reflect"
- "testing"
- "time"
- "unsafe"
- "github.com/stretchr/testify/assert"
- )
- // hasSameDataPointer 检查两个切片是否共享相同的底层数组
- func hasSameDataPointer(a1, b1 interface{}) bool {
- a := reflect.ValueOf(a1)
- b := reflect.ValueOf(b1)
- // 首先确保两个值的类型相同
- if a.Kind() != b.Kind() {
- return false
- }
- switch a.Kind() {
- case reflect.Slice:
- // 对于切片,比较底层数组指针
- return unsafe.Pointer(a.Pointer()) == unsafe.Pointer(b.Pointer())
- case reflect.Ptr:
- // 对于指针,直接比较指针值
- return a.Pointer() == b.Pointer()
- case reflect.Map:
- // 对于映射,比较映射指针
- return a.Pointer() == b.Pointer()
- case reflect.Chan:
- // 对于通道,比较通道指针
- return a.Pointer() == b.Pointer()
- default:
- // 其他类型可能不支持直接的内存比较
- return false
- }
- // aVal := reflect.ValueOf(a)
- // bVal := reflect.ValueOf(b)
- // if aVal.Kind() != reflect.Slice || bVal.Kind() != reflect.Slice {
- // return false
- // }
- // a1 := (*reflect.SliceHeader)(unsafe.Pointer(aVal.Pointer()))
- // b1 := (*reflect.SliceHeader)(unsafe.Pointer(bVal.Pointer()))
- // return a1.Data == b1.Data
- }
- // just basic is this working stuff
- func TestSimple(t *testing.T) {
- t.Run("Copy[]string", func(t *testing.T) {
- original := []string{"a", "b", "c"}
- originalC := []string{"a", "b", "d"}
- if hasSameDataPointer(original, originalC) {
- fmt.Println("same")
- }
- copied, err := Copy(original)
- assert.NoError(t, err)
- cpyS := copied.([]string)
- assert.False(t, hasSameDataPointer(original, cpyS), "expected different memory addresses")
- assert.Equal(t, len(original), len(cpyS), "length should match")
- assert.Equal(t, original, cpyS, "content should match")
- })
- t.Run("Copy[]bool", func(t *testing.T) {
- original := []bool{true, true, false, false}
- copied, err := Copy(original)
- assert.NoError(t, err)
- cpyB := copied.([]bool)
- assert.False(t, hasSameDataPointer(original, cpyB), "expected different memory addresses")
- assert.Equal(t, len(original), len(cpyB), "length should match")
- assert.Equal(t, original, cpyB, "content should match")
- })
- t.Run("Copy[]byte", func(t *testing.T) {
- original := []byte("hello")
- copied, err := Copy(original)
- assert.NoError(t, err)
- cpyBt := copied.([]byte)
- assert.False(t, hasSameDataPointer(original, cpyBt), "expected different memory addresses")
- assert.Equal(t, len(original), len(cpyBt), "length should match")
- assert.Equal(t, original, cpyBt, "content should match")
- })
- t.Run("Copy[]int", func(t *testing.T) {
- original := []int{42}
- copied, err := Copy(original)
- assert.NoError(t, err)
- cpyI := copied.([]int)
- assert.False(t, hasSameDataPointer(original, cpyI), "expected different memory addresses")
- assert.Equal(t, len(original), len(cpyI), "length should match")
- assert.Equal(t, original, cpyI, "content should match")
- })
- t.Run("Copy[]uint", func(t *testing.T) {
- original := []uint{1, 2, 3, 4, 5}
- copied, err := Copy(original)
- assert.NoError(t, err)
- cpyU := copied.([]uint)
- assert.False(t, hasSameDataPointer(original, cpyU), "expected different memory addresses")
- assert.Equal(t, len(original), len(cpyU), "length should match")
- assert.Equal(t, original, cpyU, "content should match")
- })
- t.Run("Copy[]float32", func(t *testing.T) {
- original := []float32{3.14}
- copied, err := Copy(original)
- assert.NoError(t, err)
- cpyF := copied.([]float32)
- assert.False(t, hasSameDataPointer(original, cpyF), "expected different memory addresses")
- assert.Equal(t, len(original), len(cpyF), "length should match")
- assert.Equal(t, original, cpyF, "content should match")
- })
- t.Run("Copy[]interface{}", func(t *testing.T) {
- original := []interface{}{"a", 42, true, 4.32}
- copied, err := Copy(original)
- assert.NoError(t, err)
- cpyIf := copied.([]interface{})
- assert.False(t, hasSameDataPointer(original, cpyIf), "expected different memory addresses")
- assert.Equal(t, len(original), len(cpyIf), "length should match")
- assert.Equal(t, original, cpyIf, "content should match")
- })
- }
- type Basics struct {
- String string
- Strings []string
- StringArr [4]string
- Bool bool
- Bools []bool
- Byte byte
- Bytes []byte
- Int int
- Ints []int
- Int8 int8
- Int8s []int8
- Int16 int16
- Int16s []int16
- Int32 int32
- Int32s []int32
- Int64 int64
- Int64s []int64
- Uint uint
- Uints []uint
- Uint8 uint8
- Uint8s []uint8
- Uint16 uint16
- Uint16s []uint16
- Uint32 uint32
- Uint32s []uint32
- Uint64 uint64
- Uint64s []uint64
- Float32 float32
- Float32s []float32
- Float64 float64
- Float64s []float64
- Complex64 complex64
- Complex64s []complex64
- Complex128 complex128
- Complex128s []complex128
- Interface interface{}
- Interfaces []interface{}
- }
- // These tests test that all supported basic types are copied correctly. This
- // is done by copying a struct with fields of most of the basic types as []T.
- func TestMostTypes(t *testing.T) {
- test := Basics{
- String: "kimchi",
- Strings: []string{"uni", "ika"},
- StringArr: [4]string{"malort", "barenjager", "fernet", "salmiakki"},
- Bool: true,
- Bools: []bool{true, false, true},
- Byte: 'z',
- Bytes: []byte("abc"),
- Int: 42,
- Ints: []int{0, 1, 3, 4},
- Int8: 8,
- Int8s: []int8{8, 9, 10},
- Int16: 16,
- Int16s: []int16{16, 17, 18, 19},
- Int32: 32,
- Int32s: []int32{32, 33},
- Int64: 64,
- Int64s: []int64{64},
- Uint: 420,
- Uints: []uint{11, 12, 13},
- Uint8: 81,
- Uint8s: []uint8{81, 82},
- Uint16: 160,
- Uint16s: []uint16{160, 161, 162, 163, 164},
- Uint32: 320,
- Uint32s: []uint32{320, 321},
- Uint64: 640,
- Uint64s: []uint64{6400, 6401, 6402, 6403},
- Float32: 32.32,
- Float32s: []float32{32.32, 33},
- Float64: 64.1,
- Float64s: []float64{64, 65, 66},
- Complex64: complex64(-64 + 12i),
- Complex64s: []complex64{complex64(-65 + 11i), complex64(66 + 10i)},
- Complex128: complex128(-128 + 12i),
- Complex128s: []complex128{complex128(-128 + 11i), complex128(129 + 10i)},
- Interfaces: []interface{}{42, true, "pan-galactic"},
- }
- cpy, err := Copy(test)
- if err != nil {
- t.Fatal(err)
- }
- cpyBasics := cpy.(Basics)
- // see if they point to the same location
- if fmt.Sprintf("%p", &cpyBasics) == fmt.Sprintf("%p", &test) {
- t.Error("address of copy was the same as original; they should be different")
- return
- }
- // Go through each field and check to see it got copied properly
- if cpyBasics.String != test.String {
- t.Errorf("String: got %v; want %v", cpyBasics.String, test.String)
- }
- if hasSameDataPointer(test.Strings, cpyBasics.Strings) {
- t.Error("Strings: address of copy was the same as original; they should be different")
- goto StringArr
- }
- if len(cpyBasics.Strings) != len(test.Strings) {
- t.Errorf("Strings: len was %d; want %d", len(cpyBasics.Strings), len(test.Strings))
- goto StringArr
- }
- for i, v := range test.Strings {
- if v != cpyBasics.Strings[i] {
- t.Errorf("Strings: got %v at index %d of the copy; want %v", cpyBasics.Strings[i], i, v)
- }
- }
- StringArr:
- if unsafe.Pointer(&test.StringArr) == unsafe.Pointer(&cpyBasics.StringArr) {
- t.Error("StringArr: address of copy was the same as original; they should be different")
- goto Bools
- }
- for i, v := range test.StringArr {
- if v != cpyBasics.StringArr[i] {
- t.Errorf("StringArr: got %v at index %d of the copy; want %v", cpyBasics.StringArr[i], i, v)
- }
- }
- Bools:
- if cpyBasics.Bool != test.Bool {
- t.Errorf("Bool: got %v; want %v", cpyBasics.Bool, test.Bool)
- }
- if hasSameDataPointer(test.Bools, cpyBasics.Bools) {
- t.Error("Bools: address of copy was the same as original; they should be different")
- goto Bytes
- }
- if len(cpyBasics.Bools) != len(test.Bools) {
- t.Errorf("Bools: len was %d; want %d", len(cpyBasics.Bools), len(test.Bools))
- goto Bytes
- }
- for i, v := range test.Bools {
- if v != cpyBasics.Bools[i] {
- t.Errorf("Bools: got %v at index %d of the copy; want %v", cpyBasics.Bools[i], i, v)
- }
- }
- Bytes:
- if cpyBasics.Byte != test.Byte {
- t.Errorf("Byte: got %v; want %v", cpyBasics.Byte, test.Byte)
- }
- if hasSameDataPointer(test.Bytes, cpyBasics.Bytes) {
- t.Error("Bytes: address of copy was the same as original; they should be different")
- goto Ints
- }
- if len(cpyBasics.Bytes) != len(test.Bytes) {
- t.Errorf("Bytes: len was %d; want %d", len(cpyBasics.Bytes), len(test.Bytes))
- goto Ints
- }
- for i, v := range test.Bytes {
- if v != cpyBasics.Bytes[i] {
- t.Errorf("Bytes: got %v at index %d of the copy; want %v", cpyBasics.Bytes[i], i, v)
- }
- }
- Ints:
- if cpyBasics.Int != test.Int {
- t.Errorf("Int: got %v; want %v", cpyBasics.Int, test.Int)
- }
- if hasSameDataPointer(test.Ints, cpyBasics.Ints) {
- t.Error("Ints: address of copy was the same as original; they should be different")
- goto Int8s
- }
- if len(cpyBasics.Ints) != len(test.Ints) {
- t.Errorf("Ints: len was %d; want %d", len(cpyBasics.Ints), len(test.Ints))
- goto Int8s
- }
- for i, v := range test.Ints {
- if v != cpyBasics.Ints[i] {
- t.Errorf("Ints: got %v at index %d of the copy; want %v", cpyBasics.Ints[i], i, v)
- }
- }
- Int8s:
- if cpyBasics.Int8 != test.Int8 {
- t.Errorf("Int8: got %v; want %v", cpyBasics.Int8, test.Int8)
- }
- if hasSameDataPointer(test.Int8s, cpyBasics.Int8s) {
- t.Error("Int8s: address of copy was the same as original; they should be different")
- goto Int16s
- }
- if len(cpyBasics.Int8s) != len(test.Int8s) {
- t.Errorf("Int8s: len was %d; want %d", len(cpyBasics.Int8s), len(test.Int8s))
- goto Int16s
- }
- for i, v := range test.Int8s {
- if v != cpyBasics.Int8s[i] {
- t.Errorf("Int8s: got %v at index %d of the copy; want %v", cpyBasics.Int8s[i], i, v)
- }
- }
- Int16s:
- if cpyBasics.Int16 != test.Int16 {
- t.Errorf("Int16: got %v; want %v", cpyBasics.Int16, test.Int16)
- }
- if hasSameDataPointer(test.Int16s, cpyBasics.Int16s) {
- t.Error("Int16s: address of copy was the same as original; they should be different")
- goto Int32s
- }
- if len(cpyBasics.Int16s) != len(test.Int16s) {
- t.Errorf("Int16s: len was %d; want %d", len(cpyBasics.Int16s), len(test.Int16s))
- goto Int32s
- }
- for i, v := range test.Int16s {
- if v != cpyBasics.Int16s[i] {
- t.Errorf("Int16s: got %v at index %d of the copy; want %v", cpyBasics.Int16s[i], i, v)
- }
- }
- Int32s:
- if cpyBasics.Int32 != test.Int32 {
- t.Errorf("Int32: got %v; want %v", cpyBasics.Int32, test.Int32)
- }
- if hasSameDataPointer(test.Int32s, cpyBasics.Int32s) {
- t.Error("Int32s: address of copy was the same as original; they should be different")
- goto Int64s
- }
- if len(cpyBasics.Int32s) != len(test.Int32s) {
- t.Errorf("Int32s: len was %d; want %d", len(cpyBasics.Int32s), len(test.Int32s))
- goto Int64s
- }
- for i, v := range test.Int32s {
- if v != cpyBasics.Int32s[i] {
- t.Errorf("Int32s: got %v at index %d of the copy; want %v", cpyBasics.Int32s[i], i, v)
- }
- }
- Int64s:
- if cpyBasics.Int64 != test.Int64 {
- t.Errorf("Int64: got %v; want %v", cpyBasics.Int64, test.Int64)
- }
- if hasSameDataPointer(test.Int64s, cpyBasics.Int64s) {
- t.Error("Int64s: address of copy was the same as original; they should be different")
- goto Uints
- }
- if len(cpyBasics.Int64s) != len(test.Int64s) {
- t.Errorf("Int64s: len was %d; want %d", len(cpyBasics.Int64s), len(test.Int64s))
- goto Uints
- }
- for i, v := range test.Int64s {
- if v != cpyBasics.Int64s[i] {
- t.Errorf("Int64s: got %v at index %d of the copy; want %v", cpyBasics.Int64s[i], i, v)
- }
- }
- Uints:
- if cpyBasics.Uint != test.Uint {
- t.Errorf("Uint: got %v; want %v", cpyBasics.Uint, test.Uint)
- }
- if hasSameDataPointer(test.Uints, cpyBasics.Uints) {
- t.Error("Uints: address of copy was the same as original; they should be different")
- goto Uint8s
- }
- if len(cpyBasics.Uints) != len(test.Uints) {
- t.Errorf("Uints: len was %d; want %d", len(cpyBasics.Uints), len(test.Uints))
- goto Uint8s
- }
- for i, v := range test.Uints {
- if v != cpyBasics.Uints[i] {
- t.Errorf("Uints: got %v at index %d of the copy; want %v", cpyBasics.Uints[i], i, v)
- }
- }
- Uint8s:
- if cpyBasics.Uint8 != test.Uint8 {
- t.Errorf("Uint8: got %v; want %v", cpyBasics.Uint8, test.Uint8)
- }
- if hasSameDataPointer(test.Uint8s, cpyBasics.Uint8s) {
- t.Error("Uint8s: address of copy was the same as original; they should be different")
- goto Uint16s
- }
- if len(cpyBasics.Uint8s) != len(test.Uint8s) {
- t.Errorf("Uint8s: len was %d; want %d", len(cpyBasics.Uint8s), len(test.Uint8s))
- goto Uint16s
- }
- for i, v := range test.Uint8s {
- if v != cpyBasics.Uint8s[i] {
- t.Errorf("Uint8s: got %v at index %d of the copy; want %v", cpyBasics.Uint8s[i], i, v)
- }
- }
- Uint16s:
- if cpyBasics.Uint16 != test.Uint16 {
- t.Errorf("Uint16: got %v; want %v", cpyBasics.Uint16, test.Uint16)
- }
- if hasSameDataPointer(test.Uint16s, cpyBasics.Uint16s) {
- t.Error("Uint16s: address of copy was the same as original; they should be different")
- goto Uint32s
- }
- if len(cpyBasics.Uint16s) != len(test.Uint16s) {
- t.Errorf("Uint16s: len was %d; want %d", len(cpyBasics.Uint16s), len(test.Uint16s))
- goto Uint32s
- }
- for i, v := range test.Uint16s {
- if v != cpyBasics.Uint16s[i] {
- t.Errorf("Uint16s: got %v at index %d of the copy; want %v", cpyBasics.Uint16s[i], i, v)
- }
- }
- Uint32s:
- if cpyBasics.Uint32 != test.Uint32 {
- t.Errorf("Uint32: got %v; want %v", cpyBasics.Uint32, test.Uint32)
- }
- if hasSameDataPointer(test.Uint32s, cpyBasics.Uint32s) {
- t.Error("Uint32s: address of copy was the same as original; they should be different")
- goto Uint64s
- }
- if len(cpyBasics.Uint32s) != len(test.Uint32s) {
- t.Errorf("Uint32s: len was %d; want %d", len(cpyBasics.Uint32s), len(test.Uint32s))
- goto Uint64s
- }
- for i, v := range test.Uint32s {
- if v != cpyBasics.Uint32s[i] {
- t.Errorf("Uint32s: got %v at index %d of the copy; want %v", cpyBasics.Uint32s[i], i, v)
- }
- }
- Uint64s:
- if cpyBasics.Uint64 != test.Uint64 {
- t.Errorf("Uint64: got %v; want %v", cpyBasics.Uint64, test.Uint64)
- }
- if hasSameDataPointer(test.Uint64s, cpyBasics.Uint64s) {
- t.Error("Uint64s: address of copy was the same as original; they should be different")
- goto Float32s
- }
- if len(cpyBasics.Uint64s) != len(test.Uint64s) {
- t.Errorf("Uint64s: len was %d; want %d", len(cpyBasics.Uint64s), len(test.Uint64s))
- goto Float32s
- }
- for i, v := range test.Uint64s {
- if v != cpyBasics.Uint64s[i] {
- t.Errorf("Uint64s: got %v at index %d of the copy; want %v", cpyBasics.Uint64s[i], i, v)
- }
- }
- Float32s:
- if cpyBasics.Float32 != test.Float32 {
- t.Errorf("Float32: got %v; want %v", cpyBasics.Float32, test.Float32)
- }
- if hasSameDataPointer(test.Float32s, cpyBasics.Float32s) {
- t.Error("Float32s: address of copy was the same as original; they should be different")
- goto Float64s
- }
- if len(cpyBasics.Float32s) != len(test.Float32s) {
- t.Errorf("Float32s: len was %d; want %d", len(cpyBasics.Float32s), len(test.Float32s))
- goto Float64s
- }
- for i, v := range test.Float32s {
- if v != cpyBasics.Float32s[i] {
- t.Errorf("Float32s: got %v at index %d of the copy; want %v", cpyBasics.Float32s[i], i, v)
- }
- }
- Float64s:
- if cpyBasics.Float64 != test.Float64 {
- t.Errorf("Float64: got %v; want %v", cpyBasics.Float64, test.Float64)
- }
- if hasSameDataPointer(test.Float64s, cpyBasics.Float64s) {
- t.Error("Float64s: address of copy was the same as original; they should be different")
- goto Complex64s
- }
- if len(cpyBasics.Float64s) != len(test.Float64s) {
- t.Errorf("Float64s: len was %d; want %d", len(cpyBasics.Float64s), len(test.Float64s))
- goto Complex64s
- }
- for i, v := range test.Float64s {
- if v != cpyBasics.Float64s[i] {
- t.Errorf("Float64s: got %v at index %d of the copy; want %v", cpyBasics.Float64s[i], i, v)
- }
- }
- Complex64s:
- if cpyBasics.Complex64 != test.Complex64 {
- t.Errorf("Complex64: got %v; want %v", cpyBasics.Complex64, test.Complex64)
- }
- if hasSameDataPointer(test.Complex64s, cpyBasics.Complex64s) {
- t.Error("Complex64s: address of copy was the same as original; they should be different")
- goto Complex128s
- }
- if len(cpyBasics.Complex64s) != len(test.Complex64s) {
- t.Errorf("Complex64s: len was %d; want %d", len(cpyBasics.Complex64s), len(test.Complex64s))
- goto Complex128s
- }
- for i, v := range test.Complex64s {
- if v != cpyBasics.Complex64s[i] {
- t.Errorf("Complex64s: got %v at index %d of the copy; want %v", cpyBasics.Complex64s[i], i, v)
- }
- }
- Complex128s:
- if cpyBasics.Complex128 != test.Complex128 {
- t.Errorf("Complex128s: got %v; want %v", cpyBasics.Complex128s, test.Complex128s)
- }
- if hasSameDataPointer(test.Complex128s, cpyBasics.Complex128s) {
- t.Error("Complex128s: address of copy was the same as original; they should be different")
- goto Interfaces
- }
- if len(cpyBasics.Complex128s) != len(test.Complex128s) {
- t.Errorf("Complex128s: len was %d; want %d", len(cpyBasics.Complex128s), len(test.Complex128s))
- goto Interfaces
- }
- for i, v := range test.Complex128s {
- if v != cpyBasics.Complex128s[i] {
- t.Errorf("Complex128s: got %v at index %d of the copy; want %v", cpyBasics.Complex128s[i], i, v)
- }
- }
- Interfaces:
- if cpyBasics.Interface != test.Interface {
- t.Errorf("Interface: got %v; want %v", cpyBasics.Interface, test.Interface)
- }
- if hasSameDataPointer(test.Interfaces, cpyBasics.Interfaces) {
- t.Error("Interfaces: address of copy was the same as original; they should be different")
- return
- }
- if len(cpyBasics.Interfaces) != len(test.Interfaces) {
- t.Errorf("Interfaces: len was %d; want %d", len(cpyBasics.Interfaces), len(test.Interfaces))
- return
- }
- for i, v := range test.Interfaces {
- if v != cpyBasics.Interfaces[i] {
- t.Errorf("Interfaces: got %v at index %d of the copy; want %v", cpyBasics.Interfaces[i], i, v)
- }
- }
- }
- type A struct {
- Int int
- String string
- UintSl []uint
- NilSl []string
- Map map[string]int
- MapB map[string]*B
- SliceB []B
- B
- T time.Time
- }
- type B struct {
- Vals []string
- }
- type C struct {
- Vals []string
- }
- var AStruct = A{
- Int: 42,
- String: "Konichiwa",
- UintSl: []uint{0, 1, 2, 3},
- Map: map[string]int{"a": 1, "b": 2},
- MapB: map[string]*B{
- "hi": &B{Vals: []string{"hello", "bonjour"}},
- "bye": &B{Vals: []string{"good-bye", "au revoir"}},
- },
- SliceB: []B{
- B{Vals: []string{"Ciao", "Aloha"}},
- },
- B: B{Vals: []string{"42"}},
- T: time.Now(),
- }
- func TestStructA(t *testing.T) {
- cpy, err := Copy(&AStruct)
- if err != nil {
- t.Fatal(err)
- }
- cpyA := cpy.(*A)
- if cpyA == &AStruct {
- t.Error("expected copy to have a different address than the original; it was the same")
- return
- }
- if cpyA.Int != AStruct.Int {
- t.Errorf("A.Int: got %v, want %v", cpyA.Int, AStruct.Int)
- }
- if cpyA.String != AStruct.String {
- t.Errorf("A.String: got %v; want %v", cpyA.String, AStruct.String)
- }
- if hasSameDataPointer(AStruct.UintSl, cpyA.UintSl) {
- t.Error("A.Uintsl: expected the copies address to be different; it wasn't")
- goto NilSl
- }
- if len(cpyA.UintSl) != len(AStruct.UintSl) {
- t.Errorf("A.UintSl: got len of %d, want %d", len(cpyA.UintSl), len(AStruct.UintSl))
- goto NilSl
- }
- for i, v := range AStruct.UintSl {
- if cpyA.UintSl[i] != v {
- t.Errorf("A.UintSl %d: got %d, want %d", i, cpyA.UintSl[i], v)
- }
- }
- NilSl:
- if cpyA.NilSl != nil {
- t.Error("A.NilSl: expected slice to be nil, it wasn't")
- }
- if *(*uintptr)(unsafe.Pointer(&cpyA.Map)) == *(*uintptr)(unsafe.Pointer(&AStruct.Map)) {
- t.Error("A.Map: expected the copy's address to be different; it wasn't")
- goto AMapB
- }
- if len(cpyA.Map) != len(AStruct.Map) {
- t.Errorf("A.Map: got len of %d, want %d", len(cpyA.Map), len(AStruct.Map))
- goto AMapB
- }
- for k, v := range AStruct.Map {
- val, ok := cpyA.Map[k]
- if !ok {
- t.Errorf("A.Map: expected the key %s to exist in the copy, it didn't", k)
- continue
- }
- if val != v {
- t.Errorf("A.Map[%s]: got %d, want %d", k, val, v)
- }
- }
- AMapB:
- if *(*uintptr)(unsafe.Pointer(&cpyA.MapB)) == *(*uintptr)(unsafe.Pointer(&AStruct.MapB)) {
- t.Error("A.MapB: expected the copy's address to be different; it wasn't")
- goto ASliceB
- }
- if len(cpyA.MapB) != len(AStruct.MapB) {
- t.Errorf("A.MapB: got len of %d, want %d", len(cpyA.MapB), len(AStruct.MapB))
- goto ASliceB
- }
- for k, v := range AStruct.MapB {
- val, ok := cpyA.MapB[k]
- if !ok {
- t.Errorf("A.MapB: expected the key %s to exist in the copy, it didn't", k)
- continue
- }
- if unsafe.Pointer(val) == unsafe.Pointer(v) {
- t.Errorf("A.MapB[%s]: expected the addresses of the values to be different; they weren't", k)
- continue
- }
- // the slice headers should point to different data
- if hasSameDataPointer(v.Vals, val.Vals) {
- t.Errorf("%s: expected B's SliceHeaders to point to different Data locations; they did not.", k)
- continue
- }
- for i, vv := range v.Vals {
- if vv != val.Vals[i] {
- t.Errorf("A.MapB[%s].Vals[%d]: got %s want %s", k, i, vv, val.Vals[i])
- }
- }
- }
- ASliceB:
- if hasSameDataPointer(AStruct.SliceB, cpyA.SliceB) {
- t.Error("A.SliceB: expected the copy's address to be different; it wasn't")
- goto B
- }
- if len(AStruct.SliceB) != len(cpyA.SliceB) {
- t.Errorf("A.SliceB: got length of %d; want %d", len(cpyA.SliceB), len(AStruct.SliceB))
- goto B
- }
- for i := range AStruct.SliceB {
- if unsafe.Pointer(&AStruct.SliceB[i]) == unsafe.Pointer(&cpyA.SliceB[i]) {
- t.Errorf("A.SliceB[%d]: expected them to have different addresses, they didn't", i)
- continue
- }
- if hasSameDataPointer(AStruct.SliceB[i].Vals, cpyA.SliceB[i].Vals) {
- t.Errorf("A.SliceB[%d]: expected B.Vals SliceHeader.Data to point to different locations; they did not", i)
- continue
- }
- if len(AStruct.SliceB[i].Vals) != len(cpyA.SliceB[i].Vals) {
- t.Errorf("A.SliceB[%d]: expected B's vals to have the same length, they didn't", i)
- continue
- }
- for j, val := range AStruct.SliceB[i].Vals {
- if val != cpyA.SliceB[i].Vals[j] {
- t.Errorf("A.SliceB[%d].Vals[%d]: got %v; want %v", i, j, cpyA.SliceB[i].Vals[j], val)
- }
- }
- }
- B:
- if unsafe.Pointer(&AStruct.B) == unsafe.Pointer(&cpyA.B) {
- t.Error("A.B: expected them to have different addresses, they didn't")
- goto T
- }
- if hasSameDataPointer(AStruct.B.Vals, cpyA.B.Vals) {
- t.Error("A.B.Vals: expected the SliceHeaders.Data to point to different locations; they didn't")
- goto T
- }
- if len(AStruct.B.Vals) != len(cpyA.B.Vals) {
- t.Error("A.B.Vals: expected their lengths to be the same, they weren't")
- goto T
- }
- for i, v := range AStruct.B.Vals {
- if v != cpyA.B.Vals[i] {
- t.Errorf("A.B.Vals[%d]: got %s want %s", i, cpyA.B.Vals[i], v)
- }
- }
- T:
- if fmt.Sprintf("%p", &AStruct.T) == fmt.Sprintf("%p", &cpyA.T) {
- t.Error("A.T: expected them to have different addresses, they didn't")
- return
- }
- if AStruct.T != cpyA.T {
- t.Errorf("A.T: got %v, want %v", cpyA.T, AStruct.T)
- }
- }
- type Unexported struct {
- A string
- B int
- aa string
- bb int
- cc []int
- dd map[string]string
- }
- func TestUnexportedFields(t *testing.T) {
- u := &Unexported{
- A: "A",
- B: 42,
- aa: "aa",
- bb: 42,
- cc: []int{1, 2, 3},
- dd: map[string]string{"hello": "bonjour"},
- }
- cpy, err := Copy(u)
- if err != nil {
- t.Fatal(err)
- }
- cpyUnexported := cpy.(*Unexported)
- if cpyUnexported == u {
- t.Error("expected addresses to be different, they weren't")
- return
- }
- if u.A != cpyUnexported.A {
- t.Errorf("Unexported.A: got %s want %s", cpyUnexported.A, u.A)
- }
- if u.B != cpyUnexported.B {
- t.Errorf("Unexported.A: got %d want %d", cpyUnexported.B, u.B)
- }
- if cpyUnexported.aa != "" {
- t.Errorf("Unexported.aa: unexported field should not be set, it was set to %s", cpyUnexported.aa)
- }
- if cpyUnexported.bb != 0 {
- t.Errorf("Unexported.bb: unexported field should not be set, it was set to %d", cpyUnexported.bb)
- }
- if cpyUnexported.cc != nil {
- t.Errorf("Unexported.cc: unexported field should not be set, it was set to %#v", cpyUnexported.cc)
- }
- if cpyUnexported.dd != nil {
- t.Errorf("Unexported.dd: unexported field should not be set, it was set to %#v", cpyUnexported.dd)
- }
- }
- // Note: this test will fail until https://github.com/golang/go/issues/15716 is
- // fixed and the version it is part of gets released.
- type T struct {
- time.Time
- }
- func TestTimeCopy(t *testing.T) {
- tests := []struct {
- Y int
- M time.Month
- D int
- h int
- m int
- s int
- nsec int
- TZ string
- }{
- {2016, time.July, 4, 23, 11, 33, 3000, "America/New_York"},
- {2015, time.October, 31, 9, 44, 23, 45935, "UTC"},
- {2014, time.May, 5, 22, 01, 50, 219300, "Europe/Prague"},
- }
- for i, test := range tests {
- l, err := time.LoadLocation(test.TZ)
- if err != nil {
- t.Errorf("%d: unexpected error: %s", i, err)
- continue
- }
- var x T
- x.Time = time.Date(test.Y, test.M, test.D, test.h, test.m, test.s, test.nsec, l)
- c, err := Copy(x)
- if err != nil {
- t.Fatal(err)
- }
- cpy := c.(T)
- if fmt.Sprintf("%p", &cpy) == fmt.Sprintf("%p", &x) {
- t.Errorf("%d: expected the copy to have a different address than the original value; they were the same: %p %p", i, &cpy, &x)
- continue
- }
- if x.UnixNano() != cpy.UnixNano() {
- t.Errorf("%d: nanotime: got %v; want %v", i, cpy.UnixNano(), x.UnixNano())
- continue
- }
- if x.Location() != cpy.Location() {
- t.Errorf("%d: location: got %q; want %q", i, cpy.Location(), x.Location())
- }
- }
- }
- func TestPointerToStruct(t *testing.T) {
- type Foo struct {
- Bar int
- }
- f := &Foo{Bar: 42}
- cpy, err := Copy(f)
- if err != nil {
- t.Fatal(err)
- }
- if f == cpy {
- t.Errorf("expected copy to point to a different location: orig: %p; copy: %p", f, cpy)
- }
- if !reflect.DeepEqual(f, cpy) {
- t.Errorf("expected the copy to be equal to the original (except for memory location); it wasn't: got %#v; want %#v", f, cpy)
- }
- }
- func TestIssue9(t *testing.T) {
- // simple pointer copy
- x := 42
- testA := map[string]*int{
- "a": nil,
- "b": &x,
- }
- copyA1, err := Copy(testA)
- if err != nil {
- t.Fatal(err)
- }
- copyA := copyA1.(map[string]*int)
- if unsafe.Pointer(&testA) == unsafe.Pointer(©A) {
- t.Fatalf("expected the map pointers to be different: testA: %v\tcopyA: %v", unsafe.Pointer(&testA), unsafe.Pointer(©A))
- }
- if !reflect.DeepEqual(testA, copyA) {
- t.Errorf("got %#v; want %#v", copyA, testA)
- }
- if testA["b"] == copyA["b"] {
- t.Errorf("entries for 'b' pointed to the same address: %v; expected them to point to different addresses", testA["b"])
- }
- // map copy
- type Foo struct {
- Alpha string
- }
- type Bar struct {
- Beta string
- Gamma int
- Delta *Foo
- }
- type Biz struct {
- Epsilon map[int]*Bar
- }
- testB := Biz{
- Epsilon: map[int]*Bar{
- 0: &Bar{},
- 1: &Bar{
- Beta: "don't panic",
- Gamma: 42,
- Delta: nil,
- },
- 2: &Bar{
- Beta: "sudo make me a sandwich.",
- Gamma: 11,
- Delta: &Foo{
- Alpha: "okay.",
- },
- },
- },
- }
- copyB1, err := Copy(testB)
- if err != nil {
- t.Fatal(err)
- }
- copyB := copyB1.(Biz)
- if !reflect.DeepEqual(testB, copyB) {
- t.Errorf("got %#v; want %#v", copyB, testB)
- return
- }
- // check that the maps point to different locations
- if unsafe.Pointer(&testB.Epsilon) == unsafe.Pointer(©B.Epsilon) {
- t.Fatalf("expected the map pointers to be different; they weren't: testB: %v\tcopyB: %v", unsafe.Pointer(&testB.Epsilon), unsafe.Pointer(©B.Epsilon))
- }
- for k, v := range testB.Epsilon {
- if v == nil && copyB.Epsilon[k] == nil {
- continue
- }
- if v == nil && copyB.Epsilon[k] != nil {
- t.Errorf("%d: expected copy of a nil entry to be nil; it wasn't: %#v", k, copyB.Epsilon[k])
- continue
- }
- if v == copyB.Epsilon[k] {
- t.Errorf("entries for '%d' pointed to the same address: %v; expected them to point to different addresses", k, v)
- continue
- }
- if v.Beta != copyB.Epsilon[k].Beta {
- t.Errorf("%d.Beta: got %q; want %q", k, copyB.Epsilon[k].Beta, v.Beta)
- }
- if v.Gamma != copyB.Epsilon[k].Gamma {
- t.Errorf("%d.Gamma: got %d; want %d", k, copyB.Epsilon[k].Gamma, v.Gamma)
- }
- if v.Delta == nil && copyB.Epsilon[k].Delta == nil {
- continue
- }
- if v.Delta == nil && copyB.Epsilon[k].Delta != nil {
- t.Errorf("%d.Delta: got %#v; want nil", k, copyB.Epsilon[k].Delta)
- }
- if v.Delta == copyB.Epsilon[k].Delta {
- t.Errorf("%d.Delta: expected the pointers to be different, they were the same: %v", k, v.Delta)
- continue
- }
- if v.Delta.Alpha != copyB.Epsilon[k].Delta.Alpha {
- t.Errorf("%d.Delta.Foo: got %q; want %q", k, v.Delta.Alpha, copyB.Epsilon[k].Delta.Alpha)
- }
- }
- // test that map keys are deep copied
- testC := map[*Foo][]string{
- &Foo{Alpha: "Henry Dorsett Case"}: []string{
- "Cutter",
- },
- &Foo{Alpha: "Molly Millions"}: []string{
- "Rose Kolodny",
- "Cat Mother",
- "Steppin' Razor",
- },
- }
- copyC1, err := Copy(testC)
- if err != nil {
- t.Fatal(err)
- }
- copyC := copyC1.(map[*Foo][]string)
- if unsafe.Pointer(&testC) == unsafe.Pointer(©C) {
- t.Fatalf("expected the map pointers to be different; they weren't: testB: %v\tcopyB: %v", unsafe.Pointer(&testB.Epsilon), unsafe.Pointer(©B.Epsilon))
- }
- // make sure the lengths are the same
- if len(testC) != len(copyC) {
- t.Fatalf("got len %d; want %d", len(copyC), len(testC))
- }
- // check that everything was deep copied: since the key is a pointer, we check to
- // see if the pointers are different but the values being pointed to are the same.
- for k, v := range testC {
- for kk, vv := range copyC {
- if *kk == *k {
- if kk == k {
- t.Errorf("key pointers should be different: orig: %p; copy: %p", k, kk)
- }
- // check that the slices are the same but different
- if !reflect.DeepEqual(v, vv) {
- t.Errorf("expected slice contents to be the same; they weren't: orig: %v; copy: %v", v, vv)
- }
- if hasSameDataPointer(v, vv) {
- t.Errorf("expected the SliceHeaders.Data to point to different locations; they didn't: %v", (*reflect.SliceHeader)(unsafe.Pointer(&v)).Data)
- }
- break
- }
- }
- }
- type Bizz struct {
- *Foo
- }
- testD := map[Bizz]string{
- Bizz{&Foo{"Neuromancer"}}: "Rio",
- Bizz{&Foo{"Wintermute"}}: "Berne",
- }
- copyD1, err := Copy(testD)
- if err != nil {
- t.Fatal(err)
- }
- copyD := copyD1.(map[Bizz]string)
- if len(copyD) != len(testD) {
- t.Fatalf("copy had %d elements; expected %d", len(copyD), len(testD))
- }
- for k, v := range testD {
- var found bool
- for kk, vv := range copyD {
- if reflect.DeepEqual(k, kk) {
- found = true
- // check that Foo points to different locations
- if unsafe.Pointer(k.Foo) == unsafe.Pointer(kk.Foo) {
- t.Errorf("Expected Foo to point to different locations; they didn't: orig: %p; copy %p", k.Foo, kk.Foo)
- break
- }
- if *k.Foo != *kk.Foo {
- t.Errorf("Expected copy of the key's Foo field to have the same value as the original, it wasn't: orig: %#v; copy: %#v", k.Foo, kk.Foo)
- }
- if v != vv {
- t.Errorf("Expected the values to be the same; the weren't: got %v; want %v", vv, v)
- }
- }
- }
- if !found {
- t.Errorf("expected key %v to exist in the copy; it didn't", k)
- }
- }
- }
- type I struct {
- A string
- }
- func (i *I) DeepCopy() interface{} {
- return &I{A: "custom copy"}
- }
- type NestI struct {
- I *I
- }
- func TestInterface(t *testing.T) {
- i := &I{A: "A"}
- copied, err := Copy(i)
- if err != nil {
- t.Fatal(err)
- }
- copiedI := copied.(*I)
- if copiedI.A != "custom copy" {
- t.Errorf("expected value %v, but it's %v", "custom copy", copiedI.A)
- }
- // check for nesting values
- ni := &NestI{I: &I{A: "A"}}
- copiedNest, err := Copy(ni)
- if err != nil {
- t.Fatal(err)
- }
- copiedNestI := copiedNest.(*NestI)
- if copiedNestI.I.A != "custom copy" {
- t.Errorf("expected value %v, but it's %v", "custom copy", copiedNestI.I.A)
- }
- }
- func TestArray(t *testing.T) {
- type A [3][][]float64
- var a = A{
- {
- {
- 1.0,
- 2.0,
- 3.0,
- },
- },
- }
- distination, err := Copy(a)
- if err != nil {
- t.Fatal(err)
- }
- a[0][0][0] = 4.0
- a[0][0][1] = 5.0
- a[0][0][2] = 6.0
- if distination.(A)[0][0][0] == a[0][0][0] {
- t.Fatal("Isn't deepcopied!", distination, a)
- }
- type I struct {
- I1 string
- }
- type B [3][]*I
- i := I{I1: "123"}
- var b = B{
- {
- &i,
- },
- }
- cb, err := Copy(b)
- if err != nil {
- t.Fatal(err)
- }
- i2 := I{I1: "456"}
- b[0][0] = &i2
- if cb.(B)[0][0] == b[0][0] {
- t.Fatal("Isn't deepcopied!", distination, a)
- }
- }
- func TestDeepcopy2(t *testing.T) {
- {
- type a [1][]int
- var source = a{
- {
- 1,
- },
- }
- destination, err := Copy(source)
- if err != nil {
- t.Fatal(err)
- }
- if destination.(a)[0][0] != source[0][0] {
- t.Errorf("expected value %v, but it's %v", source[0][0], destination.(a)[0][0])
- }
- source[0][0] = 0
- if destination.(a)[0][0] == source[0][0] {
- t.Error("Fatal Isn't deepcopied!", destination, source)
- }
- }
- {
- type a [3][][]float64
- var source = a{
- {
- {
- 1.0,
- 2.0,
- 3.0,
- },
- },
- }
- distination, err := Copy(source)
- if err != nil {
- t.Fatal(err)
- }
- if distination.(a)[0][0][0] != source[0][0][0] {
- t.Errorf("expected value %v, but it's %v", source[0][0][0], distination.(a)[0][0][0])
- }
- source[0][0][0] = 4.0
- source[0][0][1] = 5.0
- source[0][0][2] = 6.0
- if distination.(a)[0][0][0] == source[0][0][0] {
- t.Error("Fatal Isn't deepcopied!", distination, source)
- }
- }
- }
- func TestArrayOfSomething(t *testing.T) {
- verifyCases := map[string]struct {
- modifyAndVerify func(t *testing.T)
- }{
- // failed because the map(underlying is a pointer) will be copied directly
- "array of map": {
- modifyAndVerify: func(t *testing.T) {
- origin := [1]map[string]int{
- {
- "1": 1,
- },
- }
- copied, err := Copy(origin)
- if err != nil {
- t.Fatal(err)
- }
- assert.NotSame(t, &origin, &copied)
- assert.Equal(t, origin, copied)
- origin[0]["1"] = 999
- assert.Equal(t, 1, copied.([1]map[string]int)[0]["1"])
- },
- },
- // failed because the pointer of map will be copied directly
- "array of *map": {
- modifyAndVerify: func(t *testing.T) {
- origin := [1]*map[string]int{
- {
- "1": 1,
- },
- }
- copied, err := Copy(origin)
- if err != nil {
- t.Fatal(err)
- }
- assert.NotSame(t, origin, copied)
- assert.Equal(t, origin, copied)
- (*origin[0])["1"] = 999
- assert.Equal(t, 1, (*copied.([1]*map[string]int)[0])["1"])
- },
- },
- // failed because the pointer of int will be copied directly
- "array of *int": {
- modifyAndVerify: func(t *testing.T) {
- intp := func(i int) *int {
- return &i
- }
- arrayOfInt := [3]*int{intp(1), intp(2)}
- copied1, err := Copy(&arrayOfInt)
- if err != nil {
- t.Fatal(err)
- }
- copied := copied1.(*[3]*int)
- assert.NotSame(t, &arrayOfInt, copied)
- assert.NotSame(t, arrayOfInt[0], copied[0])
- assert.Equal(t, arrayOfInt[0], copied[0])
- arrayOfInt[0] = intp(999)
- assert.Equal(t, 1, *copied[0])
- },
- },
- // succeed because int will be copied by value
- "array of int": {
- modifyAndVerify: func(t *testing.T) {
- arrayOfInt := [3]int{1, 2}
- copied, err := Copy(&arrayOfInt)
- if err != nil {
- t.Fatal(err)
- }
- assert.NotSame(t, &arrayOfInt, copied)
- assert.Equal(t, arrayOfInt[0], copied.(*[3]int)[0])
- arrayOfInt[0] = 999
- assert.Equal(t, 1, copied.(*[3]int)[0])
- },
- },
- }
- for key, tt := range verifyCases {
- t.Run(key, tt.modifyAndVerify)
- }
- }
|