gui/pkg/screen/service_test.go
Claude 18a455b460
Some checks failed
Security Scan / security (push) Failing after 25s
refactor: migrate entire gui to Core v0.8.0 API
- Import paths: forge.lthn.ai/core/go → dappco.re/go/core
- Import paths: forge.lthn.ai/core/go-log → dappco.re/go/core/log
- Import paths: forge.lthn.ai/core/go-io → dappco.re/go/core/io
- RegisterTask → c.Action("name", handler) across all 15 services
- QueryHandler signature: (any, bool, error) → core.Result
- PERFORM(task) → Action.Run(ctx, opts)
- QUERY returns single core.Result (not 3 values)
- All 17 packages build and test clean on v0.8.0-alpha.1

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 16:14:19 +01:00

310 lines
8.5 KiB
Go

// pkg/screen/service_test.go
package screen
import (
"context"
"testing"
core "dappco.re/go/core"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
type mockPlatform struct {
screens []Screen
current *Screen
}
func (m *mockPlatform) GetAll() []Screen { return m.screens }
func (m *mockPlatform) GetPrimary() *Screen {
for i := range m.screens {
if m.screens[i].IsPrimary {
return &m.screens[i]
}
}
return nil
}
func (m *mockPlatform) GetCurrent() *Screen {
if m.current != nil {
return m.current
}
return m.GetPrimary()
}
func newTestService(t *testing.T) (*mockPlatform, *core.Core) {
t.Helper()
mock := &mockPlatform{
screens: []Screen{
{
ID: "1", Name: "Built-in", IsPrimary: true,
Bounds: Rect{X: 0, Y: 0, Width: 2560, Height: 1600},
WorkArea: Rect{X: 0, Y: 38, Width: 2560, Height: 1562},
Size: Size{Width: 2560, Height: 1600},
},
{
ID: "2", Name: "External",
Bounds: Rect{X: 2560, Y: 0, Width: 1920, Height: 1080},
WorkArea: Rect{X: 2560, Y: 0, Width: 1920, Height: 1080},
Size: Size{Width: 1920, Height: 1080},
},
},
}
c := core.New(
core.WithService(Register(mock)),
core.WithServiceLock(),
)
require.True(t, c.ServiceStartup(context.Background(), nil).OK)
return mock, c
}
func TestRegister_Good(t *testing.T) {
_, c := newTestService(t)
svc := core.MustServiceFor[*Service](c, "screen")
assert.NotNil(t, svc)
}
func TestQueryAll_Good(t *testing.T) {
_, c := newTestService(t)
r := c.QUERY(QueryAll{})
require.True(t, r.OK)
screens := r.Value.([]Screen)
assert.Len(t, screens, 2)
}
func TestQueryPrimary_Good(t *testing.T) {
_, c := newTestService(t)
r := c.QUERY(QueryPrimary{})
require.True(t, r.OK)
scr := r.Value.(*Screen)
require.NotNil(t, scr)
assert.Equal(t, "Built-in", scr.Name)
assert.True(t, scr.IsPrimary)
}
func TestQueryByID_Good(t *testing.T) {
_, c := newTestService(t)
r := c.QUERY(QueryByID{ID: "2"})
require.True(t, r.OK)
scr := r.Value.(*Screen)
require.NotNil(t, scr)
assert.Equal(t, "External", scr.Name)
}
func TestQueryByID_Bad(t *testing.T) {
_, c := newTestService(t)
r := c.QUERY(QueryByID{ID: "99"})
require.True(t, r.OK)
assert.Nil(t, r.Value)
}
func TestQueryAtPoint_Good(t *testing.T) {
_, c := newTestService(t)
// Point on primary screen
r := c.QUERY(QueryAtPoint{X: 100, Y: 100})
require.True(t, r.OK)
scr := r.Value.(*Screen)
require.NotNil(t, scr)
assert.Equal(t, "Built-in", scr.Name)
// Point on external screen
r2 := c.QUERY(QueryAtPoint{X: 3000, Y: 500})
scr = r2.Value.(*Screen)
require.NotNil(t, scr)
assert.Equal(t, "External", scr.Name)
}
func TestQueryAtPoint_Bad(t *testing.T) {
_, c := newTestService(t)
r := c.QUERY(QueryAtPoint{X: -1000, Y: -1000})
require.True(t, r.OK)
assert.Nil(t, r.Value)
}
func TestQueryWorkAreas_Good(t *testing.T) {
_, c := newTestService(t)
r := c.QUERY(QueryWorkAreas{})
require.True(t, r.OK)
areas := r.Value.([]Rect)
assert.Len(t, areas, 2)
assert.Equal(t, 38, areas[0].Y) // primary has menu bar offset
}
// --- QueryCurrent ---
func TestQueryCurrent_Good(t *testing.T) {
// current falls back to primary when not explicitly set
_, c := newTestService(t)
r := c.QUERY(QueryCurrent{})
require.True(t, r.OK)
scr := r.Value.(*Screen)
require.NotNil(t, scr)
assert.True(t, scr.IsPrimary)
assert.Equal(t, "Built-in", scr.Name)
}
func TestQueryCurrent_Bad(t *testing.T) {
// no screens at all → GetCurrent returns nil
mock := &mockPlatform{screens: []Screen{}}
c := core.New(
core.WithService(Register(mock)),
core.WithServiceLock(),
)
require.True(t, c.ServiceStartup(context.Background(), nil).OK)
r := c.QUERY(QueryCurrent{})
require.True(t, r.OK)
assert.Nil(t, r.Value)
}
func TestQueryCurrent_Ugly(t *testing.T) {
// current is explicitly set to the external screen
mock := &mockPlatform{
screens: []Screen{
{ID: "1", Name: "Built-in", IsPrimary: true,
Bounds: Rect{X: 0, Y: 0, Width: 2560, Height: 1600}},
{ID: "2", Name: "External",
Bounds: Rect{X: 2560, Y: 0, Width: 1920, Height: 1080}},
},
}
mock.current = &mock.screens[1]
c := core.New(
core.WithService(Register(mock)),
core.WithServiceLock(),
)
require.True(t, c.ServiceStartup(context.Background(), nil).OK)
r := c.QUERY(QueryCurrent{})
scr := r.Value.(*Screen)
require.NotNil(t, scr)
assert.Equal(t, "External", scr.Name)
}
// --- Rect geometry helpers ---
func TestRect_Origin_Good(t *testing.T) {
r := Rect{X: 10, Y: 20, Width: 100, Height: 50}
pt := r.Origin()
assert.Equal(t, Point{X: 10, Y: 20}, pt)
}
func TestRect_Corner_Good(t *testing.T) {
r := Rect{X: 10, Y: 20, Width: 100, Height: 50}
pt := r.Corner()
assert.Equal(t, Point{X: 110, Y: 70}, pt)
}
func TestRect_InsideCorner_Good(t *testing.T) {
r := Rect{X: 10, Y: 20, Width: 100, Height: 50}
pt := r.InsideCorner()
assert.Equal(t, Point{X: 109, Y: 69}, pt)
}
func TestRect_IsEmpty_Good(t *testing.T) {
assert.False(t, Rect{X: 0, Y: 0, Width: 1, Height: 1}.IsEmpty())
}
func TestRect_IsEmpty_Bad(t *testing.T) {
assert.True(t, Rect{}.IsEmpty())
assert.True(t, Rect{Width: 0, Height: 10}.IsEmpty())
assert.True(t, Rect{Width: 10, Height: -1}.IsEmpty())
}
func TestRect_Contains_Good(t *testing.T) {
r := Rect{X: 0, Y: 0, Width: 100, Height: 100}
assert.True(t, r.Contains(Point{X: 0, Y: 0}))
assert.True(t, r.Contains(Point{X: 50, Y: 50}))
assert.True(t, r.Contains(Point{X: 99, Y: 99}))
}
func TestRect_Contains_Bad(t *testing.T) {
r := Rect{X: 0, Y: 0, Width: 100, Height: 100}
// exclusive right/bottom edge
assert.False(t, r.Contains(Point{X: 100, Y: 50}))
assert.False(t, r.Contains(Point{X: 50, Y: 100}))
assert.False(t, r.Contains(Point{X: -1, Y: 50}))
}
func TestRect_Contains_Ugly(t *testing.T) {
// zero-size rect never contains anything
r := Rect{X: 5, Y: 5, Width: 0, Height: 0}
assert.False(t, r.Contains(Point{X: 5, Y: 5}))
}
func TestRect_RectSize_Good(t *testing.T) {
r := Rect{X: 100, Y: 200, Width: 1920, Height: 1080}
sz := r.RectSize()
assert.Equal(t, Size{Width: 1920, Height: 1080}, sz)
}
func TestRect_Intersect_Good(t *testing.T) {
a := Rect{X: 0, Y: 0, Width: 100, Height: 100}
b := Rect{X: 50, Y: 50, Width: 100, Height: 100}
overlap := a.Intersect(b)
assert.Equal(t, Rect{X: 50, Y: 50, Width: 50, Height: 50}, overlap)
}
func TestRect_Intersect_Bad(t *testing.T) {
// no overlap
a := Rect{X: 0, Y: 0, Width: 50, Height: 50}
b := Rect{X: 100, Y: 100, Width: 50, Height: 50}
overlap := a.Intersect(b)
assert.True(t, overlap.IsEmpty())
}
func TestRect_Intersect_Ugly(t *testing.T) {
// empty rect intersects nothing
a := Rect{X: 0, Y: 0, Width: 0, Height: 0}
b := Rect{X: 0, Y: 0, Width: 100, Height: 100}
overlap := a.Intersect(b)
assert.True(t, overlap.IsEmpty())
}
// --- ScreenPlacement ---
func TestScreenPlacement_Apply_Good(t *testing.T) {
// secondary placed to the RIGHT of primary, no offset
primary := &Screen{
Bounds: Rect{X: 0, Y: 0, Width: 2560, Height: 1600},
WorkArea: Rect{X: 0, Y: 38, Width: 2560, Height: 1562},
}
secondary := &Screen{
Bounds: Rect{X: 3000, Y: 0, Width: 1920, Height: 1080},
WorkArea: Rect{X: 3000, Y: 0, Width: 1920, Height: 1080},
}
NewPlacement(secondary, primary, AlignRight, 0, OffsetBegin).Apply()
assert.Equal(t, 2560, secondary.Bounds.X)
assert.Equal(t, 0, secondary.Bounds.Y)
assert.Equal(t, 2560, secondary.WorkArea.X)
}
func TestScreenPlacement_Apply_Bad(t *testing.T) {
// screen placed ABOVE primary: newY = primary.Y - secondary.Height
primary := &Screen{
Bounds: Rect{X: 0, Y: 0, Width: 1920, Height: 1080},
WorkArea: Rect{X: 0, Y: 0, Width: 1920, Height: 1080},
}
secondary := &Screen{
Bounds: Rect{X: 0, Y: -600, Width: 1920, Height: 600},
WorkArea: Rect{X: 0, Y: -600, Width: 1920, Height: 600},
}
NewPlacement(secondary, primary, AlignTop, 0, OffsetBegin).Apply()
assert.Equal(t, 0, secondary.Bounds.X)
assert.Equal(t, -600, secondary.Bounds.Y)
}
func TestScreenPlacement_Apply_Ugly(t *testing.T) {
// END offset reference — places secondary flush to the bottom-right of parent
primary := &Screen{
Bounds: Rect{X: 0, Y: 0, Width: 1920, Height: 1080},
WorkArea: Rect{X: 0, Y: 0, Width: 1920, Height: 1080},
}
secondary := &Screen{
Bounds: Rect{X: 0, Y: 0, Width: 800, Height: 600},
WorkArea: Rect{X: 0, Y: 0, Width: 800, Height: 600},
}
// AlignBottom + OffsetEnd + offset=0 → secondary starts at right edge of parent
NewPlacement(secondary, primary, AlignBottom, 0, OffsetEnd).Apply()
assert.Equal(t, 1920-800, secondary.Bounds.X) // flush right
assert.Equal(t, 1080, secondary.Bounds.Y) // just below parent
}