test(ticks): require raw callback unref exactly once
- commit
- 7b6d57c91221f96e60530f7d2c4b7d7c91e03293
- author
- brice · · 2026-07-14 07:10 UTC
- committer
- brice · · 2026-07-14 09:32 UTC
- parent
- 7351f41
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
2 files · +28 -0
M internal/infrastructure/cef/webview_begin_frame_cleanup_test.go +14 -0
| @@ -9,10 +9,24 @@ import ( | |||
| 9 | 9 | func TestStopBeginFrameLoopReleasesCallbackSlotWithoutWidget(t *testing.T) { | |
| 10 | 10 | callback := new(gtk.TickCallback) | |
| 11 | 11 | wv := &WebView{beginFrameTick: callback, beginFrameTickID: 17} | |
| 12 | + | oldUnref := unrefTickCallback | |
| 13 | + | defer func() { unrefTickCallback = oldUnref }() | |
| 14 | + | var unrefs int | |
| 15 | + | unrefTickCallback = func(got any) error { | |
| 16 | + | if got != callback { | |
| 17 | + | t.Fatalf("unref callback = %p, want %p", got, callback) | |
| 18 | + | } | |
| 19 | + | unrefs++ | |
| 20 | + | return nil | |
| 21 | + | } | |
| 12 | 22 | ||
| 23 | + | wv.stopBeginFrameLoop() | |
| 13 | 24 | wv.stopBeginFrameLoop() | |
| 14 | 25 | ||
| 15 | 26 | if wv.beginFrameTick != nil || wv.beginFrameTickID != 0 { | |
| 16 | 27 | t.Fatal("stop must release the BeginFrame callback slot even after the GTK widget is gone") | |
| 17 | 28 | } | |
| 29 | + | if unrefs != 1 { | |
| 30 | + | t.Fatalf("callback unrefs = %d, want 1", unrefs) | |
| 31 | + | } | |
| 18 | 32 | } | |
| @@ -9,10 +9,24 @@ import ( | |||||
| 9 | func TestStopBeginFrameLoopReleasesCallbackSlotWithoutWidget(t *testing.T) { | 9 | func TestStopBeginFrameLoopReleasesCallbackSlotWithoutWidget(t *testing.T) { | ||
| 10 | callback := new(gtk.TickCallback) | 10 | callback := new(gtk.TickCallback) | ||
| 11 | wv := &WebView{beginFrameTick: callback, beginFrameTickID: 17} | 11 | wv := &WebView{beginFrameTick: callback, beginFrameTickID: 17} | ||
| 12 | + | oldUnref := unrefTickCallback | |||
| 13 | + | defer func() { unrefTickCallback = oldUnref }() | |||
| 14 | + | var unrefs int | |||
| 15 | + | unrefTickCallback = func(got any) error { | |||
| 16 | + | if got != callback { | |||
| 17 | + | t.Fatalf("unref callback = %p, want %p", got, callback) | |||
| 18 | + | } | |||
| 19 | + | unrefs++ | |||
| 20 | + | return nil | |||
| 21 | + | } | |||
| 12 | 22 | ||||
| 23 | + | wv.stopBeginFrameLoop() | |||
| 13 | wv.stopBeginFrameLoop() | 24 | wv.stopBeginFrameLoop() | ||
| 14 | 25 | ||||
| 15 | if wv.beginFrameTick != nil || wv.beginFrameTickID != 0 { | 26 | if wv.beginFrameTick != nil || wv.beginFrameTickID != 0 { | ||
| 16 | t.Fatal("stop must release the BeginFrame callback slot even after the GTK widget is gone") | 27 | t.Fatal("stop must release the BeginFrame callback slot even after the GTK widget is gone") | ||
| 17 | } | 28 | } | ||
| 29 | + | if unrefs != 1 { | |||
| 30 | + | t.Fatalf("callback unrefs = %d, want 1", unrefs) | |||
| 31 | + | } | |||
| 18 | } | 32 | } | ||
M internal/ui/floating_pane_callback_cleanup_test.go +14 -0
| @@ -9,10 +9,24 @@ import ( | |||
| 9 | 9 | func TestStopFloatingResizeWatcherReleasesRawCallbackSlot(t *testing.T) { | |
| 10 | 10 | callback := new(gtk.TickCallback) | |
| 11 | 11 | session := &floatingWorkspaceSession{resizeTickCallback: callback, resizeTickID: 17, resizeWatcherActive: true} | |
| 12 | + | oldUnref := unrefTickCallback | |
| 13 | + | defer func() { unrefTickCallback = oldUnref }() | |
| 14 | + | var unrefs int | |
| 15 | + | unrefTickCallback = func(got any) error { | |
| 16 | + | if got != callback { | |
| 17 | + | t.Fatalf("unref callback = %p, want %p", got, callback) | |
| 18 | + | } | |
| 19 | + | unrefs++ | |
| 20 | + | return nil | |
| 21 | + | } | |
| 12 | 22 | ||
| 23 | + | (&App{}).stopFloatingResizeWatcher(session) | |
| 13 | 24 | (&App{}).stopFloatingResizeWatcher(session) | |
| 14 | 25 | ||
| 15 | 26 | if session.resizeTickCallback != nil || session.resizeTickID != 0 || session.resizeWatcherActive { | |
| 16 | 27 | t.Fatal("stop must release the floating resize callback slot exactly once") | |
| 17 | 28 | } | |
| 29 | + | if unrefs != 1 { | |
| 30 | + | t.Fatalf("callback unrefs = %d, want 1", unrefs) | |
| 31 | + | } | |
| 18 | 32 | } | |
| @@ -9,10 +9,24 @@ import ( | |||||
| 9 | func TestStopFloatingResizeWatcherReleasesRawCallbackSlot(t *testing.T) { | 9 | func TestStopFloatingResizeWatcherReleasesRawCallbackSlot(t *testing.T) { | ||
| 10 | callback := new(gtk.TickCallback) | 10 | callback := new(gtk.TickCallback) | ||
| 11 | session := &floatingWorkspaceSession{resizeTickCallback: callback, resizeTickID: 17, resizeWatcherActive: true} | 11 | session := &floatingWorkspaceSession{resizeTickCallback: callback, resizeTickID: 17, resizeWatcherActive: true} | ||
| 12 | + | oldUnref := unrefTickCallback | |||
| 13 | + | defer func() { unrefTickCallback = oldUnref }() | |||
| 14 | + | var unrefs int | |||
| 15 | + | unrefTickCallback = func(got any) error { | |||
| 16 | + | if got != callback { | |||
| 17 | + | t.Fatalf("unref callback = %p, want %p", got, callback) | |||
| 18 | + | } | |||
| 19 | + | unrefs++ | |||
| 20 | + | return nil | |||
| 21 | + | } | |||
| 12 | 22 | ||||
| 23 | + | (&App{}).stopFloatingResizeWatcher(session) | |||
| 13 | (&App{}).stopFloatingResizeWatcher(session) | 24 | (&App{}).stopFloatingResizeWatcher(session) | ||
| 14 | 25 | ||||
| 15 | if session.resizeTickCallback != nil || session.resizeTickID != 0 || session.resizeWatcherActive { | 26 | if session.resizeTickCallback != nil || session.resizeTickID != 0 || session.resizeWatcherActive { | ||
| 16 | t.Fatal("stop must release the floating resize callback slot exactly once") | 27 | t.Fatal("stop must release the floating resize callback slot exactly once") | ||
| 17 | } | 28 | } | ||
| 29 | + | if unrefs != 1 { | |||
| 30 | + | t.Fatalf("callback unrefs = %d, want 1", unrefs) | |||
| 31 | + | } | |||
| 18 | } | 32 | } | ||