Files
bjarneo--cliamp/ui/model/overlay_inline_test.go
wehub-resource-sync ead81af521
Deploy to GitHub Pages / deploy (push) Failing after 0s
CI / go (push) Has been cancelled
CI / build (darwin, macos-14) (push) Has been cancelled
CI / build (windows, windows-2025) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:31:13 +08:00

99 lines
2.9 KiB
Go

package model
import (
"fmt"
"strings"
"testing"
"charm.land/lipgloss/v2"
"github.com/bjarneo/cliamp/playlist"
"github.com/bjarneo/cliamp/ui"
)
// newInlineOverlayModel builds a Model with a real player/playlist/visualizer
// for exercising the inline overlay render path.
func newInlineOverlayModel(t *testing.T, w, h int) Model {
t.Helper()
sharedPlayer.Stop()
pl := playlist.New()
for i := range 8 {
pl.Add(playlist.Track{
Path: fmt.Sprintf("/tmp/track-%d.mp3", i),
Title: fmt.Sprintf("Track %d", i+1),
})
}
m := Model{
player: sharedPlayer,
playlist: pl,
vis: ui.NewVisualizer(float64(sharedPlayer.SampleRate())),
width: w,
height: h,
focus: focusPlaylist,
plVisible: 6,
}
m.vis.Mode = ui.VisNone
m.refreshChrome()
m.applyHeightMode()
return m
}
// TestInlineOverlaysFitTerminal opens each overlay inline and asserts the framed
// view never overflows the terminal height or width. Overlays render in the
// playlist region beneath the live now-playing/visualizer/controls chrome, so
// the total frame must still fit.
func TestInlineOverlaysFitTerminal(t *testing.T) {
if sharedPlayer == nil {
t.Skip("audio hardware unavailable")
}
sizes := []struct{ w, h int }{
{80, 24},
{80, 20},
{100, 30},
}
overlays := []struct {
name string
set func(m *Model)
}{
{"themePicker", func(m *Model) { m.themePicker.visible = true }},
{"devicePicker", func(m *Model) { m.devicePicker.visible = true }},
{"queue", func(m *Model) { m.queue.visible = true }},
{"info", func(m *Model) { m.showInfo = true }},
{"search", func(m *Model) { m.search.active = true }},
{"keymap", func(m *Model) { m.keymap.visible = true; m.keymap.entries = m.buildKeymapEntries() }},
{"netSearch", func(m *Model) { m.netSearch.active = true }},
{"urlInput", func(m *Model) { m.urlInputting = true }},
{"lyrics", func(m *Model) { m.lyrics.visible = true }},
{"jump", func(m *Model) { m.jumping = true }},
{"spotSearch", func(m *Model) { m.spotSearch.visible = true }},
{"navBrowser", func(m *Model) { m.navBrowser.visible = true; m.navBrowser.mode = navBrowseModeMenu }},
{"playlistManager", func(m *Model) { m.plManager.visible = true; m.plManager.screen = plMgrScreenList }},
{"fileBrowser", func(m *Model) { m.fileBrowser.visible = true }},
{"visPicker", func(m *Model) { m.openVisPicker() }},
}
for _, sz := range sizes {
for _, ov := range overlays {
t.Run(fmt.Sprintf("%s_%dx%d", ov.name, sz.w, sz.h), func(t *testing.T) {
withFrameWidth(t, sz.w)
m := newInlineOverlayModel(t, sz.w, sz.h)
ov.set(&m)
out := m.View().Content
if got := lipgloss.Height(out); got > sz.h {
t.Fatalf("%s view height = %d, want <= %d", ov.name, got, sz.h)
}
for _, line := range strings.Split(out, "\n") {
if got := lipgloss.Width(line); got > sz.w {
t.Fatalf("%s view line width = %d, want <= %d: %q", ov.name, got, sz.w, line)
}
}
})
}
}
}