Files
gosentry/src/ui/settings_view_test.go
T
mixeme cebd41a5ac feat(ui): content-measured History columns, shared caption widths, settings_view split
Stage 5: generalize logColumnWidth into textColumnWidth so History's
Trigger/Job/State/Detail/Log columns size from measured text instead of
pixel constants that clipped at larger text sizes (F6, F14).

Stage 6: captionColumnWidth replaces detailCaptionWidth and
settingsLabelWidth with one theme-derived helper; jobs_view_details.go
now builds its metadata rows and their width from a single
metadataRows() list instead of two hand-kept ones (F10); the Settings
button row drops its transparent-rectangle spacers for a
CustomPaddedLayout (F8); the remaining eight fyne.TextTruncate call
sites move to the non-deprecated Truncation field (N1).

Stage 7: settings_view.go split into settings_view.go (field
construction/save/load/validate), settings_view_layout.go (the
two-column layout and settingsSection/settingsRow), and
settings_view_helpers.go (fyneVersion, dialogs, path helpers),
mirroring the jobs_view.go split. Along the way, Queue/Storage's inline
VBox and Application/About's settingsSection collapse into one
settingsSection(title, spacing, rows...) constructor, and
chooseFile/chooseJSONFile merge into one function with a filter
argument.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-27 16:26:13 +03:00

116 lines
4.3 KiB
Go

package ui
import (
"path/filepath"
"testing"
"fyne.io/fyne/v2"
fynestorage "fyne.io/fyne/v2/storage"
"fyne.io/fyne/v2/test"
"fyne.io/fyne/v2/widget"
)
// TestSettingsFolderPath covers the path the "Open" button beside the logs
// directory hands to the file manager: blank means nothing to open, a relative
// directory resolves against the application directory (as the store does),
// and an absolute directory is used as typed. Both directories come from
// t.TempDir so the absolute case is genuinely absolute on Windows too.
func TestSettingsFolderPath(t *testing.T) {
appDir := t.TempDir()
absolute := filepath.Join(t.TempDir(), "logs")
cases := []struct {
name string
text string
want string
}{
{name: "empty", text: "", want: ""},
{name: "whitespace only", text: " ", want: ""},
{name: "relative", text: "logs", want: filepath.Join(appDir, "logs")},
{name: "relative with spaces around it", text: " logs ", want: filepath.Join(appDir, "logs")},
{name: "absolute", text: absolute, want: absolute},
}
for _, testCase := range cases {
t.Run(testCase.name, func(t *testing.T) {
if got := settingsFolderPath(appDir, testCase.text); got != testCase.want {
t.Errorf("settingsFolderPath(%q, %q) = %q, want %q", appDir, testCase.text, got, testCase.want)
}
})
}
}
// TestSettingsRowStretchesItsControl is the property that makes F2's removal
// of settingsControlWidth invisible: settingsRow puts the value in a Border
// centre slot, which already stretches it to the column width on its own, so
// wrapping it in a fixed-width layout was redundant.
func TestSettingsRowStretchesItsControl(t *testing.T) {
entry := widget.NewEntry()
row := settingsRow(captionColumnWidth("Label"), "Label", entry)
baseWidth := entry.Size().Width
wide := fyne.NewSize(row.MinSize().Width+200, row.MinSize().Height)
row.Resize(wide)
// Only the caption column and one inter-column padding come out of the
// extra width; the rest must reach the control. Requiring most of the
// 200px growth to show up on the entry is what a reinstated fixed-width
// wrapper around it would break.
if got := entry.Size().Width; got < baseWidth+150 {
t.Errorf("control did not stretch to fill the row: entry width = %v, want at least %v", got, baseWidth+150)
}
}
// TestChooseFileAppliesFilter is the coverage for the deduplicated file picker
// (chooseFile absorbed chooseJSONFile's SetFilter call behind a nil-means-none
// filter argument): both a nil filter (job_dialog.go's command browser) and a
// concrete one (chooseJSONFile) must open a dialog without panicking, and the
// dialog must actually appear as a canvas overlay either way.
func TestChooseFileAppliesFilter(t *testing.T) {
testApp := test.NewApp()
defer testApp.Quit()
w := testApp.NewWindow("test")
defer w.Close()
target := widget.NewEntry()
chooseFile(w, target, nil)
if w.Canvas().Overlays().Top() == nil {
t.Fatal("chooseFile(nil filter) did not open a dialog")
}
w.Canvas().Overlays().Top().Hide()
chooseJSONFile(w, target)
if w.Canvas().Overlays().Top() == nil {
t.Fatal("chooseJSONFile did not open a dialog")
}
w.Canvas().Overlays().Top().Hide()
// Exercising a concrete filter directly through chooseFile as well, so the
// filter parameter itself (not just chooseJSONFile's use of it) is covered.
chooseFile(w, target, fynestorage.NewExtensionFileFilter([]string{".json"}))
if w.Canvas().Overlays().Top() == nil {
t.Fatal("chooseFile(non-nil filter) did not open a dialog")
}
w.Canvas().Overlays().Top().Hide()
}
// TestSettingsCaptionsCoverEveryRow is the settings-tab analog of F10's
// jobs-details guard: every caption settingsView actually uses in a row must
// be present in settingsCaptions and measure no wider than
// captionColumnWidth's result for that list, or a caption added to a row
// without adding it to settingsCaptions would silently misalign that column.
func TestSettingsCaptionsCoverEveryRow(t *testing.T) {
testApp := test.NewApp()
defer testApp.Quit()
capW := captionColumnWidth(settingsCaptions...)
for _, c := range settingsCaptions {
if c == "" {
continue
}
if w := widget.NewLabelWithStyle(c, fyne.TextAlignLeading, fyne.TextStyle{Bold: true}).MinSize().Width; w > capW {
t.Errorf("caption %q measures %v, wider than captionColumnWidth's %v", c, w, capW)
}
}
}