Source file
src/unique/handle_test.go
1
2
3
4
5 package unique
6
7 import (
8 "fmt"
9 "internal/abi"
10 "reflect"
11 "runtime"
12 "strings"
13 "testing"
14 "time"
15 "unsafe"
16 )
17
18
19
20 type testString string
21 type testIntArray [4]int
22 type testEface any
23 type testStringArray [3]string
24 type testStringStruct struct {
25 a string
26 }
27 type testStringStructArrayStruct struct {
28 s [2]testStringStruct
29 }
30 type testStruct struct {
31 z float64
32 b string
33 }
34
35 func TestHandle(t *testing.T) {
36 testHandle[testString](t, "foo")
37 testHandle[testString](t, "bar")
38 testHandle[testString](t, "")
39 testHandle[testIntArray](t, [4]int{7, 77, 777, 7777})
40 testHandle[testEface](t, nil)
41 testHandle[testStringArray](t, [3]string{"a", "b", "c"})
42 testHandle[testStringStruct](t, testStringStruct{"x"})
43 testHandle[testStringStructArrayStruct](t, testStringStructArrayStruct{
44 s: [2]testStringStruct{testStringStruct{"y"}, testStringStruct{"z"}},
45 })
46 testHandle[testStruct](t, testStruct{0.5, "184"})
47 testHandle[testEface](t, testEface("hello"))
48 }
49
50 func testHandle[T comparable](t *testing.T, value T) {
51 name := reflect.TypeFor[T]().Name()
52 t.Run(fmt.Sprintf("%s/%#v", name, value), func(t *testing.T) {
53 t.Parallel()
54
55 v0 := Make(value)
56 v1 := Make(value)
57
58 if v0.Value() != v1.Value() {
59 t.Error("v0.Value != v1.Value")
60 }
61 if v0.Value() != value {
62 t.Errorf("v0.Value not %#v", value)
63 }
64 if v0 != v1 {
65 t.Error("v0 != v1")
66 }
67
68 drainMaps(t)
69 checkMapsFor(t, value)
70 })
71 }
72
73
74 func drainMaps(t *testing.T) {
75 t.Helper()
76
77 wait := make(chan struct{}, 1)
78
79
80
81
82
83 cleanupMu.Lock()
84 cleanupNotify = append(cleanupNotify, func() {
85 select {
86 case wait <- struct{}{}:
87 default:
88 }
89 })
90
91 runtime.GC()
92 cleanupMu.Unlock()
93
94
95 <-wait
96 }
97
98 func checkMapsFor[T comparable](t *testing.T, value T) {
99
100 typ := abi.TypeFor[T]()
101 a, ok := uniqueMaps.Load(typ)
102 if !ok {
103 return
104 }
105 m := a.(*uniqueMap[T])
106 wp, ok := m.Load(value)
107 if !ok {
108 return
109 }
110 if wp.Strong() != nil {
111 t.Errorf("value %v still referenced a handle (or tiny block?) ", value)
112 return
113 }
114 t.Errorf("failed to drain internal maps of %v", value)
115 }
116
117 func TestMakeClonesStrings(t *testing.T) {
118 s := strings.Clone("abcdefghijklmnopqrstuvwxyz")
119 ran := make(chan bool)
120 runtime.SetFinalizer(unsafe.StringData(s), func(_ *byte) {
121 ran <- true
122 })
123 h := Make(s)
124
125
126 runtime.GC()
127
128 select {
129 case <-time.After(1 * time.Second):
130 t.Fatal("string was improperly retained")
131 case <-ran:
132 }
133 runtime.KeepAlive(h)
134 }
135
View as plain text