package app
import (
"strings"
"testing"
)
// TestNavBaseRendersFirstPageWithoutPageCount is the regression test for the
// navigation panel vanishing on some artworks. The comment list on a deviation
// cannot count its pages, so it passes Pages: 0; on page one, with no further
// page to offer, the panel used to render as nothing but a
.
func TestNavBaseRendersFirstPageWithoutPageCount(t *testing.T) {
s := skunkyart{Page: 1, _pth: "/deviation/1"}
out := s.NavBase(DeviationList{Pages: 0, More: false})
if strings.TrimSpace(strings.TrimPrefix(out, "
")) == "" {
t.Fatalf("navigation panel is empty, want the current page rendered: %q", out)
}
if !strings.Contains(out, "1") {
t.Errorf("current page number missing from %q", out)
}
}
// TestNavBaseFirstPageOffersNextWhenMore covers the same Pages: 0 case when a
// further page does exist: the current page must still appear alongside Next,
// rather than Next standing on its own with nothing to anchor it.
func TestNavBaseFirstPageOffersNextWhenMore(t *testing.T) {
s := skunkyart{Page: 1, _pth: "/deviation/1"}
out := s.NavBase(DeviationList{Pages: 0, More: true})
if !strings.Contains(out, "Next") {
t.Errorf("Next link missing from %q", out)
}
if !strings.Contains(out, "1") {
t.Errorf("current page number missing from %q", out)
}
}
// TestNavBaseKnownPageCountUnchanged pins the ordinary path: when the caller
// does know the page count, the window is still bounded by it.
func TestNavBaseKnownPageCountUnchanged(t *testing.T) {
s := skunkyart{Page: 1, _pth: "/gallery"}
out := s.NavBase(DeviationList{Pages: 3, More: true})
for _, want := range []string{"1", "2", "3"} {
if !strings.Contains(out, want) {
t.Errorf("page %s missing from %q", want, out)
}
}
if strings.Contains(out, "p=4") {
t.Errorf("linked past the last page in %q", out)
}
}
// TestInstanceAboutCarriesHideAI covers the About page and /api/instance both
// reading hide-ai from config, so a visitor can tell whether an instance
// filters AI-generated works without inferring it from absent results.
func TestInstanceAboutCarriesHideAI(t *testing.T) {
hide := CFG.HideAI
defer func() { CFG.HideAI = hide }()
for _, on := range []bool{true, false} {
CFG.HideAI = on
if got := (instanceAbout{HideAI: CFG.HideAI}).HideAI; got != on {
t.Errorf("instanceAbout.HideAI = %v, want %v", got, on)
}
if got := (settingsParams{HideAI: CFG.HideAI}).HideAI; got != on {
t.Errorf("settingsParams.HideAI = %v, want %v", got, on)
}
}
}
// TestForcedThemeCSSOnlyForAnExplicitChoice pins that "auto" adds nothing: the
// stylesheet already carries dark plus a prefers-color-scheme light block, and
// appending a palette would defeat the visitor's own system setting.
func TestForcedThemeCSSOnlyForAnExplicitChoice(t *testing.T) {
theme := CFG.Theme
defer func() { CFG.Theme = theme }()
CFG.Theme = "auto"
if got := forcedThemeCSS(); got != "" {
t.Errorf("auto appended %q, want nothing", got)
}
for _, want := range []string{"dark", "light"} {
CFG.Theme = want
css := forcedThemeCSS()
if !strings.Contains(css, ":root{") {
t.Errorf("%s theme did not emit a :root block: %q", want, css)
}
if !strings.Contains(css, "--bg:") || !strings.Contains(css, "--status-note:") {
t.Errorf("%s theme is missing palette variables: %q", want, css)
}
}
}
// TestForcedThemeCSSCoversEveryVariable is the guard against a half-applied
// palette: a forced theme that omits a variable falls through to the default
// one, which is how a light theme ends up with black panels.
func TestForcedThemeCSSCoversEveryVariable(t *testing.T) {
theme := CFG.Theme
defer func() { CFG.Theme = theme }()
vars := []string{
"--bg", "--fg", "--fg-strong", "--link", "--link-hover", "--edge",
"--edge-strong", "--accent", "--surface", "--surface-sunken",
"--surface-alt", "--surface-deep", "--status-bad", "--status-good",
"--status-mild", "--status-note",
}
for _, mode := range []string{"dark", "light"} {
CFG.Theme = mode
css := forcedThemeCSS()
for _, v := range vars {
if !strings.Contains(css, v+":") {
t.Errorf("%s theme does not set %s", mode, v)
}
}
}
}