aboutsummaryrefslogtreecommitdiffstats
path: root/internal/web/web_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/web/web_test.go')
-rw-r--r--internal/web/web_test.go111
1 files changed, 93 insertions, 18 deletions
diff --git a/internal/web/web_test.go b/internal/web/web_test.go
index 5078c44..ae26029 100644
--- a/internal/web/web_test.go
+++ b/internal/web/web_test.go
@@ -1,15 +1,20 @@
package web
import (
+ "io/fs"
"net/http"
"net/http/httptest"
"net/url"
+ "os"
+ "path/filepath"
+ "regexp"
"strings"
"testing"
"time"
"github.com/google/uuid"
"github.com/gramanas/blogspace/internal/config"
+ "github.com/gramanas/blogspace/internal/i18n"
"github.com/gramanas/blogspace/internal/store"
)
@@ -188,16 +193,16 @@ func TestModuleKinds(t *testing.T) {
if !moduleHasSettings("html") || moduleHasSettings("rss") {
t.Error("moduleHasSettings")
}
- if got := moduleSummary(store.Module{Kind: "recent", Count: 5, Title: "Fresh"}); got != "5 posts, heading “Fresh”" {
+ if got := moduleSummary("en", store.Module{Kind: "recent", Count: 5, Title: "Fresh"}); got != "5 posts, heading “Fresh”" {
t.Errorf("recent summary: %q", got)
}
- if got := moduleSummary(store.Module{Kind: "html", Body: " <p>hi\n there</p> "}); got != "<p>hi there</p>" {
+ if got := moduleSummary("en", store.Module{Kind: "html", Body: " <p>hi\n there</p> "}); got != "<p>hi there</p>" {
t.Errorf("html summary: %q", got)
}
- if got := moduleSummary(store.Module{Kind: "html", Body: strings.Repeat("x", 100)}); len([]rune(got)) != 58 || !strings.HasSuffix(got, "…") {
+ if got := moduleSummary("en", store.Module{Kind: "html", Body: strings.Repeat("x", 100)}); len([]rune(got)) != 58 || !strings.HasSuffix(got, "…") {
t.Errorf("long html summary: %q", got)
}
- if got := moduleSummary(store.Module{Kind: "menu"}); got != "" {
+ if got := moduleSummary("en", store.Module{Kind: "menu"}); got != "" {
t.Errorf("menu summary: %q", got)
}
}
@@ -222,7 +227,7 @@ func TestGroupArchive(t *testing.T) {
if len(years) != 2 || years[0].Year != 2026 || years[0].Count != 3 || years[1].Year != 2025 || years[1].Count != 1 {
t.Fatalf("years: %+v", years)
}
- if len(years[0].Months) != 2 || years[0].Months[0].Name != "September" || len(years[0].Months[0].Posts) != 2 || years[0].Months[1].Name != "February" {
+ if len(years[0].Months) != 2 || years[0].Months[0].Month != time.September || len(years[0].Months[0].Posts) != 2 || years[0].Months[1].Month != time.February {
t.Errorf("months: %+v", years[0].Months)
}
if years[0].Months[0].Posts[0].Title != "d" || years[1].Months[0].Posts[0].Title != "a" {
@@ -294,26 +299,96 @@ func TestPresets(t *testing.T) {
}
}
-func TestFormatDate(t *testing.T) {
- at := time.Date(2026, 9, 3, 10, 0, 0, 0, time.UTC)
- for format, want := range map[string]string{"long": "3 September 2026", "short": "3 Sep 2026", "iso": "2026-09-03"} {
- th := Theme{DateFormat: format}
- if got := th.FormatDate(at); got != want {
- t.Errorf("%s: got %q, want %q", format, got, want)
- }
- }
-}
-
func TestAllTemplatesParse(t *testing.T) {
- tpl := newTemplates(false, funcs)
+ tpl := newTemplates(false)
for _, name := range []string{"auth/login.html", "dashboard/overview.html", "dashboard/pages.html", "dashboard/page_form.html",
"dashboard/posts.html", "dashboard/post_form.html", "dashboard/design.html", "dashboard/images.html", "dashboard/settings.html",
"dashboard/password.html", "dashboard/confirm.html", "dashboard/sections.html", "dashboard/section_form.html", "dashboard/layout.html", "dashboard/module_form.html", "admin/index.html", "admin/new_user.html", "admin/delete_user.html",
"blog/page.html", "blog/post.html", "blog/404.html"} {
- if _, err := tpl.get(name); err != nil {
- t.Errorf("%s: %v", name, err)
+ for _, l := range i18n.Languages() {
+ if _, err := tpl.get(l.Code, name); err != nil {
+ t.Errorf("%s (%s): %v", name, l.Code, err)
+ }
+ }
+ }
+}
+
+// Every string the templates and handlers translate must be in the Greek
+// catalog, and the catalog must not keep entries nothing uses any more (a
+// reworded English key would otherwise silently fall back to English).
+func TestGreekCatalogComplete(t *testing.T) {
+ used := map[string]bool{}
+ add := func(re *regexp.Regexp, src string) {
+ for _, m := range re.FindAllStringSubmatch(src, -1) {
+ used[m[1]] = true
+ }
+ }
+ tplKey := regexp.MustCompile(`\b(?:t|tf) "((?:[^"\\]|\\.)*)"`)
+ goKey := regexp.MustCompile(`\b(?:s\.trf?\(r|i18n\.Tf?\([A-Za-z]+), "((?:[^"\\]|\\.)*)"`)
+ if err := fs.WalkDir(assets, "templates", func(path string, d fs.DirEntry, err error) error {
+ if err != nil || d.IsDir() {
+ return err
+ }
+ b, err := fs.ReadFile(assets, path)
+ add(tplKey, string(b))
+ return err
+ }); err != nil {
+ t.Fatal(err)
+ }
+ goFiles, _ := filepath.Glob("*.go")
+ for _, f := range goFiles {
+ if strings.HasSuffix(f, "_test.go") {
+ continue
+ }
+ b, err := os.ReadFile(f)
+ if err != nil {
+ t.Fatal(err)
+ }
+ add(goKey, string(b))
+ }
+ // Keys that reach t/tr through a variable rather than a literal.
+ for _, m := range []map[string]string{moduleNames, areaNames} {
+ for _, v := range m {
+ used[v] = true
}
}
+ for _, p := range Presets() {
+ used[p.Name] = true
+ }
+ for _, k := range []string{"top", "bottom", store.RoleSuperadmin, store.RoleBlogger} {
+ used[k] = true
+ }
+ have := map[string]bool{}
+ for _, k := range i18n.Keys("el") {
+ have[k] = true
+ if !used[k] {
+ t.Errorf("el catalog: %q is not used anywhere", k)
+ }
+ }
+ for k := range used {
+ if !have[k] {
+ t.Errorf("el catalog: missing %q", k)
+ }
+ }
+ if len(used) < 100 {
+ t.Errorf("only %d keys found; the scan is broken", len(used))
+ }
+}
+
+// Anonymous pages follow the browser's language; unknown ones fall back to English.
+func TestLangFromAcceptLanguage(t *testing.T) {
+ s := NewServer(&config.Config{BaseDomain: "example.com", JWTSecret: []byte("x")}, nil)
+ req := httptest.NewRequest("GET", "/webadmin", nil)
+ if got := s.lang(req); got != "en" {
+ t.Errorf("no header: %q", got)
+ }
+ req.Header.Set("Accept-Language", "el-GR,el;q=0.9,en;q=0.8")
+ if got := s.lang(req); got != "el" {
+ t.Errorf("greek header: %q", got)
+ }
+ if got := s.lang(withLang(req, "en")); got != "en" {
+ t.Errorf("context wins: %q", got)
+ }
}
// /webadmin on a blog's own host bounces to the root login page and back to that blog's dashboard.