Add GUI coverage tests
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 18:08:38 +01:00
parent 48511c8272
commit 683fe8f85e
3 changed files with 459 additions and 0 deletions

View file

@ -4,6 +4,7 @@ package browser
import (
"context"
core "dappco.re/go/core"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
@ -127,3 +128,81 @@ func TestTaskOpenURL_Bad_NoService(t *testing.T) {
))
assert.False(t, r.OK)
}
func TestService_validatedOpenURL_Good(t *testing.T) {
cases := []struct {
name string
raw string
want string
}{
{
name: "trimmed",
raw: " https://example.com ",
want: "https://example.com",
},
{
name: "pathAndQuery",
raw: "https://example.com/docs?q=core",
want: "https://example.com/docs?q=core",
},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
got, err := validatedOpenURL(tc.raw)
require.NoError(t, err)
assert.Equal(t, tc.want, got)
})
}
}
func TestService_validatedOpenURL_Bad(t *testing.T) {
cases := []string{
"",
" ",
"example.com",
"ftp://example.com",
"https://user:pass@example.com",
}
for _, raw := range cases {
t.Run(raw, func(t *testing.T) {
got, err := validatedOpenURL(raw)
require.Error(t, err)
assert.Empty(t, got)
})
}
}
func TestService_validatedOpenURL_Ugly(t *testing.T) {
got, err := validatedOpenURL("https://example.com/\x00")
require.Error(t, err)
assert.Empty(t, got)
}
func TestService_validatedOpenFilePath_Good(t *testing.T) {
got, err := validatedOpenFilePath("/tmp/../tmp/report.txt")
require.NoError(t, err)
assert.Equal(t, filepath.Clean("/tmp/report.txt"), got)
}
func TestService_validatedOpenFilePath_Bad(t *testing.T) {
cases := []string{
"",
"relative/report.txt",
}
for _, raw := range cases {
t.Run(raw, func(t *testing.T) {
got, err := validatedOpenFilePath(raw)
require.Error(t, err)
assert.Empty(t, got)
})
}
}
func TestService_validatedOpenFilePath_Ugly(t *testing.T) {
got, err := validatedOpenFilePath("/tmp/\x00report.txt")
require.Error(t, err)
assert.Empty(t, got)
}

View file

