v0.4.0 0b9cfda

render_test.go RawHistoryFolder

1package graphicsharness
2
3import (
4	"bytes"
5	_ "embed"
6	"encoding/base64"
7	"image/color"
8	"strings"
9	"testing"
10
11	"github.com/stretchr/testify/require"
12
13	vt "github.com/bnema/vev-vt"
14	"github.com/bnema/vev-vt/graphics"
15)
16
17//go:embed testdata/pngsuite-exif2c08.png.b64
18var pngSuiteEXIFBase64 string
19
20//go:embed testdata/demo.apc
21var demoAPC []byte
22
23func TestRenderTerminalDemo(t *testing.T) {
24	geometry := vt.Geometry{Cols: 4, Rows: 4, PixelWidth: 4, PixelHeight: 4}
25	screen := vt.NewScreen(geometry.Cols, geometry.Rows)
26	screen.SetGeometry(geometry)
27	screen.Write(demoAPC)
28	require.Equal(t, uint64(2), screen.GraphicsSnapshot().Usage().Assets)
29	require.Equal(t, uint64(2), screen.GraphicsSnapshot().Usage().Placements)
30	placements := screen.GraphicsSnapshot().Placements()
31	require.Equal(t, graphics.PixelRect{X: 1, Y: 1, Width: 2, Height: 2}, placements[1].Destination())
32	require.Equal(t, graphics.PixelRect{Width: 2, Height: 2}, placements[1].Source())
33	require.Equal(t, int64(1), placements[1].Layer())
34
35	frame, err := RenderTerminal(demoAPC, geometry)
36	require.NoError(t, err)
37	require.Equal(t, color.RGBA{22, 62, 143, 255}, frame.RGBAAt(0, 0))
38	require.Equal(t, color.RGBA{168, 67, 106, 255}, frame.RGBAAt(1, 1))
39}
40
41func TestRenderTerminalAPC(t *testing.T) {
42	frame, err := RenderTerminal([]byte("\x1b_Ga=T,i=1,f=32,s=1,v=1;/wAA/w\x1b\\"), vt.Geometry{Cols: 1, Rows: 1, PixelWidth: 1, PixelHeight: 1})
43	require.NoError(t, err)
44	require.Equal(t, color.RGBA{255, 0, 0, 255}, frame.RGBAAt(0, 0))
45}
46
47func TestRenderDecodesMetadataBearingPNG(t *testing.T) {
48	encoded, err := base64.StdEncoding.DecodeString(pngSuiteEXIFBase64)
49	require.NoError(t, err)
50	require.True(t, bytes.Contains(encoded, []byte("eXIf")), "fixture must retain its eXIf metadata chunk")
51
52	input := []byte("\x1b_Ga=T,i=1,f=100;" + strings.ReplaceAll(pngSuiteEXIFBase64, "\n", "") + "\x1b\\")
53	frame, err := RenderTerminal(input, vt.Geometry{Cols: 32, Rows: 32, PixelWidth: 32, PixelHeight: 32})
54	require.NoError(t, err)
55	require.Equal(t, 32, frame.Bounds().Dx())
56	require.Equal(t, 32, frame.Bounds().Dy())
57}
58
59func TestRenderRejectsPNGDimensionsDifferentFromSnapshot(t *testing.T) {
60	encoded, err := base64.StdEncoding.DecodeString(pngSuiteEXIFBase64)
61	require.NoError(t, err)
62	scene := graphics.NewScene(graphics.Limits{})
63	assetID, err := scene.AddAsset(graphics.AssetBlob{Format: graphics.AssetFormatPNG, Width: 31, Height: 32, Encoded: encoded})
64	require.NoError(t, err)
65	_, err = scene.Place(graphics.PlacementSpec{Asset: assetID, Destination: graphics.PixelRect{Width: 31, Height: 32}})
66	require.NoError(t, err)
67
68	_, err = Render(scene.Snapshot(), graphics.PixelRect{Width: 31, Height: 32})
69	require.EqualError(t, err, "decode asset a1: PNG dimensions do not match snapshot")
70}
71
72func TestRenderScalesCropsAndClips(t *testing.T) {
73	scene := graphics.NewScene(graphics.Limits{})
74	assetID, err := scene.AddAsset(graphics.AssetBlob{
75		Format: graphics.AssetFormatRGBA,
76		Width:  3,
77		Height: 2,
78		Encoded: []byte{
79			255, 0, 0, 255, 0, 255, 0, 255, 0, 0, 255, 255,
80			0, 255, 255, 255, 255, 0, 255, 255, 255, 255, 0, 255,
81		},
82	})
83	require.NoError(t, err)
84	_, err = scene.Place(graphics.PlacementSpec{
85		Asset:       assetID,
86		Source:      graphics.PixelRect{X: 1, Width: 2, Height: 2},
87		Destination: graphics.PixelRect{X: -1, Y: 1, Width: 5, Height: 2},
88	})
89	require.NoError(t, err)
90
91	frame, err := Render(scene.Snapshot(), graphics.PixelRect{Width: 4, Height: 4})
92	require.NoError(t, err)
93
94	for x, want := range []color.RGBA{{0, 255, 0, 255}, {0, 255, 0, 255}, {0, 0, 255, 255}, {0, 0, 255, 255}} {
95		require.Equal(t, want, frame.RGBAAt(x, 1))
96	}
97	for x, want := range []color.RGBA{{255, 0, 255, 255}, {255, 0, 255, 255}, {255, 255, 0, 255}, {255, 255, 0, 255}} {
98		require.Equal(t, want, frame.RGBAAt(x, 2))
99	}
100}
101
102func TestRenderCompositesPlacementsInLayerOrder(t *testing.T) {
103	scene := graphics.NewScene(graphics.Limits{})
104	background, err := scene.AddAsset(graphics.AssetBlob{Format: graphics.AssetFormatRGBA, Width: 2, Height: 1, Encoded: []byte{0, 0, 255, 255, 0, 0, 255, 255}})
105	require.NoError(t, err)
106	foreground, err := scene.AddAsset(graphics.AssetBlob{Format: graphics.AssetFormatRGBA, Width: 1, Height: 1, Encoded: []byte{255, 0, 0, 128}})
107	require.NoError(t, err)
108	_, err = scene.Place(graphics.PlacementSpec{Asset: background, Destination: graphics.PixelRect{Width: 2, Height: 1}, HasLayer: true})
109	require.NoError(t, err)
110	_, err = scene.Place(graphics.PlacementSpec{Asset: foreground, Destination: graphics.PixelRect{X: 1, Width: 1, Height: 1}, Layer: 1, HasLayer: true})
111	require.NoError(t, err)
112
113	frame, err := Render(scene.Snapshot(), graphics.PixelRect{Width: 2, Height: 1})
114	require.NoError(t, err)
115	require.Equal(t, color.RGBA{0, 0, 255, 255}, frame.RGBAAt(0, 0))
116	require.Equal(t, color.RGBA{128, 0, 127, 255}, frame.RGBAAt(1, 0))
117}

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 13

↑↓ moveenter openesc close