v0.6.0 7d47882

crop_test.go RawHistoryFolder

1package wayland
2
3import (
4	"context"
5	"runtime"
6	"testing"
7	"unsafe"
8
9	"github.com/stretchr/testify/require"
10
11	"github.com/bnema/nefercap/internal/adapters/wayland/testserver"
12	"github.com/bnema/nefercap/internal/ports"
13)
14
15func bigOutput() []testserver.OutputSpec {
16	return []testserver.OutputSpec{{Name: "BIG", Width: 64, Height: 48, Scale: 1}}
17}
18
19// Without the extension a region is cropped from the output frame, borrowing
20// the shared storage: no pixel is copied and the full stride is kept.
21func TestCaptureRegionCropsOutputFrame(t *testing.T) {
22	s, srv := newSource(t, testserver.Config{Outputs: bigOutput()})
23	out := firstOutput(t, s)
24	f, err := s.Capture(context.Background(), ports.Target{OutputID: out.ID, Region: ports.Region{X: 10, Y: 5, Width: 20, Height: 8}})
25	require.NoError(t, err)
26	require.NoError(t, f.Validate())
27	require.Equal(t, [3]int{20, 8, 64 * 4}, [3]int{f.Width, f.Height, f.Stride})
28	want := testserver.Pixel(10, 5, 1)
29	require.Equal(t, want[:], f.Row(0)[:4])
30	want = testserver.Pixel(29, 12, 1)
31	require.Equal(t, want[:], f.Row(7)[19*4:])
32	require.Equal(t, "output", srv.Stats().LastSource)
33	require.Equal(t, 1, srv.Stats().Buffers, "a single screenshot allocates a single buffer")
34}
35
36func TestCropIsAWindowOfTheFrame(t *testing.T) {
37	out := &output{id: 1, width: 64, height: 48, scale: 1}
38	f := ports.Frame{Pixels: make([]byte, 64*48*4), Width: 64, Height: 48, Stride: 64 * 4, Format: ports.XRGB8888}
39	c, err := cropFrame(f, ports.Region{X: 10, Y: 5, Width: 20, Height: 8}, out)
40	require.NoError(t, err)
41	require.Equal(t, unsafe.Add(unsafe.Pointer(&f.Pixels[0]), 5*64*4+10*4), unsafe.Pointer(&c.Pixels[0]))
42	require.Equal(t, 7*64*4+20*4, len(c.Pixels), "the window ends with the last row's pixels")
43}
44
45func TestCropRoundsToBufferPixels(t *testing.T) {
46	s, _ := newSource(t, testserver.Config{Outputs: []testserver.OutputSpec{{Name: "HI", Width: 64, Height: 48, Scale: 2}}})
47	out := firstOutput(t, s)
48	// logical size is 32x24 (mode over scale): one logical pixel is two buffer pixels
49	f, err := s.Capture(context.Background(), ports.Target{OutputID: out.ID, Region: ports.Region{X: 3, Y: 2, Width: 5, Height: 4}})
50	require.NoError(t, err)
51	require.Equal(t, [2]int{10, 8}, [2]int{f.Width, f.Height})
52	want := testserver.Pixel(6, 4, 1)
53	require.Equal(t, want[:], f.Row(0)[:4])
54}
55
56func TestCropClipsToOutputAndRejectsOutside(t *testing.T) {
57	s, _ := newSource(t, testserver.Config{Outputs: bigOutput()})
58	out := firstOutput(t, s)
59	f, err := s.Capture(context.Background(), ports.Target{OutputID: out.ID, Region: ports.Region{X: 60, Y: 40, Width: 100, Height: 100}})
60	require.NoError(t, err)
61	require.Equal(t, [2]int{4, 8}, [2]int{f.Width, f.Height})
62	_, err = s.Capture(context.Background(), ports.Target{OutputID: out.ID, Region: ports.Region{X: 64, Y: 0, Width: 4, Height: 4}})
63	require.ErrorIs(t, err, ports.ErrInvalidRegion)
64}
65
66func TestCropUsesXdgOutputLogicalSize(t *testing.T) {
67	s, _ := newSource(t, testserver.Config{Outputs: []testserver.OutputSpec{{Name: "FR", Width: 64, Height: 48, Scale: 1, LogicalWidth: 32, LogicalHeight: 24}}})
68	f, err := s.Capture(context.Background(), ports.Target{OutputID: firstOutput(t, s).ID, Region: ports.Region{Width: 16, Height: 12}})
69	require.NoError(t, err)
70	require.Equal(t, [2]int{32, 24}, [2]int{f.Width, f.Height}, "fractional scale: logical 16x12 is 32x24 buffer pixels")
71}
72
73// The crop must not allocate: it is a window, not a copy.
74func TestCropAllocations(t *testing.T) {
75	if raceEnabled {
76		t.Skip("race instrumentation changes allocation counts")
77	}
78	out := &output{id: 1, width: 1920, height: 1080, scale: 1}
79	f := ports.Frame{Pixels: make([]byte, 1920*1080*4), Width: 1920, Height: 1080, Stride: 1920 * 4, Format: ports.XRGB8888}
80	r := ports.Region{X: 100, Y: 100, Width: 800, Height: 600}
81	runtime.GC()
82	avg := testing.AllocsPerRun(1000, func() {
83		if _, err := cropFrame(f, r, out); err != nil {
84			panic(err)
85		}
86	})
87	require.Zero(t, avg)
88}

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 2

Tags 9

↑↓ moveenter openesc close