v0.33.1 9577fee

mode_toaster_view_gtk_test.go RawHistoryFolder

1package ui
2
3import (
4	"testing"
5
6	"github.com/bnema/puregotk/v4/glib"
7	"github.com/bnema/puregotk/v4/gobject"
8	"github.com/bnema/puregotk/v4/gtk"
9	"github.com/stretchr/testify/require"
10)
11
12// watchFinalized reports, through the returned flag, when widget is finalized.
13func watchFinalized(t *testing.T, widget *gtk.Widget) *bool {
14	t.Helper()
15	finalized := new(bool)
16	notify := gobject.WeakNotify(func(_, _ uintptr) { *finalized = true })
17	t.Cleanup(func() { _ = notify })
18	widget.WeakRef(&notify, 0)
19	return finalized
20}
21
22func TestGTKModeToasterViewReleasesWidgets(t *testing.T) {
23	gtkApp := requireGTKDisplayApp(t)
24	defer gtkApp.Unref()
25	// Windows may only be created once the GApplication has started up;
26	// registering emits the startup signal.
27	registered, err := gtkApp.Register(nil)
28	require.NoError(t, err)
29	require.True(t, registered, "the test application registers")
30
31	var view *gtkModeToasterView
32	done := make(chan struct{})
33	run := glib.SourceFunc(func(uintptr) bool {
34		defer close(done)
35		window := gtk.NewApplicationWindow(gtkApp)
36		require.NotNil(t, window)
37		overlay := gtk.NewOverlay()
38		window.SetChild(&overlay.Widget)
39		overlayFinalized := watchFinalized(t, &overlay.Widget)
40		view = newGTKModeToasterView(overlay, window, modeToasterEvents{})
41		require.NotNil(t, view)
42
43		groups := []legendGroup{{Name: "SCROLL", Rows: []legendRow{{Action: "down", Keys: []string{"j"}, Desc: "Down"}}}}
44		view.setLegend(groups)
45		row := watchFinalized(t, view.rows["down"][0])
46		keycap := watchFinalized(t, view.keycaps["down"][0])
47		group := watchFinalized(t, &view.groupBoxes[0].Widget)
48
49		view.setLegend(nil)
50		require.True(t, *row, "a replaced legend row is released")
51		require.True(t, *keycap, "a replaced legend keycap is released")
52		require.True(t, *group, "a replaced legend group is released")
53
54		view.setLegend(groups)
55		view.layoutColumns(1)
56		column := watchFinalized(t, &view.columnBoxes[0].Widget)
57		view.layoutColumns(2)
58		require.True(t, *column, "a column dropped by a relayout is released")
59
60		pill := watchFinalized(t, &view.pill.Widget)
61		body := watchFinalized(t, &view.root.Widget)
62		label := watchFinalized(t, &view.pillLabel.Widget)
63		lastRow := watchFinalized(t, view.rows["down"][0])
64		view.destroy()
65		require.True(t, *pill, "destroy releases the pill")
66		require.True(t, *body, "destroy releases the legend body")
67		require.True(t, *label, "destroy releases the pill label")
68		require.True(t, *lastRow, "destroy releases the legend rows")
69
70		frame := newModeFrame(overlay)
71		require.NotNil(t, frame)
72		border := watchFinalized(t, &frame.border.Widget)
73		frame.destroy()
74		require.True(t, *border, "destroy releases the mode frame border")
75
76		// The window is never presented: destroying an unrealized window
77		// crashes on Wayland, so drop the references instead (the same as
78		// the global shortcut handler test). The overlay's last reference
79		// goes with the window's child; the window itself stays on GTK's
80		// toplevel list until destroyed, so its finalization is not asserted.
81		window.SetChild(nil)
82		overlay.Unref()
83		require.True(t, *overlayFinalized, "the test releases its overlay")
84		gtkApp.RemoveWindow(&window.Window)
85		window.Unref()
86		return false
87	})
88	glib.MainContextDefault().Invoke(&run, 0)
89	<-done
90}

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