package terminology import ( "reflect" "strings" "testing" ) func TestParseTypesKeepsOnlyAskedAndVocabulary(t *testing.T) { id := func(s string) string { return s } reply := strings.Join([]string{ "元石\tterm", "方源 name", // spaces instead of a tab — tolerant split "青茅山 | place", // padded pipe "家老\tPERSON", // off-vocabulary → refused and counted "陌生\tterm", // never asked → refused and counted "元石\tname", // duplicate key → first answer wins "мусор", // one field → refused and counted }, "\n") got, st := ParseTypes(reply, []string{"元石", "方源", "青茅山", "家老"}, id) want := map[string]string{"元石": "term", "方源": "name", "青茅山": "place"} if !reflect.DeepEqual(got, want) { t.Fatalf("parse = %#v, want %#v", got, want) } // off-vocabulary PERSON + unasked 陌生 + malformed мусор = 3 bad lines (the duplicate is silently ignored, // not counted, exactly like ParseReply). if st.Bad != 3 { t.Fatalf("unusable/off-vocabulary lines must be COUNTED, got %d", st.Bad) } } func TestParseTypesNormalizesKey(t *testing.T) { got, _ := ParseTypes("FANG\tname", []string{"fang"}, strings.ToLower) if got["fang"] != "name" { t.Fatalf("the reply key must be normalized by the caller's function, got %#v", got) } } // TestTypeLabelMismatchesIsHonest pins the screen's DELIBERATE limit: it flags a name/place whose rendering // was clearly translated (multi-word), but it is NOT a safety net — a mistyped name rendered as one token, // lower-case (元石→юаньши) or capitalised (元海→Юаньхай), passes it clean. The classifier phase is what // prevents that harm; asserting the miss keeps a future reader from mistaking this for the guard. func TestTypeLabelMismatchesIsHonest(t *testing.T) { rows := []LabelRow{ {Src: "花家", Type: "name", Dst: "Дом Хуа"}, // translated name → FLAG {Src: "青茅山", Type: "place", Dst: "гора Цинмао"}, // translated place → FLAG {Src: "元石", Type: "name", Dst: "юаньши"}, // the harm, single lower-case token → MISSED {Src: "元海", Type: "name", Dst: "Юаньхай"}, // the harm, capitalised token → MISSED {Src: "灵泉", Type: "term", Dst: "духовный источник"}, // term is not screened → not flagged } got := TypeLabelMismatches(rows) var srcs []string for _, r := range got { srcs = append(srcs, r.Src) } if !reflect.DeepEqual(srcs, []string{"花家", "青茅山"}) { t.Fatalf("only the translated name/place rows must flag, got %v", srcs) } }