Add display wrapper coverage
Some checks are pending
Security Scan / security (push) Waiting to run
Test / test (push) Waiting to run

This commit is contained in:
Snider 2026-04-17 19:47:15 +01:00
parent 86d0a5d525
commit fb43e9a729
3 changed files with 650 additions and 2 deletions

View file

@ -1,2 +0,0 @@
- @coverage pkg/display/api.go:286 — Tray, clipboard, notification, and theme wrapper methods still need direct unit coverage for their remaining branches.
- @coverage pkg/display/display.go:1469 — Layout delegation wrappers for delete/tile/snap/stack/workflow/screen-space/pair-arrangement still need unit coverage.

View file

@ -0,0 +1,371 @@
package display
import (
"context"
"testing"
core "dappco.re/go/core"
"forge.lthn.ai/core/gui/pkg/clipboard"
"forge.lthn.ai/core/gui/pkg/environment"
"forge.lthn.ai/core/gui/pkg/notification"
"forge.lthn.ai/core/gui/pkg/systray"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
type errorOnlyWrapperCase struct {
name string
action string
call func(*Service) error
setupGood func(*testing.T, *core.Core)
}
func runErrorOnlyWrapperCase(t *testing.T, tc errorOnlyWrapperCase) {
t.Helper()
t.Run("good", func(t *testing.T) {
svc, c := newTestDisplayAPIService(t)
if tc.setupGood != nil {
tc.setupGood(t, c)
}
require.NoError(t, tc.call(svc))
})
t.Run("bad", func(t *testing.T) {
svc, c := newTestDisplayAPIService(t)
c.Action(tc.action, func(_ context.Context, _ core.Options) core.Result {
return core.Result{Value: assert.AnError, OK: false}
})
err := tc.call(svc)
require.Error(t, err)
assert.Equal(t, assert.AnError, err)
})
t.Run("ugly", func(t *testing.T) {
svc, c := newTestDisplayAPIService(t)
c.Action(tc.action, func(_ context.Context, _ core.Options) core.Result {
return core.Result{Value: "unexpected", OK: false}
})
err := tc.call(svc)
require.Error(t, err)
assert.Contains(t, err.Error(), tc.action)
})
}
func TestDisplayAPI_TrayWrappers(t *testing.T) {
cases := []errorOnlyWrapperCase{
{
name: "SetTrayTooltip",
action: "systray.setTooltip",
call: func(svc *Service) error {
return svc.SetTrayTooltip("Helper tooltip")
},
setupGood: func(t *testing.T, c *core.Core) {
t.Helper()
c.Action("systray.setTooltip", func(_ context.Context, opts core.Options) core.Result {
task := opts.Get("task").Value.(systray.TaskSetTrayTooltip)
assert.Equal(t, "Helper tooltip", task.Tooltip)
return core.Result{OK: true}
})
},
},
{
name: "SetTrayLabel",
action: "systray.setLabel",
call: func(svc *Service) error {
return svc.SetTrayLabel("Launcher")
},
setupGood: func(t *testing.T, c *core.Core) {
t.Helper()
c.Action("systray.setLabel", func(_ context.Context, opts core.Options) core.Result {
task := opts.Get("task").Value.(systray.TaskSetTrayLabel)
assert.Equal(t, "Launcher", task.Label)
return core.Result{OK: true}
})
},
},
{
name: "SetTrayMenu",
action: "systray.setMenu",
call: func(svc *Service) error {
return svc.SetTrayMenu([]TrayMenuItem{
{Label: "Open", ActionID: "open"},
{
Label: "More",
ActionID: "more",
Children: []TrayMenuItem{{Label: "Nested", ActionID: "nested"}},
},
})
},
setupGood: func(t *testing.T, c *core.Core) {
t.Helper()
c.Action("systray.setMenu", func(_ context.Context, opts core.Options) core.Result {
task := opts.Get("task").Value.(systray.TaskSetTrayMenu)
require.Len(t, task.Items, 2)
assert.Equal(t, "Open", task.Items[0].Label)
require.Len(t, task.Items[1].Submenu, 1)
assert.Equal(t, "nested", task.Items[1].Submenu[0].ActionID)
return core.Result{OK: true}
})
},
},
{
name: "ShowTrayMessage",
action: "systray.showMessage",
call: func(svc *Service) error {
return svc.ShowTrayMessage("Status", "Task complete")
},
setupGood: func(t *testing.T, c *core.Core) {
t.Helper()
c.Action("systray.showMessage", func(_ context.Context, opts core.Options) core.Result {
task := opts.Get("task").Value.(systray.TaskShowMessage)
assert.Equal(t, "Status", task.Title)
assert.Equal(t, "Task complete", task.Message)
return core.Result{OK: true}
})
},
},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
runErrorOnlyWrapperCase(t, tc)
})
}
}
func TestDisplayAPI_ClipboardWrappers(t *testing.T) {
t.Run("ClearClipboard", func(t *testing.T) {
runErrorOnlyWrapperCase(t, errorOnlyWrapperCase{
name: "ClearClipboard",
action: "clipboard.clear",
call: func(svc *Service) error {
return svc.ClearClipboard()
},
setupGood: func(t *testing.T, c *core.Core) {
t.Helper()
c.Action("clipboard.clear", func(_ context.Context, opts core.Options) core.Result {
assert.Equal(t, 0, opts.Len())
return core.Result{OK: true}
})
},
})
})
t.Run("HasClipboard", func(t *testing.T) {
svc, c := newTestDisplayAPIService(t)
c.RegisterQuery(func(_ *core.Core, q core.Query) core.Result {
switch q.(type) {
case clipboard.QueryText:
return core.Result{
Value: clipboard.ClipboardContent{
Text: "present",
HasContent: true,
},
OK: true,
}
default:
return core.Result{}
}
})
assert.True(t, svc.HasClipboard())
svc, c = newTestDisplayAPIService(t)
c.RegisterQuery(func(_ *core.Core, q core.Query) core.Result {
switch q.(type) {
case clipboard.QueryText:
return core.Result{
Value: clipboard.ClipboardContent{
Text: "",
HasContent: false,
},
OK: true,
}
default:
return core.Result{}
}
})
assert.False(t, svc.HasClipboard())
svc, c = newTestDisplayAPIService(t)
c.RegisterQuery(func(_ *core.Core, q core.Query) core.Result {
switch q.(type) {
case clipboard.QueryText:
return core.Result{OK: false}
default:
return core.Result{}
}
})
assert.False(t, svc.HasClipboard())
})
}
func TestDisplayAPI_NotificationWrappers(t *testing.T) {
cases := []errorOnlyWrapperCase{
{
name: "ShowNotification",
action: "notification.send",
call: func(svc *Service) error {
return svc.ShowNotification(NotificationOptions{
ID: "alert-1",
Title: "Deploy",
Message: "Done",
Subtitle: "CI",
})
},
setupGood: func(t *testing.T, c *core.Core) {
t.Helper()
c.Action("notification.send", func(_ context.Context, opts core.Options) core.Result {
task := opts.Get("task").Value.(notification.TaskSend)
assert.Equal(t, notification.NotificationOptions{
ID: "alert-1",
Title: "Deploy",
Message: "Done",
Subtitle: "CI",
}, task.Options)
return core.Result{OK: true}
})
},
},
{
name: "ShowInfoNotification",
action: "notification.send",
call: func(svc *Service) error {
return svc.ShowInfoNotification("Info", "Ready")
},
setupGood: func(t *testing.T, c *core.Core) {
t.Helper()
c.Action("notification.send", func(_ context.Context, opts core.Options) core.Result {
task := opts.Get("task").Value.(notification.TaskSend)
assert.Equal(t, notification.NotificationOptions{
Title: "Info",
Message: "Ready",
}, task.Options)
return core.Result{OK: true}
})
},
},
{
name: "ShowWarningNotification",
action: "notification.send",
call: func(svc *Service) error {
return svc.ShowWarningNotification("Warn", "Careful")
},
setupGood: func(t *testing.T, c *core.Core) {
t.Helper()
c.Action("notification.send", func(_ context.Context, opts core.Options) core.Result {
task := opts.Get("task").Value.(notification.TaskSend)
assert.Equal(t, notification.NotificationOptions{
Title: "Warn",
Message: "Careful",
Severity: notification.SeverityWarning,
}, task.Options)
return core.Result{OK: true}
})
},
},
{
name: "ShowErrorNotification",
action: "notification.send",
call: func(svc *Service) error {
return svc.ShowErrorNotification("Error", "Failed")
},
setupGood: func(t *testing.T, c *core.Core) {
t.Helper()
c.Action("notification.send", func(_ context.Context, opts core.Options) core.Result {
task := opts.Get("task").Value.(notification.TaskSend)
assert.Equal(t, notification.NotificationOptions{
Title: "Error",
Message: "Failed",
Severity: notification.SeverityError,
}, task.Options)
return core.Result{OK: true}
})
},
},
{
name: "ClearNotifications",
action: "notification.clear",
call: func(svc *Service) error {
return svc.ClearNotifications()
},
setupGood: func(t *testing.T, c *core.Core) {
t.Helper()
c.Action("notification.clear", func(_ context.Context, opts core.Options) core.Result {
task := opts.Get("task").Value.(notification.TaskClear)
assert.Empty(t, task.ID)
return core.Result{OK: true}
})
},
},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
runErrorOnlyWrapperCase(t, tc)
})
}
}
func TestDisplayAPI_ThemeWrapper(t *testing.T) {
runErrorOnlyWrapperCase(t, errorOnlyWrapperCase{
name: "SetTheme",
action: "environment.setTheme",
call: func(svc *Service) error {
return svc.SetTheme("system")
},
setupGood: func(t *testing.T, c *core.Core) {
t.Helper()
c.Action("environment.setTheme", func(_ context.Context, opts core.Options) core.Result {
task := opts.Get("task").Value.(environment.TaskSetTheme)
assert.Equal(t, "system", task.Theme)
return core.Result{OK: true}
})
},
})
}
func TestDisplayAPI_GetTrayInfo(t *testing.T) {
svc, c := newTestDisplayAPIService(t)
c.RegisterQuery(func(_ *core.Core, q core.Query) core.Result {
switch q.(type) {
case systray.QueryInfo:
return core.Result{
Value: map[string]any{
"tooltip": "Ready",
},
OK: true,
}
default:
return core.Result{}
}
})
info := svc.GetTrayInfo()
require.NotNil(t, info)
assert.Equal(t, "Ready", info["tooltip"])
svc, c = newTestDisplayAPIService(t)
c.RegisterQuery(func(_ *core.Core, q core.Query) core.Result {
switch q.(type) {
case systray.QueryInfo:
return core.Result{Value: "unexpected", OK: true}
default:
return core.Result{}
}
})
assert.Nil(t, svc.GetTrayInfo())
svc, c = newTestDisplayAPIService(t)
c.RegisterQuery(func(_ *core.Core, q core.Query) core.Result {
switch q.(type) {
case systray.QueryInfo:
return core.Result{OK: false}
default:
return core.Result{}
}
})
assert.Nil(t, svc.GetTrayInfo())
}

