| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216 |
- // Copyright (c) Tailscale Inc & AUTHORS
- // SPDX-License-Identifier: BSD-3-Clause
- package main
- import (
- "reflect"
- "testing"
- "tailscale.com/cmd/cloner/clonerex"
- )
- func TestSliceContainer(t *testing.T) {
- num := 5
- examples := []struct {
- name string
- in *clonerex.SliceContainer
- }{
- {
- name: "nil",
- in: nil,
- },
- {
- name: "zero",
- in: &clonerex.SliceContainer{},
- },
- {
- name: "empty",
- in: &clonerex.SliceContainer{
- Slice: []*int{},
- },
- },
- {
- name: "nils",
- in: &clonerex.SliceContainer{
- Slice: []*int{nil, nil, nil, nil, nil},
- },
- },
- {
- name: "one",
- in: &clonerex.SliceContainer{
- Slice: []*int{&num},
- },
- },
- {
- name: "several",
- in: &clonerex.SliceContainer{
- Slice: []*int{&num, &num, &num, &num, &num},
- },
- },
- }
- for _, ex := range examples {
- t.Run(ex.name, func(t *testing.T) {
- out := ex.in.Clone()
- if !reflect.DeepEqual(ex.in, out) {
- t.Errorf("Clone() = %v, want %v", out, ex.in)
- }
- })
- }
- }
- func TestInterfaceContainer(t *testing.T) {
- examples := []struct {
- name string
- in *clonerex.InterfaceContainer
- }{
- {
- name: "nil",
- in: nil,
- },
- {
- name: "zero",
- in: &clonerex.InterfaceContainer{},
- },
- {
- name: "with_interface",
- in: &clonerex.InterfaceContainer{
- Interface: &clonerex.CloneableImpl{Value: 42},
- },
- },
- {
- name: "with_nil_interface",
- in: &clonerex.InterfaceContainer{
- Interface: nil,
- },
- },
- }
- for _, ex := range examples {
- t.Run(ex.name, func(t *testing.T) {
- out := ex.in.Clone()
- if !reflect.DeepEqual(ex.in, out) {
- t.Errorf("Clone() = %v, want %v", out, ex.in)
- }
- // Verify no aliasing: modifying the clone should not affect the original
- if ex.in != nil && ex.in.Interface != nil {
- if impl, ok := out.Interface.(*clonerex.CloneableImpl); ok {
- impl.Value = 999
- if origImpl, ok := ex.in.Interface.(*clonerex.CloneableImpl); ok {
- if origImpl.Value == 999 {
- t.Errorf("Clone() aliased memory with original")
- }
- }
- }
- }
- })
- }
- }
- func TestMapWithPointers(t *testing.T) {
- num1, num2 := 42, 100
- orig := &clonerex.MapWithPointers{
- Nested: map[string]*int{
- "foo": &num1,
- "bar": &num2,
- },
- WithCloneMethod: map[string]*clonerex.SliceContainer{
- "container1": {Slice: []*int{&num1, &num2}},
- "container2": {Slice: []*int{&num1}},
- },
- CloneInterface: map[string]clonerex.Cloneable{
- "impl1": &clonerex.CloneableImpl{Value: 123},
- "impl2": &clonerex.CloneableImpl{Value: 456},
- },
- }
- cloned := orig.Clone()
- if !reflect.DeepEqual(orig, cloned) {
- t.Errorf("Clone() = %v, want %v", cloned, orig)
- }
- // Mutate cloned.Nested pointer values
- *cloned.Nested["foo"] = 999
- if *orig.Nested["foo"] == 999 {
- t.Errorf("Clone() aliased memory in Nested: original was modified")
- }
- // Mutate cloned.WithCloneMethod slice values
- *cloned.WithCloneMethod["container1"].Slice[0] = 888
- if *orig.WithCloneMethod["container1"].Slice[0] == 888 {
- t.Errorf("Clone() aliased memory in WithCloneMethod: original was modified")
- }
- // Mutate cloned.CloneInterface values
- if impl, ok := cloned.CloneInterface["impl1"].(*clonerex.CloneableImpl); ok {
- impl.Value = 777
- if origImpl, ok := orig.CloneInterface["impl1"].(*clonerex.CloneableImpl); ok {
- if origImpl.Value == 777 {
- t.Errorf("Clone() aliased memory in CloneInterface: original was modified")
- }
- }
- }
- }
- func TestDeeplyNestedMap(t *testing.T) {
- num := 123
- orig := &clonerex.DeeplyNestedMap{
- ThreeLevels: map[string]map[string]map[string]int{
- "a": {
- "b": {"c": 1, "d": 2},
- "e": {"f": 3},
- },
- "g": {
- "h": {"i": 4},
- },
- },
- FourLevels: map[string]map[string]map[string]map[string]*clonerex.SliceContainer{
- "l1a": {
- "l2a": {
- "l3a": {
- "l4a": {Slice: []*int{&num}},
- "l4b": {Slice: []*int{&num, &num}},
- },
- },
- },
- },
- }
- cloned := orig.Clone()
- if !reflect.DeepEqual(orig, cloned) {
- t.Errorf("Clone() = %v, want %v", cloned, orig)
- }
- // Mutate the clone's ThreeLevels map
- cloned.ThreeLevels["a"]["b"]["c"] = 777
- if orig.ThreeLevels["a"]["b"]["c"] == 777 {
- t.Errorf("Clone() aliased memory in ThreeLevels: original was modified")
- }
- // Mutate the clone's FourLevels map at the deepest pointer level
- *cloned.FourLevels["l1a"]["l2a"]["l3a"]["l4a"].Slice[0] = 666
- if *orig.FourLevels["l1a"]["l2a"]["l3a"]["l4a"].Slice[0] == 666 {
- t.Errorf("Clone() aliased memory in FourLevels: original was modified")
- }
- // Add a new top-level key to the clone's FourLevels map
- newNum := 999
- cloned.FourLevels["l1b"] = map[string]map[string]map[string]*clonerex.SliceContainer{
- "l2b": {
- "l3b": {
- "l4c": {Slice: []*int{&newNum}},
- },
- },
- }
- if _, exists := orig.FourLevels["l1b"]; exists {
- t.Errorf("Clone() aliased FourLevels map: new top-level key appeared in original")
- }
- // Add a new nested key to the clone's FourLevels map
- cloned.FourLevels["l1a"]["l2a"]["l3a"]["l4c"] = &clonerex.SliceContainer{Slice: []*int{&newNum}}
- if _, exists := orig.FourLevels["l1a"]["l2a"]["l3a"]["l4c"]; exists {
- t.Errorf("Clone() aliased FourLevels map: new nested key appeared in original")
- }
- }
|