package main
import (
"context"
"net/http"
"net/http/httptest"
"net/url"
"strings"
"testing"
"time"
)
func TestAgo(t *testing.T) {
now := time.Date(2026, 9, 5, 12, 0, 0, 0, time.Local)
for _, tc := range []struct {
name string
at time.Time
want string
}{
{"seconds", now.Add(-30 * time.Second), "juuri nyt"},
{"one minute", now.Add(-time.Minute), "minuutti sitten"},
{"minutes", now.Add(-5 * time.Minute), "5 minuuttia sitten"},
{"one hour", now.Add(-time.Hour), "tunti sitten"},
{"hours", now.Add(-5 * time.Hour), "5 tuntia sitten"},
{"yesterday", now.Add(-25 * time.Hour), "eilen"},
{"days", now.Add(-5 * 24 * time.Hour), "5 päivää sitten"},
// Past a week the exact age stops mattering and the date takes over.
{"a week", now.Add(-7 * 24 * time.Hour), "29.8.2026"},
{"months", now.Add(-60 * 24 * time.Hour), "7.7.2026"},
} {
t.Run(tc.name, func(t *testing.T) {
if got := ago(tc.at, now); got != tc.want {
t.Fatalf("ago = %q, want %q", got, tc.want)
}
})
}
}
// A draft is the author's alone. It must not reach a member through either surface.
func TestDraftsAreInvisibleToMembers(t *testing.T) {
a := testApp(t)
ctx := context.Background()
for _, n := range []struct {
title string
draft bool
}{
{"Julkaistu tiedote", false},
{"Salainen luonnos", true},
} {
if _, err := a.db.ExecContext(ctx,
`insert into news (title, body, is_draft) values ($1, 'teksti', $2)`,
n.title, n.draft); err != nil {
t.Fatal(err)
}
}
items, err := a.publishedNews(ctx, 10)
if err != nil {
t.Fatal(err)
}
if len(items) != 1 || items[0].Title != "Julkaistu tiedote" {
t.Fatalf("published news = %+v, want only the published one", items)
}
// The admin listing is the one place a draft shows up.
all, err := a.adminNews(ctx)
if err != nil {
t.Fatal(err)
}
if len(all) != 2 {
t.Fatalf("admin news = %d items, want 2", len(all))
}
}
// The body reaches the page through template.HTML, which turns off Go's escaping. goldmark has to
// be the thing that neutralises a script tag, so assert it actually does.
func TestMarkdownEscapesRawHTML(t *testing.T) {
n := newsItem{Body: "Hei ja **lihavointi** ja [linkki](https://example.com)."}
got := string(n.HTML())
// goldmark drops raw HTML rather than escaping it, so the tag disappears entirely — stricter
// than escaping, and either outcome is safe. What matters is that no tag survives.
if strings.Contains(got, "