...
Source file
src/weak/pointer_test.go
Documentation: weak
1
2
3
4
5 package weak_test
6
7 import (
8 "context"
9 "internal/goarch"
10 "runtime"
11 "sync"
12 "testing"
13 "time"
14 "unsafe"
15 "weak"
16 )
17
18 type T struct {
19
20
21 t *T
22 a int
23 }
24
25 func TestPointer(t *testing.T) {
26 var zero weak.Pointer[T]
27 if zero.Value() != nil {
28 t.Error("Value of zero value of weak.Pointer is not nil")
29 }
30 zeroNil := weak.Make[T](nil)
31 if zeroNil.Value() != nil {
32 t.Error("Value of weak.Make[T](nil) is not nil")
33 }
34
35 bt := new(T)
36 wt := weak.Make(bt)
37 if st := wt.Value(); st != bt {
38 t.Fatalf("weak pointer is not the same as strong pointer: %p vs. %p", st, bt)
39 }
40
41 runtime.GC()
42
43 if st := wt.Value(); st != bt {
44 t.Fatalf("weak pointer is not the same as strong pointer after GC: %p vs. %p", st, bt)
45 }
46
47 runtime.GC()
48
49 if st := wt.Value(); st != nil {
50 t.Fatalf("expected weak pointer to be nil, got %p", st)
51 }
52 }
53
54 func TestPointerEquality(t *testing.T) {
55 var zero weak.Pointer[T]
56 zeroNil := weak.Make[T](nil)
57 if zero != zeroNil {
58 t.Error("weak.Make[T](nil) != zero value of weak.Pointer[T]")
59 }
60
61 bt := make([]*T, 10)
62 wt := make([]weak.Pointer[T], 10)
63 wo := make([]weak.Pointer[int], 10)
64 for i := range bt {
65 bt[i] = new(T)
66 wt[i] = weak.Make(bt[i])
67 wo[i] = weak.Make(&bt[i].a)
68 }
69 for i := range bt {
70 st := wt[i].Value()
71 if st != bt[i] {
72 t.Fatalf("weak pointer is not the same as strong pointer: %p vs. %p", st, bt[i])
73 }
74 if wp := weak.Make(st); wp != wt[i] {
75 t.Fatalf("new weak pointer not equal to existing weak pointer: %v vs. %v", wp, wt[i])
76 }
77 if wp := weak.Make(&st.a); wp != wo[i] {
78 t.Fatalf("new weak pointer not equal to existing weak pointer: %v vs. %v", wp, wo[i])
79 }
80 if i == 0 {
81 continue
82 }
83 if wt[i] == wt[i-1] {
84 t.Fatalf("expected weak pointers to not be equal to each other, but got %v", wt[i])
85 }
86 }
87
88 runtime.GC()
89 for i := range bt {
90 st := wt[i].Value()
91 if st != bt[i] {
92 t.Fatalf("weak pointer is not the same as strong pointer: %p vs. %p", st, bt[i])
93 }
94 if wp := weak.Make(st); wp != wt[i] {
95 t.Fatalf("new weak pointer not equal to existing weak pointer: %v vs. %v", wp, wt[i])
96 }
97 if wp := weak.Make(&st.a); wp != wo[i] {
98 t.Fatalf("new weak pointer not equal to existing weak pointer: %v vs. %v", wp, wo[i])
99 }
100 if i == 0 {
101 continue
102 }
103 if wt[i] == wt[i-1] {
104 t.Fatalf("expected weak pointers to not be equal to each other, but got %v", wt[i])
105 }
106 }
107 bt = nil
108
109 runtime.GC()
110 for i := range bt {
111 st := wt[i].Value()
112 if st != nil {
113 t.Fatalf("expected weak pointer to be nil, got %p", st)
114 }
115 if i == 0 {
116 continue
117 }
118 if wt[i] == wt[i-1] {
119 t.Fatalf("expected weak pointers to not be equal to each other, but got %v", wt[i])
120 }
121 }
122 }
123
124 func TestPointerFinalizer(t *testing.T) {
125 bt := new(T)
126 wt := weak.Make(bt)
127 done := make(chan struct{}, 1)
128 runtime.SetFinalizer(bt, func(bt *T) {
129 if wt.Value() != nil {
130 t.Errorf("weak pointer did not go nil before finalizer ran")
131 }
132 done <- struct{}{}
133 })
134
135
136 runtime.GC()
137 if wt.Value() == nil {
138 t.Errorf("weak pointer went nil too soon")
139 }
140 runtime.KeepAlive(bt)
141
142
143
144
145 runtime.GC()
146 if wt.Value() != nil {
147 t.Errorf("weak pointer did not go nil when finalizer was enqueued")
148 }
149
150
151 <-done
152
153
154 runtime.GC()
155 if wt.Value() != nil {
156 t.Errorf("weak pointer is non-nil even after finalization: %v", wt)
157 }
158 }
159
160 func TestPointerSize(t *testing.T) {
161 var p weak.Pointer[T]
162 size := unsafe.Sizeof(p)
163 if size != goarch.PtrSize {
164 t.Errorf("weak.Pointer[T] size = %d, want %d", size, goarch.PtrSize)
165 }
166 }
167
168
169
170
171
172
173
174
175 func TestIssue69210(t *testing.T) {
176 if testing.Short() {
177 t.Skip("this is a stress test that takes seconds to run on its own")
178 }
179 ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
180 defer cancel()
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204 var wg sync.WaitGroup
205 wg.Add(1)
206 go func() {
207 defer wg.Done()
208 for {
209 runtime.GC()
210
211 select {
212 case <-ctx.Done():
213 return
214 default:
215 }
216 }
217 }()
218 for range max(runtime.GOMAXPROCS(-1)-1, 1) {
219 wg.Add(1)
220 go func() {
221 defer wg.Done()
222 for {
223 for range 5 {
224 bt := new(T)
225 wt := weak.Make(bt)
226 bt = nil
227 time.Sleep(1 * time.Millisecond)
228 bt = wt.Value()
229 if bt != nil {
230 time.Sleep(4 * time.Millisecond)
231 bt.t = bt
232 bt.a = 12
233 }
234 runtime.KeepAlive(bt)
235 }
236 select {
237 case <-ctx.Done():
238 return
239 default:
240 }
241 }
242 }()
243 }
244 wg.Wait()
245 }
246
247 func TestIssue70739(t *testing.T) {
248 x := make([]*int, 4<<16)
249 wx1 := weak.Make(&x[1<<16])
250 wx2 := weak.Make(&x[1<<16])
251 if wx1 != wx2 {
252 t.Fatal("failed to look up special and made duplicate weak handle; see issue #70739")
253 }
254 }
255
View as plain text