detached d852566

test(daemon): harden floating coordinate regressions

commit
d8525660fa938bed266f1fe43cea2b8f4915708a
author
brice · · 2026-07-11 05:23 UTC
parent
37d52d3
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
1 file · +39 -0
M internal/usecase/daemon/floating_render_test.go +39 -0
@@ -31,6 +31,45 @@ func TestFloatingGeometryTranslate(t *testing.T) {
3131 }, geometry)
3232 }
3333
34+func TestFloatingFrameGeometryPreservesBorderRules(t *testing.T) {
35+ const frameX, frameY = 7, 3
36+ tests := []struct {
37+ name string
38+ content domain.Rect
39+ cfg domain.FloatingConfig
40+ tinyWidth, tinyHeight bool
41+ }{
42+ {name: "normal", content: domain.Rect{Width: 80, Height: 24}, cfg: domain.FloatingConfig{Width: 80, Height: 75}},
43+ {name: "tiny width omits horizontal borders", content: domain.Rect{Width: 2, Height: 20}, cfg: domain.FloatingConfig{Width: 100, Height: 100}, tinyWidth: true},
44+ {name: "tiny height omits vertical borders", content: domain.Rect{Width: 20, Height: 2}, cfg: domain.FloatingConfig{Width: 100, Height: 100}, tinyHeight: true},
45+ {name: "full size", content: domain.Rect{Width: 80, Height: 24}, cfg: domain.FloatingConfig{Width: 100, Height: 100}},
46+ }
47+ for _, tt := range tests {
48+ t.Run(tt.name, func(t *testing.T) {
49+ contentGeometry := calculateFloatingGeometry(tt.content, tt.cfg)
50+ frameGeometry := contentGeometry.translate(frameX, frameY)
51+
52+ require.Equal(t, contentGeometry.Bounds.X+frameX, frameGeometry.Bounds.X)
53+ require.Equal(t, contentGeometry.Bounds.Y+frameY, frameGeometry.Bounds.Y)
54+ require.Equal(t, contentGeometry.Inner.X+frameX, frameGeometry.Inner.X)
55+ require.Equal(t, contentGeometry.Inner.Y+frameY, frameGeometry.Inner.Y)
56+ require.Equal(t, contentGeometry.Bounds.Width, frameGeometry.Bounds.Width)
57+ require.Equal(t, contentGeometry.Bounds.Height, frameGeometry.Bounds.Height)
58+ require.Equal(t, contentGeometry.Inner.Width, frameGeometry.Inner.Width)
59+ require.Equal(t, contentGeometry.Inner.Height, frameGeometry.Inner.Height)
60+
61+ if tt.tinyWidth {
62+ require.Equal(t, frameGeometry.Bounds.X, frameGeometry.Inner.X)
63+ require.Equal(t, frameGeometry.Bounds.Width, frameGeometry.Inner.Width)
64+ }
65+ if tt.tinyHeight {
66+ require.Equal(t, frameGeometry.Bounds.Y, frameGeometry.Inner.Y)
67+ require.Equal(t, frameGeometry.Bounds.Height, frameGeometry.Inner.Height)
68+ }
69+ })
70+ }
71+}
72+
3473 func TestCalculateFloatingGeometry(t *testing.T) {
3574 tests := []struct {
3675 name string
@@ -31,6 +31,45 @@ func TestFloatingGeometryTranslate(t *testing.T) {
31 }, geometry)31 }, geometry)
32 }32 }
33 33
34+func TestFloatingFrameGeometryPreservesBorderRules(t *testing.T) {
35+ const frameX, frameY = 7, 3
36+ tests := []struct {
37+ name string
38+ content domain.Rect
39+ cfg domain.FloatingConfig
40+ tinyWidth, tinyHeight bool
41+ }{
42+ {name: "normal", content: domain.Rect{Width: 80, Height: 24}, cfg: domain.FloatingConfig{Width: 80, Height: 75}},
43+ {name: "tiny width omits horizontal borders", content: domain.Rect{Width: 2, Height: 20}, cfg: domain.FloatingConfig{Width: 100, Height: 100}, tinyWidth: true},
44+ {name: "tiny height omits vertical borders", content: domain.Rect{Width: 20, Height: 2}, cfg: domain.FloatingConfig{Width: 100, Height: 100}, tinyHeight: true},
45+ {name: "full size", content: domain.Rect{Width: 80, Height: 24}, cfg: domain.FloatingConfig{Width: 100, Height: 100}},
46+ }
47+ for _, tt := range tests {
48+ t.Run(tt.name, func(t *testing.T) {
49+ contentGeometry := calculateFloatingGeometry(tt.content, tt.cfg)
50+ frameGeometry := contentGeometry.translate(frameX, frameY)
51+
52+ require.Equal(t, contentGeometry.Bounds.X+frameX, frameGeometry.Bounds.X)
53+ require.Equal(t, contentGeometry.Bounds.Y+frameY, frameGeometry.Bounds.Y)
54+ require.Equal(t, contentGeometry.Inner.X+frameX, frameGeometry.Inner.X)
55+ require.Equal(t, contentGeometry.Inner.Y+frameY, frameGeometry.Inner.Y)
56+ require.Equal(t, contentGeometry.Bounds.Width, frameGeometry.Bounds.Width)
57+ require.Equal(t, contentGeometry.Bounds.Height, frameGeometry.Bounds.Height)
58+ require.Equal(t, contentGeometry.Inner.Width, frameGeometry.Inner.Width)
59+ require.Equal(t, contentGeometry.Inner.Height, frameGeometry.Inner.Height)
60+
61+ if tt.tinyWidth {
62+ require.Equal(t, frameGeometry.Bounds.X, frameGeometry.Inner.X)
63+ require.Equal(t, frameGeometry.Bounds.Width, frameGeometry.Inner.Width)
64+ }
65+ if tt.tinyHeight {
66+ require.Equal(t, frameGeometry.Bounds.Y, frameGeometry.Inner.Y)
67+ require.Equal(t, frameGeometry.Bounds.Height, frameGeometry.Inner.Height)
68+ }
69+ })
70+ }
71+}
72+
34 func TestCalculateFloatingGeometry(t *testing.T) {73 func TestCalculateFloatingGeometry(t *testing.T) {
35 tests := []struct {74 tests := []struct {
36 name string75 name string

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 12

Tags 11

↑↓ moveenter openesc close