1package cef
2
3import (
4 "context"
5 "testing"
6 "time"
7
8 "github.com/bnema/dumber/internal/shared/syncdispatch"
9 purecef "github.com/bnema/purego-cef/cef"
10 "github.com/stretchr/testify/require"
11)
12
13func TestConfigureInitialBrowserCreationClearsPendingCreateWhenGTKDispatchTimesOut(t *testing.T) {
14 factory := &WebViewFactory{}
15 wv := &WebView{
16 ctx: context.Background(),
17 viewBridge: &Cef2gtkAdapter{},
18 gtkSyncTimeout: 5 * time.Millisecond,
19 gtkSyncIsOwner: func() bool { return false },
20 gtkSyncDispatch: func(func()) {
21 // Simulate a GTK main loop that does not service the callback.
22 },
23 }
24 windowInfo := purecef.NewWindowInfo()
25 settings := purecef.NewBrowserSettings()
26
27 err := factory.configureInitialBrowserCreation(context.Background(), wv, nil, &windowInfo, &settings, nil)
28
29 require.Error(t, err)
30 require.Contains(t, err.Error(), "configure initial browser creation")
31 require.Nil(t, wv.pendingCreate)
32}
33
34func TestInstallViewportSyncHooksReportsIncompleteGTKDispatch(t *testing.T) {
35 wv := &WebView{
36 ctx: context.Background(),
37 viewBridge: &Cef2gtkAdapter{},
38 gtkSyncTimeout: 5 * time.Millisecond,
39 gtkSyncIsOwner: func() bool { return false },
40 gtkSyncDispatch: func(func()) {
41 // Simulate a GTK main loop that does not service the callback.
42 },
43 }
44
45 result := wv.installViewportSyncHooks()
46
47 require.False(t, result.Completed())
48 require.Equal(t, syncdispatch.SyncDispatchTimedOut, result.Status)
49}
50
51func TestDestroyViewBridgeOnGTKSyncLeavesCleanupQueuedAfterTimeout(t *testing.T) {
52 delayed := make(chan func(), 1)
53 wv := &WebView{
54 ctx: context.Background(),
55 engine: &Engine{},
56 viewBridge: &Cef2gtkAdapter{},
57 gtkSyncTimeout: 5 * time.Millisecond,
58 gtkSyncIsOwner: func() bool { return false },
59 gtkSyncDispatch: func(fn func()) {
60 delayed <- fn
61 },
62 }
63
64 wv.destroyViewBridgeOnGTKSync()
65
66 require.NotNil(t, wv.viewBridge)
67 select {
68 case fn := <-delayed:
69 fn()
70 case <-time.After(time.Second):
71 t.Fatal("cleanup callback was not captured")
72 }
73 require.Nil(t, wv.viewBridge)
74}
75
76func TestRunOnGTKSyncCompletedAfterTimeoutStillCountsAsCompleted(t *testing.T) {
77 started := make(chan struct{})
78 release := make(chan struct{})
79 wv := &WebView{
80 ctx: context.Background(),
81 engine: &Engine{},
82 gtkSyncTimeout: 5 * time.Millisecond,
83 gtkSyncIsOwner: func() bool { return false },
84 gtkSyncDispatch: func(fn func()) {
85 go fn()
86 },
87 }
88
89 resultCh := make(chan syncdispatch.SyncDispatchResult, 1)
90 go func() {
91 resultCh <- wv.runOnGTKSync(func() {
92 close(started)
93 <-release
94 })
95 }()
96
97 <-started
98 time.Sleep(20 * time.Millisecond)
99 close(release)
100
101 result := <-resultCh
102 require.Equal(t, syncdispatch.SyncDispatchCompletedAfterTimeout, result.Status)
103 require.True(t, result.Completed())
104}