package www_test import ( "io/fs" "os" "path/filepath" "slices" "strings" "testing" "testing/fstest" "amadan.net/rastrillo/fiesta/internal/www" ) // realSite is the repository's site/ directory, the site source the // landing page is built from. func realSite() fs.FS { return os.DirFS(filepath.Join("..", "..", "site")) } // catalogs is a site source holding one landing catalog per language, // each written as Strings reads it. func catalogs(t *testing.T, langs map[string]map[string]string) fstest.MapFS { t.Helper() m := fstest.MapFS{} for lang, strs := range langs { var b strings.Builder b.WriteString("{\n") keys := make([]string, 0, len(strs)) for k := range strs { keys = append(keys, k) } slices.Sort(keys) for i, k := range keys { if i > 0 { b.WriteString(",\n") } b.WriteString(" " + quote(k) + ": " + quote(strs[k])) } b.WriteString("\n}\n") m["landing/strings/"+lang+".json"] = &fstest.MapFile{Data: []byte(b.String())} } return m } // quote is a JSON string literal, enough for the fixtures here. func quote(s string) string { return `"` + strings.NewReplacer(`\`, `\\`, `"`, `\"`, "\n", `\n`).Replace(s) + `"` } // complete is a catalog with every required key, each valued by text. func complete(text func(key string) string) map[string]string { out := make(map[string]string, len(www.RequiredKeys)) for _, k := range www.RequiredKeys { out[k] = text(k) } return out } // keyItself values a key by its own name. func keyItself(key string) string { return key } // keysOf is m's keys, sorted. func keysOf(m map[string]string) []string { keys := make([]string, 0, len(m)) for k := range m { keys = append(keys, k) } slices.Sort(keys) return keys } // TestEveryLanguageHasEveryKey: every site language has a catalog in // the site source, and each holds exactly RequiredKeys with nothing // empty. A catalog that lacks a key, adds one, leaves one empty or is // not there at all is refused, and the error names what is wrong. func TestEveryLanguageHasEveryKey(t *testing.T) { if !slices.IsSorted(www.RequiredKeys) || len(slices.Compact(slices.Clone(www.RequiredKeys))) != len(www.RequiredKeys) { t.Fatal("RequiredKeys is not sorted and unique") } if len(www.Languages) != 11 || www.Languages[0] != "en" { t.Fatalf("Languages is %v", www.Languages) } for _, lang := range www.Languages { got, err := www.Strings(realSite(), lang) if err != nil { t.Errorf("%s: %v", lang, err) continue } if keys := keysOf(got); !slices.Equal(keys, www.RequiredKeys) { t.Errorf("%s has keys %v, want RequiredKeys", lang, keys) } for k, v := range got { if strings.TrimSpace(v) == "" { t.Errorf("%s: %s is empty", lang, k) } } } short := complete(keyItself) delete(short, "sample.saved") _, err := www.Strings(catalogs(t, map[string]map[string]string{"en": short}), "en") if err == nil || !strings.Contains(err.Error(), "sample.saved") { t.Errorf("a catalog lacking sample.saved was accepted, or the error does not name it: %v", err) } extra := complete(keyItself) extra["sample.extra"] = "x" _, err = www.Strings(catalogs(t, map[string]map[string]string{"en": extra}), "en") if err == nil || !strings.Contains(err.Error(), "sample.extra") { t.Errorf("a catalog with a key the page never reads was accepted, or the error does not name it: %v", err) } blank := complete(keyItself) blank["copied"] = " " _, err = www.Strings(catalogs(t, map[string]map[string]string{"en": blank}), "en") if err == nil || !strings.Contains(err.Error(), "copied") { t.Errorf("a catalog with an empty copied was accepted, or the error does not name it: %v", err) } if _, err := www.Strings(catalogs(t, nil), "en"); err == nil { t.Error("a site source with no catalog at all was accepted") } if _, err := www.Strings(catalogs(t, map[string]map[string]string{"en": complete(keyItself)}), "en"); err != nil { t.Errorf("the complete control catalog was refused: %v", err) } } // TestPaulsWordsAreVerbatim: the headline, the lede and the install // line are Paul's words, byte for byte, in the English catalog. func TestPaulsWordsAreVerbatim(t *testing.T) { en, err := www.Strings(realSite(), "en") if err != nil { t.Fatal(err) } for key, want := range map[string]string{ "headline": "Celebrate your new design system", "lede": "Polished, accessible, multi-lingual, localised components for everyone.", "install": "One stylesheet and done. JS optional. <25KiB gzipped.", } { if got := en[key]; got != want { t.Errorf("%s is %q, want %q", key, got, want) } } } // TestThePlaceholdersSurviveTranslation: a {name} placeholder in an // English string is in its translation too. A Spanish catalog that // drops the English {n} is refused by key and placeholder; one that // keeps it passes. No real string holds a placeholder today, so the // fixture carries this test and the real catalogs merely pass. func TestThePlaceholdersSurviveTranslation(t *testing.T) { en := complete(keyItself) en["sample.next.body"] = "Reminders go out on Friday. {n} guests still need a reply." dropped := complete(keyItself) dropped["sample.next.body"] = "Los recordatorios salen el viernes. Tres invitados aún no han respondido." _, err := www.Strings(catalogs(t, map[string]map[string]string{"en": en, "es": dropped}), "es") if err == nil || !strings.Contains(err.Error(), "{n}") || !strings.Contains(err.Error(), "sample.next.body") { t.Errorf("a Spanish catalog that drops {n} was accepted, or the error does not name the key and the placeholder: %v", err) } kept := complete(keyItself) kept["sample.next.body"] = "Los recordatorios salen el viernes. {n} invitados aún no han respondido." if _, err := www.Strings(catalogs(t, map[string]map[string]string{"en": en, "es": kept}), "es"); err != nil { t.Errorf("a Spanish catalog that keeps {n} was refused: %v", err) } for _, lang := range www.Languages { if _, err := www.Strings(realSite(), lang); err != nil { t.Errorf("%s: %v", lang, err) } } }