105 lines
5.1 KiB
Go
105 lines
5.1 KiB
Go
package terminology
|
||
|
||
import (
|
||
"strings"
|
||
"testing"
|
||
"unicode"
|
||
)
|
||
|
||
// offLanguageReplies are renderings a live model actually returned when it lost the target language, and
|
||
// signedRenderings are renderings from a real signed bank plus the shapes most likely to be false
|
||
// positives (two letters, digits only, quoted, doubled space). Both lists are the acceptance material for
|
||
// the screen: every line of the first must be refused, every line of the second must pass.
|
||
var (
|
||
offLanguageReplies = []string{"cultivation", "Primordial Sea", "Rank 1", "Grade C", "talent",
|
||
"Wine Bug", "realm", "Qingmao Mountain", "Gu Yue", "is"}
|
||
signedRenderings = []string{"культивация", "море истинной ци", "гу-мастер", "Фан Юань", "гу",
|
||
"талант", "винный червь", "старейшина", "Гуюэ", "апертура", "третья гу", "гу Силы",
|
||
"Река времени", "9", "«Ода сливе»", "Фан Юань"}
|
||
)
|
||
|
||
func TestOffLanguageSeparatesForeignRenderingsFromTargetOnes(t *testing.T) {
|
||
cyr := unicode.Scripts["Cyrillic"]
|
||
for _, s := range offLanguageReplies {
|
||
if !OffLanguage(s, cyr) {
|
||
t.Errorf("%q must be refused: it carries letters and none of them are in the target script", s)
|
||
}
|
||
}
|
||
for _, s := range signedRenderings {
|
||
if OffLanguage(s, cyr) {
|
||
t.Errorf("%q is a legitimate rendering and must pass", s)
|
||
}
|
||
}
|
||
// A mixed rendering passes deliberately: one target-script letter is enough, so the screen never
|
||
// touches a rendering that carries a foreign name beside a target word.
|
||
if OffLanguage("Фан Юань (Fang Yuan)", cyr) {
|
||
t.Error("a mixed rendering must pass — the screen judges language, not spelling")
|
||
}
|
||
if OffLanguage("anything", nil) {
|
||
t.Error("with no declared script the screen must be inert")
|
||
}
|
||
}
|
||
|
||
// TestOffLanguageIsTargetBlind is the generality pin: nothing about a language lives in this package, so
|
||
// swapping the declared script swaps every verdict and no Go edit is involved.
|
||
func TestOffLanguageIsTargetBlind(t *testing.T) {
|
||
lat := unicode.Scripts["Latin"]
|
||
if !OffLanguage("культивация", lat) || OffLanguage("cultivation", lat) {
|
||
t.Fatal("under a Latin target the verdicts must be exactly reversed")
|
||
}
|
||
// A pair with neither script: Han as a target refuses both of the above and accepts a Han rendering.
|
||
han := unicode.Scripts["Han"]
|
||
if !OffLanguage("культивация", han) || !OffLanguage("cultivation", han) || OffLanguage("元海", han) {
|
||
t.Fatal("a third target must work on the same code path")
|
||
}
|
||
if _, ok := ScriptByName("Cyrillic"); !ok {
|
||
t.Fatal("a valid script name must resolve")
|
||
}
|
||
if _, ok := ScriptByName("cyrillic"); ok {
|
||
t.Fatal("resolution must be exact, so a typo fails loudly at config load instead of disabling the screen")
|
||
}
|
||
}
|
||
|
||
// TestParseReplyRefusesForeignLanguageRenderings pins the screen where it actually protects the bank: a
|
||
// reply mixing correct and foreign-language lines banks only the correct ones, counts the rest, and names
|
||
// them. Without the screen every line here is accepted and reaches the editor as this book's canon.
|
||
func TestParseReplyRefusesForeignLanguageRenderings(t *testing.T) {
|
||
id := func(s string) string { return s }
|
||
keys := []string{"修行", "元海", "转", "是为", "资质"}
|
||
reply := "修行\tcultivation\n元海\tPrimordial Sea\n转\trealm\n是为\tis\n资质\tталант"
|
||
|
||
got, _, st := ParseReply(reply, keys, id, unicode.Scripts["Cyrillic"], nil)
|
||
if len(got) != 1 || got["资质"] != "талант" {
|
||
t.Fatalf("only the target-language line may be banked, got %#v", got)
|
||
}
|
||
if st.OffLanguage != 4 || st.Bad != 4 {
|
||
t.Fatalf("all four foreign lines must be refused AND counted, got off_language=%d bad=%d", st.OffLanguage, st.Bad)
|
||
}
|
||
if len(st.OffLanguageSamples) != 4 || !strings.Contains(st.OffLanguageSamples[0], "cultivation") {
|
||
t.Fatalf("the refused lines must be named for the operator, got %q", st.OffLanguageSamples)
|
||
}
|
||
// Without a declared script the same reply is banked whole — the state the engine was in before, kept
|
||
// visible so the cost of an undeclared script is a test, not a surprise.
|
||
if inert, _, st := ParseReply(reply, keys, id, nil, nil); len(inert) != 5 || st.OffLanguage != 0 {
|
||
t.Fatalf("with no script the screen must be inert (that is what config refuses for an enabled gate), got %#v", inert)
|
||
}
|
||
}
|
||
|
||
// TestOffLanguageSamplesAreBounded keeps a whole batch answered in the wrong language from turning one
|
||
// warning into the reply itself.
|
||
func TestOffLanguageSamplesAreBounded(t *testing.T) {
|
||
id := func(s string) string { return s }
|
||
var lines []string
|
||
var keys []string
|
||
for _, k := range []string{"a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9", "b1", "b2", "b3"} {
|
||
keys = append(keys, k)
|
||
lines = append(lines, k+"\tforeign")
|
||
}
|
||
_, _, st := ParseReply(strings.Join(lines, "\n"), keys, id, unicode.Scripts["Cyrillic"], nil)
|
||
if st.OffLanguage != len(keys) {
|
||
t.Fatalf("every foreign line must be counted, got %d of %d", st.OffLanguage, len(keys))
|
||
}
|
||
if len(st.OffLanguageSamples) != offLanguageSampleCap {
|
||
t.Fatalf("the samples must stop at %d, got %d", offLanguageSampleCap, len(st.OffLanguageSamples))
|
||
}
|
||
}
|