v0.6.0 9be920f

registry_test.go RawHistoryFolder

1//go:build linux
2
3package wlturbo
4
5import (
6	"bytes"
7	"encoding/binary"
8	"errors"
9	"io"
10	"testing"
11	"time"
12)
13
14// globalEvent builds a wl_registry.global event body.
15func globalEvent(registry, name uint32, iface string, version uint32) []byte {
16	padded := (len(iface) + 1 + 3) &^ 3
17	body := make([]byte, 4+4+padded+4)
18	binary.LittleEndian.PutUint32(body, name)
19	binary.LittleEndian.PutUint32(body[4:], uint32(len(iface)+1))
20	copy(body[8:], iface)
21	binary.LittleEndian.PutUint32(body[8+padded:], version)
22	return message(registry, 0, body)
23}
24
25func u32Body(v uint32) []byte {
26	b := make([]byte, 4)
27	binary.LittleEndian.PutUint32(b, v)
28	return b
29}
30
31// readRequest reads one request the client wrote to the peer.
32func readRequest(t *testing.T, r io.Reader) (object uint32, opcode uint16, body []byte) {
33	t.Helper()
34	object, opcode, body, err := readFrame(r, 0)
35	if err != nil {
36		t.Fatalf("read request: %v", err)
37	}
38	return object, opcode, body
39}
40
41func TestRegistryBootstrapAnnouncements(t *testing.T) {
42	client, peer := unixSocketPair(t)
43	d := newDisplay(client)
44	reg := d.Registry()
45	peer.SetDeadline(time.Now().Add(2 * time.Second))
46
47	var got Global
48	reg.AddHandler("wl_compositor", func(r *Registry, name, _ uint32) { got, _ = r.FindGlobalByName(name) })
49
50	sendMessageWithFDs(t, peer, globalEvent(reg.ID(), 17, "wl_compositor", 7), nil)
51	if err := d.Dispatch(); err != nil {
52		t.Fatal(err)
53	}
54	if got.Name != 17 || got.Interface != "wl_compositor" || got.Version != 7 {
55		t.Fatalf("global: %+v", got)
56	}
57
58	sendMessageWithFDs(t, peer, message(reg.ID(), 1, u32Body(17)), nil)
59	if err := d.Dispatch(); err != nil {
60		t.Fatal(err)
61	}
62	if _, ok := reg.FindGlobalByName(17); ok {
63		t.Fatal("global not removed")
64	}
65
66	sendMessageWithFDs(t, peer, message(reg.ID(), 2, nil), nil)
67	if err := d.Dispatch(); !errors.Is(err, ErrUnknownOpcode) {
68		t.Fatalf("unknown registry opcode: %v", err)
69	}
70}
71
72func TestBindNegotiated(t *testing.T) {
73	client, peer := unixSocketPair(t)
74	d := newDisplay(client)
75	reg := d.Registry()
76	peer.SetDeadline(time.Now().Add(2 * time.Second))
77	const iface = "xdg_wm_base"
78
79	if v, err := reg.BindNegotiated(iface, 6, &BaseProxy{}); v != 0 || !errors.Is(err, ErrGlobalNotFound) {
80		t.Fatalf("missing global: %d %v", v, err)
81	}
82	if v, err := reg.BindNegotiated(iface, 0, &BaseProxy{}); v != 0 || err == nil || errors.Is(err, ErrGlobalNotFound) {
83		t.Fatalf("supported zero: %d %v", v, err)
84	}
85
86	// A global announced at version 0 is unusable.
87	sendMessageWithFDs(t, peer, globalEvent(reg.ID(), 29, iface, 0), nil)
88	if err := d.Dispatch(); err != nil {
89		t.Fatal(err)
90	}
91	if v, err := reg.BindNegotiated(iface, 6, &BaseProxy{}); v != 0 || !errors.Is(err, ErrGlobalNotFound) {
92		t.Fatalf("announced version 0: %d %v", v, err)
93	}
94	sendMessageWithFDs(t, peer, message(reg.ID(), 1, u32Body(29)), nil)
95	if err := d.Dispatch(); err != nil {
96		t.Fatal(err)
97	}
98
99	for i, announced := range []uint32{2, 9} {
100		name := uint32(30 + i)
101		sendMessageWithFDs(t, peer, globalEvent(reg.ID(), name, iface, announced), nil)
102		if err := d.Dispatch(); err != nil {
103			t.Fatal(err)
104		}
105		proxy := &BaseProxy{}
106		if v, err := reg.BindNegotiated(iface, 0, proxy); v != 0 || err == nil {
107			t.Fatalf("supported zero with global: %d %v", v, err)
108		}
109		negotiated, err := reg.BindNegotiated(iface, 6, proxy)
110		if err != nil {
111			t.Fatal(err)
112		}
113		want := min(announced, 6)
114		if negotiated != want || proxy.Version() != want {
115			t.Fatalf("announced=%d negotiated=%d proxy version=%d, want %d", announced, negotiated, proxy.Version(), want)
116		}
117		obj, op, body := readRequest(t, peer)
118		// bind: name, string (length incl. NUL, NUL, padding), version, new_id.
119		padded := (len(iface) + 1 + 3) &^ 3
120		if obj != reg.ID() || op != 0 || len(body) != 4+4+padded+4+4 ||
121			binary.LittleEndian.Uint32(body) != name ||
122			binary.LittleEndian.Uint32(body[4:]) != uint32(len(iface)+1) ||
123			string(body[8:8+len(iface)]) != iface ||
124			!bytes.Equal(body[8+len(iface):8+padded], make([]byte, padded-len(iface))) ||
125			binary.LittleEndian.Uint32(body[8+padded:]) != want ||
126			binary.LittleEndian.Uint32(body[8+padded+4:]) != proxy.ID() {
127			t.Fatalf("bind object=%d opcode=%d body=%x", obj, op, body)
128		}
129		// Remove the global so the next iteration is the only match.
130		sendMessageWithFDs(t, peer, message(reg.ID(), 1, u32Body(name)), nil)
131		if err := d.Dispatch(); err != nil {
132			t.Fatal(err)
133		}
134	}
135}

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 1

Tags 8

↑↓ moveenter openesc close