gui/pkg/window/tiling_test.go
Snider 8abfca31e7 feat(gui): 4 smart layout helpers + Good/Bad/Ugly coverage
Added layout primitives to pkg/window/tiling.go:
- BesideEditor — position a window beside an editor, same height,
  on the side with more empty space
- SuggestLayout — layout N windows on screen (golden-ratio split
  for 2, grid for 3+)
- FindEmptySpace — find the largest rectangular empty region that
  fits a minimum size; return (rect, ok)
- ArrangePair — 60/40 or 50/50 split based on aspect ratios

Plus Rect/Size aliases and a WindowPlacement type. Good/Bad/Ugly
test coverage + godoc examples.

pkg/mcp/tools_layout.go left unchanged — this branch already
registers layout_beside_editor / layout_suggest / screen_find_space
/ window_arrange_pair on top of the new helpers.

go vet clean. go test pkg/window/... passes under HOME override
(legacy layout-save tests need writeable ~/Library on non-sandbox).

Closes tasks.lthn.sh/view.php?id=30

Co-authored-by: Codex <noreply@openai.com>
Co-Authored-By: Virgil <virgil@lethean.io>
2026-04-24 07:26:22 +01:00

158 lines
4.1 KiB
Go

// pkg/window/tiling_test.go
package window
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestTiling_SnapPosition_String_Good(t *testing.T) {
tests := []struct {
name string
pos SnapPosition
want string
}{
{name: "left", pos: SnapLeft, want: "left"},
{name: "right", pos: SnapRight, want: "right"},
{name: "center", pos: SnapCenter, want: "center"},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
assert.Equal(t, tc.want, tc.pos.String())
})
}
}
func TestTiling_SnapPosition_String_Bad(t *testing.T) {
assert.Empty(t, SnapPosition(123).String())
}
func TestTiling_SnapPosition_String_Ugly(t *testing.T) {
assert.Empty(t, SnapPosition(-1).String())
}
func TestBesideEditor_Good(t *testing.T) {
rect := BesideEditor(
Rect{X: 200, Y: 50, Width: 900, Height: 800},
Size{Width: 1600, Height: 1000},
)
assert.Equal(t, Rect{X: 1100, Y: 50, Width: 500, Height: 800}, rect)
}
func TestBesideEditor_Bad(t *testing.T) {
rect := BesideEditor(
Rect{X: 0, Y: 0, Width: 1600, Height: 900},
Size{Width: 1600, Height: 900},
)
assert.Equal(t, Rect{}, rect)
}
func TestBesideEditor_Ugly(t *testing.T) {
rect := BesideEditor(
Rect{X: -100, Y: 20, Width: 700, Height: 900},
Size{Width: 1600, Height: 1000},
)
assert.Equal(t, Rect{X: 600, Y: 20, Width: 1000, Height: 900}, rect)
}
func TestSuggestLayout_Good(t *testing.T) {
placements := SuggestLayout(
[]Window{{Name: "editor"}, {Name: "preview"}},
Rect{X: 0, Y: 0, Width: 1600, Height: 900},
)
assert.Equal(t, []WindowPlacement{
{Name: "editor", Bounds: Rect{X: 0, Y: 0, Width: 989, Height: 900}},
{Name: "preview", Bounds: Rect{X: 989, Y: 0, Width: 611, Height: 900}},
}, placements)
}
func TestSuggestLayout_Bad(t *testing.T) {
placements := SuggestLayout(nil, Rect{X: 0, Y: 0, Width: 1600, Height: 900})
assert.Nil(t, placements)
}
func TestSuggestLayout_Ugly(t *testing.T) {
placements := SuggestLayout(
[]Window{{Name: "one"}, {Name: "two"}, {Name: "three"}},
Rect{X: 100, Y: 50, Width: 1500, Height: 900},
)
assert.Equal(t, []WindowPlacement{
{Name: "one", Bounds: Rect{X: 100, Y: 50, Width: 750, Height: 450}},
{Name: "two", Bounds: Rect{X: 850, Y: 50, Width: 750, Height: 450}},
{Name: "three", Bounds: Rect{X: 100, Y: 500, Width: 750, Height: 450}},
}, placements)
}
func TestFindEmptySpace_Good(t *testing.T) {
space, ok := FindEmptySpace(
Rect{X: 0, Y: 0, Width: 1600, Height: 1000},
[]Window{{Name: "left", X: 0, Y: 0, Width: 800, Height: 1000}},
Size{Width: 400, Height: 300},
)
assert.True(t, ok)
assert.Equal(t, Rect{X: 800, Y: 0, Width: 800, Height: 1000}, space)
}
func TestFindEmptySpace_Bad(t *testing.T) {
space, ok := FindEmptySpace(
Rect{X: 0, Y: 0, Width: 800, Height: 600},
nil,
Size{Width: 1200, Height: 700},
)
assert.False(t, ok)
assert.Equal(t, Rect{}, space)
}
func TestFindEmptySpace_Ugly(t *testing.T) {
space, ok := FindEmptySpace(
Rect{X: 0, Y: 0, Width: 1000, Height: 800},
[]Window{
{Name: "header", X: 0, Y: 0, Width: 1000, Height: 100},
{Name: "rail", X: 0, Y: 100, Width: 300, Height: 700},
{Name: "inspector", X: 700, Y: 300, Width: 300, Height: 200},
},
Size{Width: 200, Height: 200},
)
assert.True(t, ok)
assert.Equal(t, Rect{X: 300, Y: 100, Width: 400, Height: 700}, space)
}
func TestArrangePair_Good(t *testing.T) {
left, right := ArrangePair(
Window{Name: "editor", Width: 1280, Height: 800},
Window{Name: "terminal", Width: 1280, Height: 800},
Rect{X: 0, Y: 0, Width: 2000, Height: 1000},
)
assert.Equal(t, Rect{X: 0, Y: 0, Width: 1000, Height: 1000}, left)
assert.Equal(t, Rect{X: 1000, Y: 0, Width: 1000, Height: 1000}, right)
}
func TestArrangePair_Bad(t *testing.T) {
left, right := ArrangePair(Window{}, Window{}, Rect{})
assert.Equal(t, Rect{}, left)
assert.Equal(t, Rect{}, right)
}
func TestArrangePair_Ugly(t *testing.T) {
left, right := ArrangePair(
Window{Name: "chat", Width: 800, Height: 1600},
Window{Name: "editor", Width: 1600, Height: 900},
Rect{X: 0, Y: 0, Width: 2000, Height: 1000},
)
assert.Equal(t, Rect{X: 0, Y: 0, Width: 800, Height: 1000}, left)
assert.Equal(t, Rect{X: 800, Y: 0, Width: 1200, Height: 1000}, right)
}