75 lines
3.2 KiB
Go
75 lines
3.2 KiB
Go
package lang
|
|
|
|
import "testing"
|
|
|
|
// TestSecondPairDryRun is the §5 "second pair" dry-run for the source-script seam (П2): the echo detector
|
|
// must be REACHABLE for every source the engine handles — a source with no declared script silently sleeps
|
|
// the echo detector (the en/ko blind spots §5 named). Every 2nd-pair source declares a script here.
|
|
func TestSecondPairDryRun(t *testing.T) {
|
|
for _, tc := range []struct {
|
|
lang string
|
|
isCJK bool
|
|
}{
|
|
{"zh", true}, {"ja", true}, {"ko", true}, {"en", false}, {"ru", false},
|
|
} {
|
|
if got := LangScripts(tc.lang); len(got) == 0 {
|
|
t.Errorf("LangScripts(%q) is empty — the echo detector would sleep silently for this source (a §5 blind spot)", tc.lang)
|
|
}
|
|
if got := IsCJKScriptLang(tc.lang); got != tc.isCJK {
|
|
t.Errorf("IsCJKScriptLang(%q) = %v, want %v", tc.lang, got, tc.isCJK)
|
|
}
|
|
}
|
|
// ko (Hangul) and en (Latin) are the two the OLD hard-coded Han+kana detector was blind to.
|
|
if len(LangScripts("ko")) == 0 || len(LangScripts("en")) == 0 {
|
|
t.Fatal("ko/en must resolve scripts — these are the fixed blind spots")
|
|
}
|
|
}
|
|
|
|
// TestSeriesMorphologyUnchanged pins that moving head-finality into data (fix-pack §б) reproduces the prior
|
|
// Go-constant behaviour: every dense source co-batches head-final, every alphabetic source has the channel off.
|
|
func TestSeriesMorphologyUnchanged(t *testing.T) {
|
|
for _, tc := range []struct {
|
|
lang string
|
|
enabled, headFinal bool
|
|
}{
|
|
{"zh", true, true}, {"ja", true, true}, {"ko", true, true},
|
|
{"en", false, false}, {"ru", false, false}, {"unknown", false, false},
|
|
} {
|
|
en, hf := SeriesMorphology(tc.lang)
|
|
if en != tc.enabled || hf != tc.headFinal {
|
|
t.Errorf("SeriesMorphology(%q) = (%v,%v), want (%v,%v)", tc.lang, en, hf, tc.enabled, tc.headFinal)
|
|
}
|
|
}
|
|
// The real embedded data must declare han head-final, or zh would silently flip.
|
|
if !SeriesHeadFinal("han") {
|
|
t.Fatal("data/script-series.txt must declare han head-final")
|
|
}
|
|
}
|
|
|
|
// TestSeriesHeadFinalIsDataDriven is the fix-pack §б generality proof: a dense script's head direction comes
|
|
// from DATA, so declaring a dense NON-head-final script is a data row, not a Go edit. Driven through the pure
|
|
// parser with a synthetic table so it needs no real embedded script.
|
|
func TestSeriesHeadFinalIsDataDriven(t *testing.T) {
|
|
m, err := parseScriptHeadFinal([]byte(
|
|
"# synthetic\nhead_position\ttengwar\tinitial\nhead_position\tcirth\tfinal\n"))
|
|
if err != nil {
|
|
t.Fatalf("valid table must parse: %v", err)
|
|
}
|
|
if m["tengwar"] {
|
|
t.Fatal("a script declared `initial` must resolve head-INITIAL from data with no Go edit")
|
|
}
|
|
if !m["cirth"] {
|
|
t.Fatal("a script declared `final` must resolve head-final")
|
|
}
|
|
// An unlisted script defaults to head-final (the CJK modifier-head norm) through the exported resolver.
|
|
if !SeriesHeadFinal("no-such-script-xyz") {
|
|
t.Fatal("an unlisted script must default to head-final")
|
|
}
|
|
// Corrupt data is loud, never silent.
|
|
if _, err := parseScriptHeadFinal([]byte("head_position\than\tsideways\n")); err == nil {
|
|
t.Fatal("an invalid head position must be a parse error")
|
|
}
|
|
if _, err := parseScriptHeadFinal([]byte("wrong_cat\than\tfinal\n")); err == nil {
|
|
t.Fatal("an unknown category must be a parse error")
|
|
}
|
|
}
|