v0.33.1 9577fee

factory_resize_test.go RawHistoryFolder

1package cef
2
3import (
4	"context"
5	"testing"
6	"time"
7
8	purecef "github.com/bnema/purego-cef/cef"
9	cef2gtk "github.com/bnema/purego-cef2gtk"
10	"github.com/stretchr/testify/require"
11)
12
13type resizeOrderHost struct {
14	calls []string
15}
16
17func (h *resizeOrderHost) WasResized() {
18	h.calls = append(h.calls, "WasResized")
19}
20
21func (h *resizeOrderHost) Invalidate(_ purecef.PaintElementType) {
22	h.calls = append(h.calls, "Invalidate")
23}
24
25func TestNotifyBrowserResize_CallsWasResizedThenInvalidate(t *testing.T) {
26	host := &resizeOrderHost{}
27
28	notifyBrowserResize(host)
29
30	require.Equal(t, []string{"WasResized", "Invalidate"}, host.calls)
31}
32
33func TestConfigureWindowInfo_SetsAcceleratedWindowlessAndSharedTexture(t *testing.T) {
34	info := purecef.NewWindowInfo()
35
36	cef2gtk.ConfigureWindowInfo(&info, cef2gtk.WindowInfoOptions{})
37
38	require.Equal(t, int32(1), info.WindowlessRenderingEnabled)
39	require.Equal(t, int32(1), info.SharedTextureEnabled)
40}
41
42func TestShouldStartBrowserCreateFromSizeObserver_FalseAfterInitialResizeHandled(t *testing.T) {
43	wv := &WebView{pendingCreate: &pendingBrowserCreate{}}
44
45	require.True(t, wv.shouldStartBrowserCreateFromSizeObserver())
46	wv.markInitialBrowserCreateResizeHandled()
47	require.False(t, wv.shouldStartBrowserCreateFromSizeObserver())
48}
49
50func TestShouldStartBrowserCreateFromSizeObserver_FalseAfterPendingCreateConsumed(t *testing.T) {
51	wv := &WebView{pendingCreate: &pendingBrowserCreate{}}
52
53	require.True(t, wv.shouldStartBrowserCreateFromSizeObserver())
54	require.NotNil(t, wv.takePendingCreate())
55	require.False(t, wv.shouldStartBrowserCreateFromSizeObserver())
56}
57
58func TestInitialBrowserCreateSizeReadyFromObserver(t *testing.T) {
59	tests := []struct {
60		name   string
61		width  int32
62		height int32
63		want   bool
64	}{
65		{name: "rejects bootstrap one by one", width: 1, height: 1, want: false},
66		{name: "rejects zero width", width: 0, height: 480, want: false},
67		{name: "rejects one pixel height", width: 640, height: 1, want: false},
68		{name: "accepts real positive size", width: 640, height: 480, want: true},
69	}
70
71	for _, tt := range tests {
72		t.Run(tt.name, func(t *testing.T) {
73			require.Equal(t, tt.want, initialBrowserCreateSizeReadyFromObserver(tt.width, tt.height))
74		})
75	}
76}
77
78func TestHandleInitialBrowserCreateSizeObserver_IgnoresBootstrapForNormalWebView(t *testing.T) {
79	factory := &WebViewFactory{}
80	wv := &WebView{pendingCreate: &pendingBrowserCreate{}}
81	prepared := false
82	resized := false
83
84	handled := factory.handleInitialBrowserCreateSizeObserver(
85		context.Background(),
86		wv,
87		func(int32, int32) { resized = true },
88		func() error {
89			prepared = true
90			return nil
91		},
92		1,
93		1,
94	)
95
96	require.True(t, handled)
97	require.False(t, prepared)
98	require.False(t, resized)
99	require.True(t, wv.shouldStartBrowserCreateFromSizeObserver())
100}
101
102func TestHandleInitialBrowserCreateSizeObserver_BootstrapPopupArmsFallbackWithoutPreparing(t *testing.T) {
103	factory := &WebViewFactory{}
104	wv := &WebView{pendingCreate: &pendingBrowserCreate{}, nativePopupCandidate: true}
105	prepared := false
106	var scheduled func()
107	wv.nativePopupFallbackSchedule = func(_ time.Duration, fn func()) stoppableTimer {
108		scheduled = fn
109		return stubStoppableTimer{}
110	}
111
112	handled := factory.handleInitialBrowserCreateSizeObserver(
113		context.Background(),
114		wv,
115		func(w, h int32) {
116			factory.handlePopupShellInitialResize(context.Background(), wv, nil, w, h)
117		},
118		func() error {
119			prepared = true
120			return nil
121		},
122		1,
123		1,
124	)
125
126	require.True(t, handled)
127	require.False(t, prepared)
128	require.NotNil(t, scheduled)
129	require.True(t, wv.shouldStartBrowserCreateFromSizeObserver())
130}
131
132func TestHandleInitialBrowserCreateSizeObserver_ReadySizePreparesAndConsumesInitialResize(t *testing.T) {
133	factory := &WebViewFactory{}
134	wv := &WebView{pendingCreate: &pendingBrowserCreate{}}
135	prepared := 0
136	resizes := 0
137
138	handled := factory.handleInitialBrowserCreateSizeObserver(
139		context.Background(),
140		wv,
141		func(int32, int32) { resizes++ },
142		func() error {
143			prepared++
144			return nil
145		},
146		640,
147		480,
148	)
149
150	require.True(t, handled)
151	require.Equal(t, 1, prepared)
152	require.Equal(t, 1, resizes)
153	require.False(t, wv.shouldStartBrowserCreateFromSizeObserver())
154}
155
156func TestHandleInitialBrowserCreateSizeObserver_ReadySizeAfterPopupFallbackPostsCreate(t *testing.T) {
157	factory := &WebViewFactory{}
158	wv := &WebView{pendingCreate: &pendingBrowserCreate{}, nativePopupCandidate: true}
159	prepared := 0
160	posted := 0
161	var scheduled func()
162	wv.nativePopupFallbackSchedule = func(_ time.Duration, fn func()) stoppableTimer {
163		scheduled = fn
164		return stubStoppableTimer{}
165	}
166	onFirstResize := func(w, h int32) {
167		factory.handlePopupShellInitialResize(context.Background(), wv, func(int32, int32) {
168			posted++
169		}, w, h)
170	}
171
172	handled := factory.handleInitialBrowserCreateSizeObserver(
173		context.Background(),
174		wv,
175		onFirstResize,
176		func() error {
177			prepared++
178			return nil
179		},
180		0,
181		480,
182	)
183	require.True(t, handled)
184	require.Equal(t, 0, prepared)
185	require.Equal(t, 0, posted)
186	require.NotNil(t, scheduled)
187	require.True(t, wv.shouldStartBrowserCreateFromSizeObserver())
188
189	scheduled()
190	require.True(t, wv.awaitsBrowserCreateFromNativePopupFallback())
191
192	handled = factory.handleInitialBrowserCreateSizeObserver(
193		context.Background(),
194		wv,
195		onFirstResize,
196		func() error {
197			prepared++
198			return nil
199		},
200		640,
201		480,
202	)
203	require.True(t, handled)
204	require.Equal(t, 1, prepared)
205	require.Equal(t, 1, posted)
206	require.False(t, wv.shouldStartBrowserCreateFromSizeObserver())
207}
208
209func TestSchedulePopupShellNativeFallback_StartsFallbackOnTimeout(t *testing.T) {
210	factory := &WebViewFactory{}
211	wv := &WebView{pendingCreate: &pendingBrowserCreate{}, nativePopupCandidate: true}
212	var scheduled func()
213	wv.nativePopupFallbackSchedule = func(_ time.Duration, fn func()) stoppableTimer {
214		scheduled = fn
215		return stubStoppableTimer{}
216	}
217
218	factory.schedulePopupShellNativeFallback(context.Background(), wv)
219	require.NotNil(t, scheduled)
220
221	scheduled()
222
223	require.True(t, wv.nativePopupFallbackStarted)
224	require.False(t, wv.nativePopupCandidate)
225}
226
227func TestPostPendingBrowserCreate_RetriesWhenPostingTaskFails(t *testing.T) {
228	oldNewTask := cefNewTask
229	oldPostTask := cefPostTask
230	oldScheduleAfter := cefScheduleAfter
231	oldCreateBrowser := cefBrowserHostCreateBrowser
232	defer func() {
233		cefNewTask = oldNewTask
234		cefPostTask = oldPostTask
235		cefScheduleAfter = oldScheduleAfter
236		cefBrowserHostCreateBrowser = oldCreateBrowser
237	}()
238
239	cefNewTask = func(task purecef.Task) purecef.Task { return task }
240
241	postCalls := 0
242	cefPostTask = func(threadID purecef.ThreadID, task purecef.Task) int32 {
243		require.Equal(t, purecef.ThreadIDTidUi, threadID)
244		require.NotNil(t, task)
245		postCalls++
246		if postCalls == 1 {
247			return 0
248		}
249		task.Execute()
250		return 1
251	}
252
253	retried := false
254	cefScheduleAfter = func(delay time.Duration, fn func()) {
255		require.Equal(t, pendingBrowserCreateRetryDelay, delay)
256		retried = true
257		fn()
258	}
259
260	createCalls := 0
261	cefBrowserHostCreateBrowser = func(
262		windowInfo *purecef.WindowInfo,
263		_ purecef.RawClient,
264		url string,
265		settings *purecef.BrowserSettings,
266		_ purecef.DictionaryValue,
267		_ purecef.RequestContext,
268	) int32 {
269		createCalls++
270		require.NotNil(t, windowInfo)
271		require.NotNil(t, settings)
272		require.Equal(t, "about:blank", url)
273		require.Equal(t, int32(1), windowInfo.WindowlessRenderingEnabled)
274		require.Equal(t, int32(1), windowInfo.SharedTextureEnabled)
275		return 1
276	}
277
278	windowInfo := purecef.NewWindowInfo()
279	cef2gtk.ConfigureWindowInfo(&windowInfo, cef2gtk.WindowInfoOptions{})
280	settings := purecef.NewBrowserSettings()
281	wv := &WebView{
282		ctx: context.Background(),
283		pendingCreate: &pendingBrowserCreate{
284			windowInfo: &windowInfo,
285			settings:   &settings,
286		},
287	}
288
289	factory := &WebViewFactory{}
290	factory.postPendingBrowserCreate(context.Background(), wv, 640, 480)
291
292	require.True(t, retried)
293	require.Equal(t, 2, postCalls)
294	require.Equal(t, 1, createCalls)
295	require.Nil(t, wv.takePendingCreate())
296}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 8

Tags 42

↑↓ moveenter openesc close