View file

@ -0,0 +1,279 @@
package display
import (
"context"
"testing"
core "dappco.re/go/core"
"forge.lthn.ai/core/gui/pkg/window"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
type layoutResultWrapperCase struct {
name string
action string
zero any
call func(*Service) (any, error)
setupGood func(*testing.T, *core.Core)
wantGood func(*testing.T, any)
}
func runLayoutResultWrapperCase(t *testing.T, tc layoutResultWrapperCase) {
t.Helper()
t.Run("good", func(t *testing.T) {
svc, c := newTestDisplayAPIService(t)
if tc.setupGood != nil {
tc.setupGood(t, c)
}
got, err := tc.call(svc)
require.NoError(t, err)
tc.wantGood(t, got)
})
t.Run("bad", func(t *testing.T) {
svc, c := newTestDisplayAPIService(t)
c.Action(tc.action, func(_ context.Context, _ core.Options) core.Result {
return core.Result{Value: assert.AnError, OK: false}
})
got, err := tc.call(svc)
require.Error(t, err)
assert.Equal(t, tc.zero, got)
assert.Equal(t, assert.AnError, err)
})
t.Run("ugly-action", func(t *testing.T) {
svc, c := newTestDisplayAPIService(t)
c.Action(tc.action, func(_ context.Context, _ core.Options) core.Result {
return core.Result{Value: "unexpected", OK: false}
})
got, err := tc.call(svc)
require.Error(t, err)
assert.Equal(t, tc.zero, got)
assert.Contains(t, err.Error(), tc.action)
})
t.Run("ugly-type", func(t *testing.T) {
svc, c := newTestDisplayAPIService(t)
c.Action(tc.action, func(_ context.Context, _ core.Options) core.Result {
return core.Result{Value: "unexpected", OK: true}
})
got, err := tc.call(svc)
require.Error(t, err)
assert.Equal(t, tc.zero, got)
assert.Contains(t, err.Error(), "unexpected result type")
})
}
func TestDisplay_LayoutDelegationWrappers(t *testing.T) {
errorCases := []errorOnlyWrapperCase{
{
name: "DeleteLayout",
action: "window.deleteLayout",
call: func(svc *Service) error {
return svc.DeleteLayout("development")
},
setupGood: func(t *testing.T, c *core.Core) {
t.Helper()
c.Action("window.deleteLayout", func(_ context.Context, opts core.Options) core.Result {
task := opts.Get("task").Value.(window.TaskDeleteLayout)
assert.Equal(t, "development", task.Name)
return core.Result{OK: true}
})
},
},
{
name: "TileWindows",
action: "window.tileWindows",
call: func(svc *Service) error {
return svc.TileWindows(window.TileModeGrid, []string{"editor", "terminal"})
},
setupGood: func(t *testing.T, c *core.Core) {
t.Helper()
c.Action("window.tileWindows", func(_ context.Context, opts core.Options) core.Result {
task := opts.Get("task").Value.(window.TaskTileWindows)
assert.Equal(t, window.TileModeGrid.String(), task.Mode)
assert.Equal(t, []string{"editor", "terminal"}, task.Windows)
return core.Result{OK: true}
})
},
},
{
name: "SnapWindow",
action: "window.snapWindow",
call: func(svc *Service) error {
return svc.SnapWindow("preview", window.SnapCenter)
},
setupGood: func(t *testing.T, c *core.Core) {
t.Helper()
c.Action("window.snapWindow", func(_ context.Context, opts core.Options) core.Result {
task := opts.Get("task").Value.(window.TaskSnapWindow)
assert.Equal(t, "preview", task.Name)
assert.Equal(t, window.SnapCenter.String(), task.Position)
return core.Result{OK: true}
})
},
},
{
name: "StackWindows",
action: "window.stackWindows",
call: func(svc *Service) error {
return svc.StackWindows([]string{"editor", "preview"}, 24, 18)
},
setupGood: func(t *testing.T, c *core.Core) {
t.Helper()
c.Action("window.stackWindows", func(_ context.Context, opts core.Options) core.Result {
task := opts.Get("task").Value.(window.TaskStackWindows)
assert.Equal(t, []string{"editor", "preview"}, task.Windows)
assert.Equal(t, 24, task.OffsetX)
assert.Equal(t, 18, task.OffsetY)
return core.Result{OK: true}
})
},
},
{
name: "ApplyWorkflowLayout",
action: "window.applyWorkflow",
call: func(svc *Service) error {
return svc.ApplyWorkflowLayout(window.WorkflowCoding)
},
setupGood: func(t *testing.T, c *core.Core) {
t.Helper()
c.Action("window.applyWorkflow", func(_ context.Context, opts core.Options) core.Result {
task := opts.Get("task").Value.(window.TaskApplyWorkflow)
assert.Equal(t, window.WorkflowCoding.String(), task.Workflow)
return core.Result{OK: true}
})
},
},
}
for _, tc := range errorCases {
t.Run(tc.name, func(t *testing.T) {
runErrorOnlyWrapperCase(t, tc)
})
}
runLayoutResultWrapperCase(t, layoutResultWrapperCase{
name: "LayoutBesideEditor",
action: "window.layoutBesideEditor",
zero: window.LayoutBesideEditorResult{},
call: func(svc *Service) (any, error) {
return svc.LayoutBesideEditor("preview", "code", "right", 0.62)
},
setupGood: func(t *testing.T, c *core.Core) {
t.Helper()
c.Action("window.layoutBesideEditor", func(_ context.Context, opts core.Options) core.Result {
task := opts.Get("task").Value.(window.TaskLayoutBesideEditor)
assert.Equal(t, "preview", task.Name)
assert.Equal(t, "code", task.Editor)
assert.Equal(t, "right", task.Side)
assert.InDelta(t, 0.62, task.Ratio, 0.0001)
return core.Result{
Value: window.LayoutBesideEditorResult{
Editor: "code",
EditorBounds: window.WindowBounds{
X: 10, Y: 20, Width: 640, Height: 800,
},
WindowBounds: window.WindowBounds{
X: 650, Y: 20, Width: 640, Height: 800,
},
Side: "right",
ScreenID: "screen-1",
},
OK: true,
}
})
},
wantGood: func(t *testing.T, got any) {
t.Helper()
result := got.(window.LayoutBesideEditorResult)
assert.Equal(t, "code", result.Editor)
assert.Equal(t, "right", result.Side)
assert.Equal(t, "screen-1", result.ScreenID)
},
})
runLayoutResultWrapperCase(t, layoutResultWrapperCase{
name: "FindScreenSpace",
action: "window.findSpace",
zero: window.ScreenSpace{},
call: func(svc *Service) (any, error) {
return svc.FindScreenSpace("screen-1", 800, 600, 24)
},
setupGood: func(t *testing.T, c *core.Core) {
t.Helper()
c.Action("window.findSpace", func(_ context.Context, opts core.Options) core.Result {
task := opts.Get("task").Value.(window.TaskScreenFindSpace)
assert.Equal(t, "screen-1", task.ScreenID)
assert.Equal(t, 800, task.Width)
assert.Equal(t, 600, task.Height)
assert.Equal(t, 24, task.Padding)
return core.Result{
Value: window.ScreenSpace{
ScreenID: "screen-1",
X: 100,
Y: 120,
Width: 800,
Height: 600,
},
OK: true,
}
})
},
wantGood: func(t *testing.T, got any) {
t.Helper()
space := got.(window.ScreenSpace)
assert.Equal(t, "screen-1", space.ScreenID)
assert.Equal(t, 100, space.X)
assert.Equal(t, 120, space.Y)
assert.Equal(t, 800, space.Width)
assert.Equal(t, 600, space.Height)
},
})
runLayoutResultWrapperCase(t, layoutResultWrapperCase{
name: "ArrangeWindowPair",
action: "window.arrangePair",
zero: window.PairArrangement{},
call: func(svc *Service) (any, error) {
return svc.ArrangeWindowPair("editor", "preview", "screen-1", 0.55)
},
setupGood: func(t *testing.T, c *core.Core) {
t.Helper()
c.Action("window.arrangePair", func(_ context.Context, opts core.Options) core.Result {
task := opts.Get("task").Value.(window.TaskWindowArrangePair)
assert.Equal(t, "editor", task.Primary)
assert.Equal(t, "preview", task.Secondary)
assert.Equal(t, "screen-1", task.ScreenID)
assert.InDelta(t, 0.55, task.Ratio, 0.0001)
return core.Result{
Value: window.PairArrangement{
Primary: window.WindowBounds{
X: 0, Y: 0, Width: 800, Height: 600,
},
Secondary: window.WindowBounds{
X: 800, Y: 0, Width: 800, Height: 600,
},
Orientation: "horizontal",
ScreenID: "screen-1",
},
OK: true,
}
})
},
wantGood: func(t *testing.T, got any) {
t.Helper()
arrangement := got.(window.PairArrangement)
assert.Equal(t, "horizontal", arrangement.Orientation)
assert.Equal(t, "screen-1", arrangement.ScreenID)
assert.Equal(t, 800, arrangement.Primary.Width)
assert.Equal(t, 800, arrangement.Secondary.Width)
},
})
}