Source file
src/weak/pointer_test.go
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 b int
24 }
25
26 func TestPointer(t *testing.T) {
27 var zero weak.Pointer[T]
28 if zero.Value() != nil {
29 t.Error("Value of zero value of weak.Pointer is not nil")
30 }
31 zeroNil := weak.Make[T](nil)
32 if zeroNil.Value() != nil {
33 t.Error("Value of weak.Make[T](nil) is not nil")
34 }
35
36 bt := new(T)
37 wt := weak.Make(bt)
38 if st := wt.Value(); st != bt {
39 t.Fatalf("weak pointer is not the same as strong pointer: %p vs. %p", st, bt)
40 }
41
42 runtime.GC()
43
44 if st := wt.Value(); st != bt {
45 t.Fatalf("weak pointer is not the same as strong pointer after GC: %p vs. %p", st, bt)
46 }
47
48 runtime.GC()
49
50 if st := wt.Value(); st != nil {
51 t.Fatalf("expected weak pointer to be nil, got %p", st)
52 }
53 }
54
55 func TestPointerEquality(t *testing.T) {
56 var zero weak.Pointer[T]
57 zeroNil := weak.Make[T](nil)
58 if zero != zeroNil {
59 t.Error("weak.Make[T](nil) != zero value of weak.Pointer[T]")
60 }
61
62 bt := make([]*T, 10)
63 wt := make([]weak.Pointer[T], 10)
64 wo := make([]weak.Pointer[int], 10)
65 for i := range bt {
66 bt[i] = new(T)
67 wt[i] = weak.Make(bt[i])
68 wo[i] = weak.Make(&bt[i].a)
69 }
70 for i := range bt {
71 st := wt[i].Value()
72 if st != bt[i] {
73 t.Fatalf("weak pointer is not the same as strong pointer: %p vs. %p", st, bt[i])
74 }
75 if wp := weak.Make(st); wp != wt[i] {
76 t.Fatalf("new weak pointer not equal to existing weak pointer: %v vs. %v", wp, wt[i])
77 }
78 if wp := weak.Make(&st.a); wp != wo[i] {
79 t.Fatalf("new weak pointer not equal to existing weak pointer: %v vs. %v", wp, wo[i])
80 }
81 if i == 0 {
82 continue
83 }
84 if wt[i] == wt[i-1] {
85 t.Fatalf("expected weak pointers to not be equal to each other, but got %v", wt[i])
86 }
87 }
88
89 runtime.GC()
90 for i := range bt {
91 st := wt[i].Value()
92 if st != bt[i] {
93 t.Fatalf("weak pointer is not the same as strong pointer: %p vs. %p", st, bt[i])
94 }
95 if wp := weak.Make(st); wp != wt[i] {
96 t.Fatalf("new weak pointer not equal to existing weak pointer: %v vs. %v", wp, wt[i])
97 }
98 if wp := weak.Make(&st.a); wp != wo[i] {
99 t.Fatalf("new weak pointer not equal to existing weak pointer: %v vs. %v", wp, wo[i])
100 }
101 if i == 0 {
102 continue
103 }
104 if wt[i] == wt[i-1] {
105 t.Fatalf("expected weak pointers to not be equal to each other, but got %v", wt[i])
106 }
107 }
108 bt = nil
109
110 runtime.GC()
111 for i := range bt {
112 st := wt[i].Value()
113 if st != nil {
114 t.Fatalf("expected weak pointer to be nil, got %p", st)
115 }
116 if i == 0 {
117 continue
118 }
119 if wt[i] == wt[i-1] {
120 t.Fatalf("expected weak pointers to not be equal to each other, but got %v", wt[i])
121 }
122 }
123 }
124
125 func TestPointerFinalizer(t *testing.T) {
126 bt := new(T)
127 wt := weak.Make(bt)
128 done := make(chan struct{}, 1)
129 runtime.SetFinalizer(bt, func(bt *T) {
130 if wt.Value() != nil {
131 t.Errorf("weak pointer did not go nil before finalizer ran")
132 }
133 done <- struct{}{}
134 })
135
136
137 runtime.GC()
138 if wt.Value() == nil {
139 t.Errorf("weak pointer went nil too soon")
140 }
141 runtime.KeepAlive(bt)
142
143
144
145
146 runtime.GC()
147 if wt.Value() != nil {
148 t.Errorf("weak pointer did not go nil when finalizer was enqueued")
149 }
150
151
152 <-done
153
154
155 runtime.GC()
156 if wt.Value() != nil {
157 t.Errorf("weak pointer is non-nil even after finalization: %v", wt)
158 }
159 }
160
161 func TestPointerCleanup(t *testing.T) {
162 bt := new(T)
163 wt := weak.Make(bt)
164 done := make(chan struct{}, 1)
165 runtime.AddCleanup(bt, func(_ bool) {
166 if wt.Value() != nil {
167 t.Errorf("weak pointer did not go nil before cleanup was executed")
168 }
169 done <- struct{}{}
170 }, true)
171
172
173 runtime.GC()
174 if wt.Value() == nil {
175 t.Errorf("weak pointer went nil too soon")
176 }
177 runtime.KeepAlive(bt)
178
179
180
181
182 runtime.GC()
183 if wt.Value() != nil {
184 t.Errorf("weak pointer did not go nil when cleanup was enqueued")
185 }
186
187
188 <-done
189
190
191 runtime.GC()
192 if wt.Value() != nil {
193 t.Errorf("weak pointer is non-nil even after cleanup: %v", wt)
194 }
195 }
196
197 func TestPointerSize(t *testing.T) {
198 var p weak.Pointer[T]
199 size := unsafe.Sizeof(p)
200 if size != goarch.PtrSize {
201 t.Errorf("weak.Pointer[T] size = %d, want %d", size, goarch.PtrSize)
202 }
203 }
204
205
206
207
208
209
210
211
212 func TestIssue69210(t *testing.T) {
213 if testing.Short() {
214 t.Skip("this is a stress test that takes seconds to run on its own")
215 }
216 ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
217 defer cancel()
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241 var wg sync.WaitGroup
242 wg.Add(1)
243 go func() {
244 defer wg.Done()
245 for {
246 runtime.GC()
247
248 select {
249 case <-ctx.Done():
250 return
251 default:
252 }
253 }
254 }()
255 for range max(runtime.GOMAXPROCS(-1)-1, 1) {
256 wg.Add(1)
257 go func() {
258 defer wg.Done()
259 for {
260 for range 5 {
261 bt := new(T)
262 wt := weak.Make(bt)
263 bt = nil
264 time.Sleep(1 * time.Millisecond)
265 bt = wt.Value()
266 if bt != nil {
267 time.Sleep(4 * time.Millisecond)
268 bt.t = bt
269 bt.a = 12
270 }
271 runtime.KeepAlive(bt)
272 }
273 select {
274 case <-ctx.Done():
275 return
276 default:
277 }
278 }
279 }()
280 }
281 wg.Wait()
282 }
283
284 func TestIssue70739(t *testing.T) {
285 x := make([]*int, 4<<16)
286 wx1 := weak.Make(&x[1<<16])
287 wx2 := weak.Make(&x[1<<16])
288 if wx1 != wx2 {
289 t.Fatal("failed to look up special and made duplicate weak handle; see issue #70739")
290 }
291 }
292
293 var immortal T
294
295 func TestImmortalPointer(t *testing.T) {
296 w0 := weak.Make(&immortal)
297 if weak.Make(&immortal) != w0 {
298 t.Error("immortal weak pointers to the same pointer not equal")
299 }
300 w0a := weak.Make(&immortal.a)
301 w0b := weak.Make(&immortal.b)
302 if w0a == w0b {
303 t.Error("separate immortal pointers (same object) have the same pointer")
304 }
305 if got, want := w0.Value(), &immortal; got != want {
306 t.Errorf("immortal weak pointer to %p has unexpected Value %p", want, got)
307 }
308 if got, want := w0a.Value(), &immortal.a; got != want {
309 t.Errorf("immortal weak pointer to %p has unexpected Value %p", want, got)
310 }
311 if got, want := w0b.Value(), &immortal.b; got != want {
312 t.Errorf("immortal weak pointer to %p has unexpected Value %p", want, got)
313 }
314
315
316 runtime.GC()
317 runtime.GC()
318
319
320 if got, want := w0.Value(), &immortal; got != want {
321 t.Errorf("immortal weak pointer to %p has unexpected Value %p", want, got)
322 }
323 if got, want := w0a.Value(), &immortal.a; got != want {
324 t.Errorf("immortal weak pointer to %p has unexpected Value %p", want, got)
325 }
326 if got, want := w0b.Value(), &immortal.b; got != want {
327 t.Errorf("immortal weak pointer to %p has unexpected Value %p", want, got)
328 }
329 }
330
View as plain text