v0.31.0 bf0756b

portal_inhibitor_test.go RawHistoryFolder

1package idle
2
3import (
4	"bufio"
5	"bytes"
6	"context"
7	"os/exec"
8	"strings"
9	"sync"
10	"testing"
11
12	"github.com/godbus/dbus/v5"
13)
14
15func TestWatchForResponseCleanupSurvivesConnFieldCleared(t *testing.T) {
16	// clearConnOnDoneContext clears inhibitor.conn after watchForResponse has
17	// installed its cleanup defer; the test fails if cleanup dereferences the
18	// mutable field instead of the D-Bus connection snapshot.
19	conn := connectPrivateSessionBus(t)
20	defer conn.Close()
21
22	inhibitor := &PortalInhibitor{conn: conn}
23	ctx := &clearConnOnDoneContext{
24		Context: context.Background(),
25		done:    closedDoneChannel(),
26		clear: func() {
27			inhibitor.mu.Lock()
28			inhibitor.conn = nil
29			inhibitor.mu.Unlock()
30		},
31	}
32
33	inhibitor.watchForResponse(ctx, "/org/freedesktop/portal/desktop/request/dumber/test")
34
35	inhibitor.mu.Lock()
36	connCleared := inhibitor.conn == nil
37	inhibitor.mu.Unlock()
38	if !connCleared {
39		t.Fatal("watchForResponse returned before observing context cancellation")
40	}
41}
42
43func connectPrivateSessionBus(t *testing.T) *dbus.Conn {
44	t.Helper()
45
46	address := startPrivateSessionBus(t)
47	conn, err := dbus.Connect(address)
48	if err != nil {
49		t.Fatalf("connect to private D-Bus session bus: %v", err)
50	}
51	return conn
52}
53
54func startPrivateSessionBus(t *testing.T) string {
55	t.Helper()
56
57	if _, err := exec.LookPath("dbus-daemon"); err != nil {
58		t.Skipf("dbus-daemon unavailable: %v", err)
59	}
60
61	var stderr bytes.Buffer
62	cmd := exec.Command("dbus-daemon", "--session", "--nofork", "--print-address=1")
63	cmd.Stderr = &stderr
64
65	stdout, err := cmd.StdoutPipe()
66	if err != nil {
67		t.Fatalf("open dbus-daemon stdout: %v", err)
68	}
69	err = cmd.Start()
70	if err != nil {
71		t.Fatalf("start dbus-daemon: %v", err)
72	}
73
74	t.Cleanup(func() {
75		if cmd.Process != nil {
76			_ = cmd.Process.Kill()
77		}
78		_ = cmd.Wait()
79	})
80
81	address, err := bufio.NewReader(stdout).ReadString('\n')
82	if err != nil {
83		t.Fatalf("read dbus-daemon address: %v; stderr: %s", err, stderr.String())
84	}
85	return strings.TrimSpace(address)
86}
87
88type clearConnOnDoneContext struct {
89	context.Context
90	done  <-chan struct{}
91	once  sync.Once
92	clear func()
93}
94
95func (c *clearConnOnDoneContext) Done() <-chan struct{} {
96	c.once.Do(c.clear)
97	return c.done
98}
99
100func closedDoneChannel() <-chan struct{} {
101	done := make(chan struct{})
102	close(done)
103	return done
104}

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