91 lines
5.2 KiB
Go
91 lines
5.2 KiB
Go
package lang
|
||
|
||
import (
|
||
"strings"
|
||
"testing"
|
||
)
|
||
|
||
// TestTheDeclineRegistryShipsEmpty pins ONE data decision: the engine ships with NO decline phrases, so
|
||
// the reply parser recognises the ⟦TM-NO-DST⟧ sentinel and nothing else.
|
||
//
|
||
// WHY A PIN AND NOT A FILE NOBODY LOOKS AT. A mechanism that lands switched off in DATA is invisible to
|
||
// every gate the project has — that class is written twice in the backlog (rows 433 and 435: a built,
|
||
// ratified mechanism sitting dark because a number in a yaml says so, with nothing red anywhere). The
|
||
// emptiness here is deliberate and has a price attached, so it is asserted where a later edit meets it.
|
||
//
|
||
// ⛔ THE CONDITION UNDER WHICH THIS TEST STOPS BEING RIGHT, stated so the next session does not have to
|
||
// guess: the registry ships empty because the population of prose declines has been MEASURED at zero on
|
||
// everything this project has bought (research/35 §2.0 row Б-5: 0 of 69 and 0 of 66, control 69/69 and
|
||
// 66/66) — so a phrase authored today would be a guess about wording, and a WRONG guess takes a rendering
|
||
// the book paid for out of its bank with no retry to recover it (backlog row 438). When a population IS
|
||
// measured, the row and this test change TOGETHER, and the measurement is what the change cites.
|
||
func TestTheDeclineRegistryShipsEmpty(t *testing.T) {
|
||
rows, err := parseDeclinePhrases(mustBankData("bankdata/decline-phrases.txt"))
|
||
if err != nil {
|
||
t.Fatalf("the shipped registry must parse: %v", err)
|
||
}
|
||
if len(rows) != 0 {
|
||
t.Errorf("the shipping decline registry carries %d language(s) of phrases: %v.\n"+
|
||
"That is a BEHAVIOUR change on the money path — a matched phrase drops a paid rendering out of "+
|
||
"the bank — so it lands with the measurement that justifies it, and this test changes in the "+
|
||
"same edit", len(rows), rows)
|
||
}
|
||
// The CONTROL that keeps the zero above from being a zero about the wrong thing: the file is read,
|
||
// non-empty and parseable — «no rows» is not «no file» (a missing asset panics in mustBankData) and
|
||
// not «every line is a comment the parser silently drops».
|
||
raw := mustBankData("bankdata/decline-phrases.txt")
|
||
if len(raw) < 500 || !strings.Contains(string(raw), "lang<TAB>phrase") {
|
||
t.Errorf("the registry file must be the documented one, %d bytes read", len(raw))
|
||
}
|
||
for _, target := range []string{"ru", "en", "xx", ""} {
|
||
if d := DeclinePhrasesFor(target); !d.Empty() || d.Match("не термин") {
|
||
t.Errorf("target %q must resolve to an INERT registry", target)
|
||
}
|
||
}
|
||
}
|
||
|
||
// TestTheDeclineMatchIsTheWholeFieldAndFoldsTheShapesAModelWrites pins the matcher on a synthetic
|
||
// registry — the shipping one is empty, and a matcher nobody can exercise is a matcher nobody has tested.
|
||
//
|
||
// The fold exists because the two sides are authored by different hands: the phrase by a human editing a
|
||
// file, the field by a model writing a reply. A row authored as «не термин» must still match «„Не термин.“»
|
||
// — and must NOT match a rendering that merely contains those words.
|
||
func TestTheDeclineMatchIsTheWholeFieldAndFoldsTheShapesAModelWrites(t *testing.T) {
|
||
rows, err := parseDeclinePhrases([]byte("# a synthetic registry\nru\tне термин\nru\tэто не имя\n*\tnot a term\n"))
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
// Resolved by the SAME function production resolves with, over rows given instead of loaded — no
|
||
// global is swapped, so the emptiness test beside this one keeps measuring the shipped file and not
|
||
// this fixture's leftovers.
|
||
ru := declinePhrasesFrom(rows, "ru")
|
||
if ru.Empty() {
|
||
t.Fatal("premise broken: the synthetic registry must resolve non-empty, or every assertion below passes vacuously")
|
||
}
|
||
for _, yes := range []string{"не термин", " НЕ ТЕРМИН ", "«Не термин»", "не термин.", "„не термин!“", "это не имя"} {
|
||
if !ru.Match(yes) {
|
||
t.Errorf("a decline written %q must match the authored phrase — the model chooses the quoting, the file cannot", yes)
|
||
}
|
||
}
|
||
// ⛔ THE ARM WITH THE PRICE ON IT: a substring match would turn each of these paid renderings into a
|
||
// decline, dropping a row the book bought out of its own bank.
|
||
for _, no := range []string{"клан, а не термин родства", "Не терминал", "термин", "Фан Юань", ""} {
|
||
if ru.Match(no) {
|
||
t.Errorf("a rendering that is not the whole phrase must be KEPT: %q", no)
|
||
}
|
||
}
|
||
// The any-target rows join every target; a target's own rows do not leak into another target.
|
||
if !declinePhrasesFrom(rows, "en").Match("Not a term") {
|
||
t.Error("an any-target phrase must fire for a target with no rows of its own")
|
||
}
|
||
if declinePhrasesFrom(rows, "en").Match("не термин") {
|
||
t.Error("a ru phrase must not decline for an en book — the registry is keyed by language for a reason")
|
||
}
|
||
if !declinePhrasesFrom(rows, "RU ").Match("не термин") {
|
||
t.Error("the language key must fold case and spaces, or a book.yaml written `RU` silently gets no registry")
|
||
}
|
||
// A row that folds to nothing is refused rather than left matching every empty field.
|
||
if _, err := parseDeclinePhrases([]byte("ru\t \n")); err == nil {
|
||
t.Error("a phrase that folds to nothing must fail the parse")
|
||
}
|
||
}
|