gui/pkg/dialog/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

390 lines
12 KiB
Go

// pkg/dialog/service_test.go
package dialog
import (
"context"
"testing"
core "dappco.re/go/core"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
type mockPlatform struct {
openFilePaths []string
saveFilePath string
openDirPath string
messageButton string
openFileErr error
saveFileErr error
openDirErr error
messageErr error
lastOpenOpts OpenFileOptions
lastSaveOpts SaveFileOptions
lastDirOpts OpenDirectoryOptions
lastMsgOpts MessageDialogOptions
}
func (m *mockPlatform) OpenFile(opts OpenFileOptions) ([]string, error) {
m.lastOpenOpts = opts
return m.openFilePaths, m.openFileErr
}
func (m *mockPlatform) SaveFile(opts SaveFileOptions) (string, error) {
m.lastSaveOpts = opts
return m.saveFilePath, m.saveFileErr
}
func (m *mockPlatform) OpenDirectory(opts OpenDirectoryOptions) (string, error) {
m.lastDirOpts = opts
return m.openDirPath, m.openDirErr
}
func (m *mockPlatform) MessageDialog(opts MessageDialogOptions) (string, error) {
m.lastMsgOpts = opts
return m.messageButton, m.messageErr
}
func newTestService(t *testing.T) (*mockPlatform, *core.Core) {
t.Helper()
mock := &mockPlatform{
openFilePaths: []string{"/tmp/file.txt"},
saveFilePath: "/tmp/save.txt",
openDirPath: "/tmp/dir",
messageButton: "OK",
}
c := core.New(
core.WithService(Register(mock)),
core.WithServiceLock(),
)
require.True(t, c.ServiceStartup(context.Background(), nil).OK)
return mock, c
}
func taskRun(c *core.Core, name string, task any) core.Result {
return c.Action(name).Run(context.Background(), core.NewOptions(
core.Option{Key: "task", Value: task},
))
}
// --- Good path tests ---
func TestService_Register_Good(t *testing.T) {
_, c := newTestService(t)
svc := core.MustServiceFor[*Service](c, "dialog")
assert.NotNil(t, svc)
}
func TestService_TaskOpenFile_Good(t *testing.T) {
mock, c := newTestService(t)
mock.openFilePaths = []string{"/a.txt", "/b.txt"}
r := taskRun(c, "dialog.openFile", TaskOpenFile{
Options: OpenFileOptions{Title: "Pick", AllowMultiple: true},
})
require.True(t, r.OK)
paths := r.Value.([]string)
assert.Equal(t, []string{"/a.txt", "/b.txt"}, paths)
assert.Equal(t, "Pick", mock.lastOpenOpts.Title)
assert.True(t, mock.lastOpenOpts.AllowMultiple)
}
func TestService_TaskOpenFile_FileFilters_Good(t *testing.T) {
mock, c := newTestService(t)
mock.openFilePaths = []string{"/img.png"}
filters := []FileFilter{{DisplayName: "Images", Pattern: "*.png;*.jpg"}}
r := taskRun(c, "dialog.openFile", TaskOpenFile{
Options: OpenFileOptions{
Title: "Select image",
Filters: filters,
},
})
require.True(t, r.OK)
assert.Equal(t, []string{"/img.png"}, r.Value.([]string))
require.Len(t, mock.lastOpenOpts.Filters, 1)
assert.Equal(t, "Images", mock.lastOpenOpts.Filters[0].DisplayName)
assert.Equal(t, "*.png;*.jpg", mock.lastOpenOpts.Filters[0].Pattern)
}
func TestService_TaskOpenFile_MultipleSelection_Good(t *testing.T) {
mock, c := newTestService(t)
mock.openFilePaths = []string{"/a.txt", "/b.txt", "/c.txt"}
r := taskRun(c, "dialog.openFile", TaskOpenFile{
Options: OpenFileOptions{AllowMultiple: true},
})
require.True(t, r.OK)
assert.Equal(t, []string{"/a.txt", "/b.txt", "/c.txt"}, r.Value.([]string))
assert.True(t, mock.lastOpenOpts.AllowMultiple)
}
func TestService_TaskOpenFile_CanChooseOptions_Good(t *testing.T) {
mock, c := newTestService(t)
r := taskRun(c, "dialog.openFile", TaskOpenFile{
Options: OpenFileOptions{
CanChooseFiles: true,
CanChooseDirectories: true,
ShowHiddenFiles: true,
},
})
require.True(t, r.OK)
assert.True(t, mock.lastOpenOpts.CanChooseFiles)
assert.True(t, mock.lastOpenOpts.CanChooseDirectories)
assert.True(t, mock.lastOpenOpts.ShowHiddenFiles)
}
func TestService_TaskOpenFileWithOptions_Good(t *testing.T) {
mock, c := newTestService(t)
mock.openFilePaths = []string{"/log.txt"}
opts := &OpenFileOptions{
Title: "Select log",
AllowMultiple: false,
ShowHiddenFiles: true,
}
r := taskRun(c, "dialog.openFile", TaskOpenFileWithOptions{Options: opts})
require.True(t, r.OK)
assert.Equal(t, []string{"/log.txt"}, r.Value.([]string))
assert.Equal(t, "Select log", mock.lastOpenOpts.Title)
assert.True(t, mock.lastOpenOpts.ShowHiddenFiles)
}
func TestService_TaskOpenFileWithOptions_NilOptions_Good(t *testing.T) {
_, c := newTestService(t)
r := taskRun(c, "dialog.openFile", TaskOpenFileWithOptions{Options: nil})
require.True(t, r.OK)
assert.NotNil(t, r.Value)
}
func TestService_TaskSaveFile_Good(t *testing.T) {
_, c := newTestService(t)
r := taskRun(c, "dialog.saveFile", TaskSaveFile{
Options: SaveFileOptions{Filename: "out.txt"},
})
require.True(t, r.OK)
assert.Equal(t, "/tmp/save.txt", r.Value)
}
func TestService_TaskSaveFile_ShowHidden_Good(t *testing.T) {
mock, c := newTestService(t)
r := taskRun(c, "dialog.saveFile", TaskSaveFile{
Options: SaveFileOptions{Filename: "out.txt", ShowHiddenFiles: true},
})
require.True(t, r.OK)
assert.True(t, mock.lastSaveOpts.ShowHiddenFiles)
}
func TestService_TaskSaveFileWithOptions_Good(t *testing.T) {
mock, c := newTestService(t)
mock.saveFilePath = "/exports/data.json"
opts := &SaveFileOptions{
Title: "Export data",
Filename: "data.json",
Filters: []FileFilter{{DisplayName: "JSON", Pattern: "*.json"}},
}
r := taskRun(c, "dialog.saveFile", TaskSaveFileWithOptions{Options: opts})
require.True(t, r.OK)
assert.Equal(t, "/exports/data.json", r.Value.(string))
assert.Equal(t, "Export data", mock.lastSaveOpts.Title)
require.Len(t, mock.lastSaveOpts.Filters, 1)
assert.Equal(t, "JSON", mock.lastSaveOpts.Filters[0].DisplayName)
}
func TestService_TaskSaveFileWithOptions_NilOptions_Good(t *testing.T) {
_, c := newTestService(t)
r := taskRun(c, "dialog.saveFile", TaskSaveFileWithOptions{Options: nil})
require.True(t, r.OK)
assert.Equal(t, "/tmp/save.txt", r.Value)
}
func TestService_TaskOpenDirectory_Good(t *testing.T) {
mock, c := newTestService(t)
r := taskRun(c, "dialog.openDirectory", TaskOpenDirectory{
Options: OpenDirectoryOptions{Title: "Pick Dir", ShowHiddenFiles: true},
})
require.True(t, r.OK)
assert.Equal(t, "/tmp/dir", r.Value)
assert.Equal(t, "Pick Dir", mock.lastDirOpts.Title)
assert.True(t, mock.lastDirOpts.ShowHiddenFiles)
}
func TestService_TaskMessageDialog_Good(t *testing.T) {
mock, c := newTestService(t)
mock.messageButton = "Yes"
r := taskRun(c, "dialog.message", TaskMessageDialog{
Options: MessageDialogOptions{
Type: DialogQuestion, Title: "Confirm",
Message: "Sure?", Buttons: []string{"Yes", "No"},
},
})
require.True(t, r.OK)
assert.Equal(t, "Yes", r.Value)
assert.Equal(t, DialogQuestion, mock.lastMsgOpts.Type)
}
func TestService_TaskInfo_Good(t *testing.T) {
mock, c := newTestService(t)
mock.messageButton = "OK"
r := taskRun(c, "dialog.info", TaskInfo{
Title: "Done", Message: "File saved successfully.",
})
require.True(t, r.OK)
assert.Equal(t, "OK", r.Value.(string))
assert.Equal(t, DialogInfo, mock.lastMsgOpts.Type)
assert.Equal(t, "Done", mock.lastMsgOpts.Title)
assert.Equal(t, "File saved successfully.", mock.lastMsgOpts.Message)
}
func TestService_TaskInfo_WithButtons_Good(t *testing.T) {
mock, c := newTestService(t)
mock.messageButton = "Close"
r := taskRun(c, "dialog.info", TaskInfo{
Title: "Notice", Message: "Update available.", Buttons: []string{"Close", "Later"},
})
require.True(t, r.OK)
assert.Equal(t, "Close", r.Value.(string))
assert.Equal(t, []string{"Close", "Later"}, mock.lastMsgOpts.Buttons)
}
func TestService_TaskQuestion_Good(t *testing.T) {
mock, c := newTestService(t)
mock.messageButton = "Yes"
r := taskRun(c, "dialog.question", TaskQuestion{
Title: "Confirm deletion", Message: "Delete file?", Buttons: []string{"Yes", "No"},
})
require.True(t, r.OK)
assert.Equal(t, "Yes", r.Value.(string))
assert.Equal(t, DialogQuestion, mock.lastMsgOpts.Type)
assert.Equal(t, "Confirm deletion", mock.lastMsgOpts.Title)
}
func TestService_TaskWarning_Good(t *testing.T) {
mock, c := newTestService(t)
mock.messageButton = "OK"
r := taskRun(c, "dialog.warning", TaskWarning{
Title: "Disk full", Message: "Storage is critically low.", Buttons: []string{"OK"},
})
require.True(t, r.OK)
assert.Equal(t, "OK", r.Value.(string))
assert.Equal(t, DialogWarning, mock.lastMsgOpts.Type)
assert.Equal(t, "Disk full", mock.lastMsgOpts.Title)
}
func TestService_TaskError_Good(t *testing.T) {
mock, c := newTestService(t)
mock.messageButton = "OK"
r := taskRun(c, "dialog.error", TaskError{
Title: "Operation failed", Message: "could not write file: permission denied",
})
require.True(t, r.OK)
assert.Equal(t, "OK", r.Value.(string))
assert.Equal(t, DialogError, mock.lastMsgOpts.Type)
assert.Equal(t, "Operation failed", mock.lastMsgOpts.Title)
assert.Equal(t, "could not write file: permission denied", mock.lastMsgOpts.Message)
}
// --- Bad path tests ---
func TestService_TaskOpenFile_Bad(t *testing.T) {
c := core.New(core.WithServiceLock())
r := c.Action("dialog.openFile").Run(context.Background(), core.NewOptions())
assert.False(t, r.OK)
}
func TestService_TaskOpenFileWithOptions_Bad(t *testing.T) {
c := core.New(core.WithServiceLock())
r := c.Action("dialog.openFile").Run(context.Background(), core.NewOptions())
assert.False(t, r.OK)
}
func TestService_TaskSaveFileWithOptions_Bad(t *testing.T) {
c := core.New(core.WithServiceLock())
r := c.Action("dialog.saveFile").Run(context.Background(), core.NewOptions())
assert.False(t, r.OK)
}
func TestService_TaskInfo_Bad(t *testing.T) {
c := core.New(core.WithServiceLock())
r := c.Action("dialog.info").Run(context.Background(), core.NewOptions())
assert.False(t, r.OK)
}
func TestService_TaskQuestion_Bad(t *testing.T) {
c := core.New(core.WithServiceLock())
r := c.Action("dialog.question").Run(context.Background(), core.NewOptions())
assert.False(t, r.OK)
}
func TestService_TaskWarning_Bad(t *testing.T) {
c := core.New(core.WithServiceLock())
r := c.Action("dialog.warning").Run(context.Background(), core.NewOptions())
assert.False(t, r.OK)
}
func TestService_TaskError_Bad(t *testing.T) {
c := core.New(core.WithServiceLock())
r := c.Action("dialog.error").Run(context.Background(), core.NewOptions())
assert.False(t, r.OK)
}
// --- Ugly path tests ---
func TestService_TaskOpenFile_Ugly(t *testing.T) {
mock, c := newTestService(t)
mock.openFilePaths = nil
r := taskRun(c, "dialog.openFile", TaskOpenFile{
Options: OpenFileOptions{Title: "Pick"},
})
require.True(t, r.OK)
assert.Nil(t, r.Value.([]string))
}
func TestService_TaskOpenFileWithOptions_MultipleFilters_Ugly(t *testing.T) {
mock, c := newTestService(t)
mock.openFilePaths = []string{"/doc.pdf"}
opts := &OpenFileOptions{
Title: "Select document",
Filters: []FileFilter{
{DisplayName: "PDF", Pattern: "*.pdf"},
{DisplayName: "Word", Pattern: "*.docx"},
{DisplayName: "All files", Pattern: "*.*"},
},
}
r := taskRun(c, "dialog.openFile", TaskOpenFileWithOptions{Options: opts})
require.True(t, r.OK)
assert.Equal(t, []string{"/doc.pdf"}, r.Value.([]string))
assert.Len(t, mock.lastOpenOpts.Filters, 3)
}
func TestService_TaskSaveFileWithOptions_FiltersAndHidden_Ugly(t *testing.T) {
mock, c := newTestService(t)
opts := &SaveFileOptions{
Title: "Save",
Filename: "output.csv",
ShowHiddenFiles: true,
Filters: []FileFilter{{DisplayName: "CSV", Pattern: "*.csv"}},
}
r := taskRun(c, "dialog.saveFile", TaskSaveFileWithOptions{Options: opts})
require.True(t, r.OK)
assert.True(t, mock.lastSaveOpts.ShowHiddenFiles)
assert.Equal(t, "output.csv", mock.lastSaveOpts.Filename)
}
func TestService_UnknownTask_Ugly(t *testing.T) {
c := core.New(core.WithServiceLock())
r := c.Action("dialog.nonexistent").Run(context.Background(), core.NewOptions())
assert.False(t, r.OK)
}