Some checks failed
Security Scan / security (push) Failing after 25s
- 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>
310 lines
8.5 KiB
Go
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
|
|
}
|