v0.1.0 47aaa0f

sequence_test.go RawHistoryFolder

1//go:build linux
2
3package wayland
4
5import (
6	"encoding/binary"
7	"io"
8	"net"
9	"testing"
10	"time"
11
12	"github.com/bnema/nefergui/internal/presentation/buffers"
13	"github.com/bnema/wlturbo"
14	"github.com/bnema/wlturbo/protocol/core"
15	"github.com/bnema/wlturbo/protocol/drmsyncobj"
16	"github.com/bnema/wlturbo/wl"
17)
18
19// A socket peer records real wire requests (not a mocked Present implementation).
20// Every frame must carry both sync points and a buffer on the same commit.
21func TestPresentWireSequence(t *testing.T) {
22	client, server := net.Pipe()
23	defer server.Close()
24	// ConnectFromConn sends get_registry before it returns: drain the pipe first.
25	type request struct {
26		id     uint32
27		opcode uint16
28		args   []byte
29	}
30	requests := make(chan request, 64)
31	errs := make(chan error, 1)
32	go func() {
33		for {
34			header := make([]byte, 8)
35			if _, e := io.ReadFull(server, header); e != nil {
36				errs <- e
37				return
38			}
39			n := int(binary.LittleEndian.Uint32(header[4:]) >> 16)
40			data := make([]byte, n-8)
41			if _, e := io.ReadFull(server, data); e != nil {
42				errs <- e
43				return
44			}
45			requests <- request{binary.LittleEndian.Uint32(header), binary.LittleEndian.Uint16(header[4:]), data}
46		}
47	}()
48	d, err := wlturbo.ConnectFromConn(client)
49	if err != nil {
50		t.Fatal(err)
51	}
52	defer d.Close()
53	ctx := d.Context()
54	surface := core.NewSurface(ctx)
55	syncSurface := drmsyncobj.NewWpLinuxDrmSyncobjSurface(ctx)
56	acquire := drmsyncobj.NewWpLinuxDrmSyncobjTimeline(ctx)
57	release := drmsyncobj.NewWpLinuxDrmSyncobjTimeline(ctx)
58	buffer := core.NewBuffer(ctx)
59	for i, p := range []wl.Proxy{surface, syncSurface, acquire, release, buffer} {
60		p.SetID(uint32(20 + i))
61		ctx.Register(p)
62	}
63	w := &Window{Surface: surface, SyncSurface: syncSurface, Width: 40, Height: 30, Scale: 1, Configured: true, FrameReady: true, Transparent: true}
64	p, _ := buffers.New(1)
65	// The fake server receives a finite number of requests; no dispatch loop/GPU.
66	for frame := 0; frame < 2; frame++ {
67		b, e := p.Begin()
68		if e != nil {
69			t.Fatal(e)
70		}
71		a, e := p.Acquire(b)
72		if e != nil {
73			t.Fatal(e)
74		}
75		z, e := p.Commit(b)
76		if e != nil {
77			t.Fatal(e)
78		}
79		if e = w.Present(buffer, acquire, release, a, z); e != nil {
80			t.Fatal(e)
81		}
82		if e = p.Own(b); e != nil {
83			t.Fatal(e)
84		}
85		// Observe the generated protocol sequence up to commit. Ignore ancillary
86		// viewport/opaque/damage/frame requests, but ensure they do not replace the buffer.
87		var events []string
88		var attached, acquired, released bool
89		deadline := time.After(3 * time.Second)
90	loop:
91		for {
92			select {
93			case q := <-requests:
94				switch {
95				case q.id == syncSurface.ID() && q.opcode == 1:
96					acquired = true
97					events = append(events, "acquire")
98				case q.id == syncSurface.ID() && q.opcode == 2:
99					released = true
100					events = append(events, "release")
101				case q.id == surface.ID() && q.opcode == 1:
102					attached = binary.LittleEndian.Uint32(q.args) == buffer.ID()
103					events = append(events, "attach")
104				case q.id == surface.ID() && q.opcode == 6:
105					events = append(events, "commit")
106					break loop
107				}
108			case e := <-errs:
109				t.Fatal(e)
110			case <-deadline:
111				t.Fatal("missing commit")
112			}
113		}
114		if !attached || !acquired || !released || len(events) != 4 || events[0] != "acquire" || events[1] != "release" || events[2] != "attach" || events[3] != "commit" {
115			t.Fatalf("frame %d wire sequence %v attached=%v", frame, events, attached)
116		}
117		if e = p.Release(b); e != nil {
118			t.Fatal(e)
119		}
120		if _, e = p.Begin(); e != buffers.ErrNoBuffer {
121			t.Fatalf("wl_buffer.release reused buffer: %v", e)
122		}
123		if e = p.Signal(b, z); e != nil {
124			t.Fatal(e)
125		}
126		if e = p.Reuse(b, true); e != nil {
127			t.Fatal(e)
128		}
129		w.FrameReady = true // synthetic frame callback
130	}
131}

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 12

↑↓ moveenter openesc close