@ -3,9 +3,12 @@ package dialog
import (
"context"
"strings"
"testing"
core "dappco.re/go/core"
"forge.lthn.ai/core/gui/pkg/webview"
"forge.lthn.ai/core/gui/pkg/window"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@ -293,6 +296,42 @@ func TestService_TaskError_Good(t *testing.T) {
assert.Equal(t, "could not write file: permission denied", mock.lastMsgOpts.Message)
}
func TestService_TaskPrompt_Good(t *testing.T) {
_, c := newTestService(t)
c.RegisterQuery(func(_ *core.Core, q core.Query) core.Result {
switch q.(type) {
case window.QueryWindowList:
return core.Result{Value: []window.WindowInfo{
{Name: "editor", Focused: true},
}, OK: true}
default:
return core.Result{}
}
})
var script string
c.Action("gui.webview.eval", func(_ context.Context, opts core.Options) core.Result {
task := opts.Get("task").Value.(webview.TaskEvaluate)
script = task.Script
assert.Equal(t, "editor", task.Window)
return core.Result{Value: "draft", OK: true}
})
r := taskRun(c, "dialog.prompt", TaskPrompt{
Title: "Rename",
Message: "Enter a new name",
DefaultValue: "draft",
})
require.True(t, r.OK)
result := r.Value.(PromptResult)
assert.Equal(t, "draft", result.Value)
assert.True(t, result.Confirmed)
assert.Contains(t, script, "window.prompt(")
assert.Contains(t, script, "Rename")
assert.Contains(t, script, "Enter a new name")
}
// --- Bad path tests ---
func TestService_TaskOpenFile_Bad(t *testing.T) {
@ -388,3 +427,122 @@ func TestService_UnknownTask_Ugly(t *testing.T) {
r := c.Action("dialog.nonexistent").Run(context.Background(), core.NewOptions())
assert.False(t, r.OK)
}
func TestService_promptOptionsFrom_Good(t *testing.T) {
got, err := promptOptionsFrom(core.NewOptions(
core.Option{Key: "task", Value: TaskPrompt{
Title: "Rename",
Message: "Enter a new name",
DefaultValue: "draft",
}},
))
require.NoError(t, err)
assert.Equal(t, TaskPrompt{
Title: "Rename",
Message: "Enter a new name",
DefaultValue: "draft",
}, got)
}
func TestService_promptOptionsFrom_Bad(t *testing.T) {
got, err := promptOptionsFrom(core.NewOptions(
core.Option{Key: "title", Value: "Rename"},
core.Option{Key: "message", Value: "Enter a new name"},
core.Option{Key: "defaultValue", Value: "draft"},
))
require.NoError(t, err)
assert.Equal(t, TaskPrompt{
Title: "Rename",
Message: "Enter a new name",
DefaultValue: "draft",
}, got)
}
func TestService_promptOptionsFrom_Ugly(t *testing.T) {
got, err := promptOptionsFrom(core.NewOptions())
require.NoError(t, err)
assert.Zero(t, got)
}
func TestService_promptWindowName_Good(t *testing.T) {
_, c := newTestService(t)
svc := core.MustServiceFor[*Service](c, "dialog")
c.RegisterQuery(func(_ *core.Core, q core.Query) core.Result {
switch q.(type) {
case window.QueryWindowList:
return core.Result{Value: []window.WindowInfo{
{Name: "editor"},
{Name: "preview", Focused: true},
}, OK: true}
default:
return core.Result{}
}
})
got, err := svc.promptWindowName()
require.NoError(t, err)
assert.Equal(t, "preview", got)
}
func TestService_promptWindowName_Bad(t *testing.T) {
_, c := newTestService(t)
svc := core.MustServiceFor[*Service](c, "dialog")
c.RegisterQuery(func(_ *core.Core, q core.Query) core.Result {
switch q.(type) {
case window.QueryWindowList:
return core.Result{Value: "unexpected", OK: true}
default:
return core.Result{}
}
})
got, err := svc.promptWindowName()
require.Error(t, err)
assert.Empty(t, got)
}
func TestService_promptWindowName_Ugly(t *testing.T) {
_, c := newTestService(t)
svc := core.MustServiceFor[*Service](c, "dialog")
c.RegisterQuery(func(_ *core.Core, q core.Query) core.Result {
switch q.(type) {
case window.QueryWindowList:
return core.Result{Value: []window.WindowInfo{
{Name: "editor"},
{Name: "terminal"},
}, OK: true}
default:
return core.Result{}
}
})
got, err := svc.promptWindowName()
require.NoError(t, err)
assert.Equal(t, "editor", got)
}
func TestService_promptScript_Good(t *testing.T) {
script := promptScript("Rename", "Enter a new name", "draft")
assert.Contains(t, script, "window.prompt(")
assert.Contains(t, script, "Rename")
assert.Contains(t, script, "Enter a new name")
assert.Contains(t, script, "draft")
}
func TestService_promptScript_Bad(t *testing.T) {
script := promptScript("Rename", "", "")
assert.Contains(t, script, "window.prompt(")
assert.Contains(t, script, "Rename")
assert.NotContains(t, script, "Enter a new name")
}
func TestService_promptScript_Ugly(t *testing.T) {
script := promptScript("", "Line 1\nLine 2", "\"quoted\"")
assert.Contains(t, script, "Line 1")
assert.Contains(t, script, "Line 2")
assert.Contains(t, script, "quoted")
assert.True(t, strings.Contains(script, "window.prompt("))
}

View file

@ -1,10 +1,12 @@
package display
import (
"bytes"
"context"
"testing"
core "dappco.re/go/core"
"forge.lthn.ai/core/gui/pkg/clipboard"
"forge.lthn.ai/core/gui/pkg/dialog"
"forge.lthn.ai/core/gui/pkg/environment"
"forge.lthn.ai/core/gui/pkg/screen"
@ -309,3 +311,223 @@ func TestDisplayAPI_GetTheme_Ugly(t *testing.T) {
assert.Nil(t, svc.GetTheme())
assert.Empty(t, svc.GetSystemTheme())
}
func TestDisplayAPI_SaveFileDialog_Good(t *testing.T) {
svc, c := newTestDisplayAPIService(t)
c.Action("dialog.saveFile", func(_ context.Context, opts core.Options) core.Result {
task := opts.Get("task").Value.(dialog.TaskSaveFile)
assert.Equal(t, "Export", task.Options.Title)
assert.Equal(t, "/tmp", task.Options.Directory)
assert.Equal(t, "data.json", task.Options.Filename)
require.Len(t, task.Options.Filters, 1)
assert.Equal(t, "JSON", task.Options.Filters[0].DisplayName)
return core.Result{Value: "/exports/data.json", OK: true}
})
path, err := svc.SaveFileDialog(SaveFileOptions{
Title: "Export",
DefaultDirectory: "/tmp",
DefaultFilename: "data.json",
Filters: []FileFilter{{DisplayName: "JSON", Pattern: "*.json"}},
})
require.NoError(t, err)
assert.Equal(t, "/exports/data.json", path)
}
func TestDisplayAPI_SaveFileDialog_Bad(t *testing.T) {
svc, c := newTestDisplayAPIService(t)
c.Action("dialog.saveFile", func(_ context.Context, _ core.Options) core.Result {
return core.Result{Value: assert.AnError, OK: false}
})
path, err := svc.SaveFileDialog(SaveFileOptions{})
require.Error(t, err)
assert.Empty(t, path)
}
func TestDisplayAPI_SaveFileDialog_Ugly(t *testing.T) {
svc, c := newTestDisplayAPIService(t)
c.Action("dialog.saveFile", func(_ context.Context, _ core.Options) core.Result {
return core.Result{Value: 42, OK: true}
})
path, err := svc.SaveFileDialog(SaveFileOptions{})
require.Error(t, err)
assert.Empty(t, path)
}
func TestDisplayAPI_OpenDirectoryDialog_Good(t *testing.T) {
svc, c := newTestDisplayAPIService(t)
c.Action("dialog.openDirectory", func(_ context.Context, opts core.Options) core.Result {
task := opts.Get("task").Value.(dialog.TaskOpenDirectory)
assert.Equal(t, "Choose", task.Options.Title)
assert.Equal(t, "/var", task.Options.Directory)
return core.Result{Value: "/var/data", OK: true}
})
path, err := svc.OpenDirectoryDialog(OpenDirectoryOptions{
Title: "Choose",
DefaultDirectory: "/var",
})
require.NoError(t, err)
assert.Equal(t, "/var/data", path)
}
func TestDisplayAPI_OpenDirectoryDialog_Bad(t *testing.T) {
svc, c := newTestDisplayAPIService(t)
c.Action("dialog.openDirectory", func(_ context.Context, _ core.Options) core.Result {
return core.Result{Value: assert.AnError, OK: false}
})
path, err := svc.OpenDirectoryDialog(OpenDirectoryOptions{})
require.Error(t, err)
assert.Empty(t, path)
}
func TestDisplayAPI_OpenDirectoryDialog_Ugly(t *testing.T) {
svc, c := newTestDisplayAPIService(t)
c.Action("dialog.openDirectory", func(_ context.Context, _ core.Options) core.Result {
return core.Result{Value: 42, OK: true}
})
path, err := svc.OpenDirectoryDialog(OpenDirectoryOptions{})
require.Error(t, err)
assert.Empty(t, path)
}
func TestDisplayAPI_PromptDialog_Good(t *testing.T) {
svc, c := newTestDisplayAPIService(t)
c.Action("dialog.prompt", func(_ context.Context, opts core.Options) core.Result {
task := opts.Get("task").Value.(dialog.TaskPrompt)
assert.Equal(t, "Rename", task.Title)
assert.Equal(t, "Enter a new name", task.Message)
return core.Result{Value: dialog.PromptResult{Value: "draft", Confirmed: true}, OK: true}
})
value, confirmed, err := svc.PromptDialog("Rename", "Enter a new name")
require.NoError(t, err)
assert.True(t, confirmed)
assert.Equal(t, "draft", value)
}
func TestDisplayAPI_PromptDialog_Bad(t *testing.T) {
svc, c := newTestDisplayAPIService(t)
c.Action("dialog.prompt", func(_ context.Context, _ core.Options) core.Result {
return core.Result{Value: assert.AnError, OK: false}
})
value, confirmed, err := svc.PromptDialog("Rename", "Enter a new name")
require.Error(t, err)
assert.False(t, confirmed)
assert.Empty(t, value)
}
func TestDisplayAPI_PromptDialog_Ugly(t *testing.T) {
svc, c := newTestDisplayAPIService(t)
c.Action("dialog.prompt", func(_ context.Context, _ core.Options) core.Result {
return core.Result{Value: 42, OK: true}
})
value, confirmed, err := svc.PromptDialog("Rename", "Enter a new name")
require.Error(t, err)
assert.False(t, confirmed)
assert.Empty(t, value)
}
func TestDisplayAPI_ReadClipboardImage_Good(t *testing.T) {
svc, c := newTestDisplayAPIService(t)
payload := []byte{1, 2, 3}
c.RegisterQuery(func(_ *core.Core, q core.Query) core.Result {
switch q.(type) {
case clipboard.QueryImage:
return core.Result{Value: clipboard.ImageContent{Data: payload, HasImage: true}, OK: true}
default:
return core.Result{}
}
})
got, err := svc.ReadClipboardImage()
require.NoError(t, err)
require.Equal(t, []byte{1, 2, 3}, got)
payload[0] = 9
assert.Equal(t, byte(1), got[0])
}
func TestDisplayAPI_ReadClipboardImage_Bad(t *testing.T) {
svc, c := newTestDisplayAPIService(t)
c.RegisterQuery(func(_ *core.Core, q core.Query) core.Result {
switch q.(type) {
case clipboard.QueryImage:
return core.Result{Value: clipboard.ImageContent{HasImage: false}, OK: true}
default:
return core.Result{}
}
})
got, err := svc.ReadClipboardImage()
require.NoError(t, err)
assert.Nil(t, got)
}
func TestDisplayAPI_ReadClipboardImage_Ugly(t *testing.T) {
svc, c := newTestDisplayAPIService(t)
c.RegisterQuery(func(_ *core.Core, q core.Query) core.Result {
switch q.(type) {
case clipboard.QueryImage:
return core.Result{Value: "unexpected", OK: true}
default:
return core.Result{}
}
})
got, err := svc.ReadClipboardImage()
require.Error(t, err)
assert.Nil(t, got)
}
func TestDisplayAPI_WriteClipboardImage_Good(t *testing.T) {
svc, c := newTestDisplayAPIService(t)
var got []byte
c.Action("clipboard.setImage", func(_ context.Context, opts core.Options) core.Result {
got = append([]byte(nil), opts.Get("data").Value.([]byte)...)
return core.Result{OK: true}
})
input := []byte{4, 5, 6}
err := svc.WriteClipboardImage(input)
require.NoError(t, err)
input[0] = 9
assert.True(t, bytes.Equal([]byte{4, 5, 6}, got))
}
func TestDisplayAPI_WriteClipboardImage_Bad(t *testing.T) {
svc, _ := newTestDisplayAPIService(t)
err := svc.WriteClipboardImage(nil)
require.Error(t, err)
}
func TestDisplayAPI_WriteClipboardImage_Ugly(t *testing.T) {
svc, c := newTestDisplayAPIService(t)
c.Action("clipboard.setImage", func(_ context.Context, _ core.Options) core.Result {
return core.Result{Value: assert.AnError, OK: false}
})
err := svc.WriteClipboardImage([]byte{1})
require.Error(t, err)
}