package eval import ( "math/rand" "testing" "unicode/utf8" "git.totmin.ru/en2zmax/addrkit/internal/domain/address" "git.totmin.ru/en2zmax/addrkit/internal/domain/match" ) // TestMoveTypeFront guards against the slice-aliasing regression that made the // type word disappear. func TestMoveTypeFront(t *testing.T) { got := moveTypeFront("станционная улица 1/1") if got != "улица станционная 1/1" { t.Fatalf("moveTypeFront = %q", got) } got = moveTypeFront("2-я станционная улица 1/1") if got != "улица 2-я станционная 1/1" { t.Fatalf("moveTypeFront with ordinal = %q", got) } } // TestAddYoKeepsValidUTF8 guards against the byte-index regression. func TestAddYoKeepsValidUTF8(t *testing.T) { cases := []string{"переулок 5", "Северный проезд 7", "Зеленхозовская улица 48", "дом 1"} for _, in := range cases { out := addYo(in) if out != "" && !utf8.ValidString(out) { t.Fatalf("addYo(%q) produced invalid UTF-8: %q", in, out) } } if got := addYo("переулок 5"); got != "пёреулок 5" { t.Fatalf("addYo = %q", got) } } // TestMutateOnlyNameTokens verifies typos never target the street type word, // which would turn into a bogus name token. func TestMutateOnlyNameTokens(t *testing.T) { rng := rand.New(rand.NewSource(7)) for i := 0; i < 200; i++ { got := mutateLongestToken("Станционная улица 1/1", rng) if got == "" { continue } if got == "Станционная улицб 1/1" || got == "Станционная улиц 1/1" { t.Fatalf("type word was mutated: %q", got) } } } // TestRunDetectsWrongCity guards the multi-city safety net: canonical address // text is identical across cities, so a found result must be checked against // the expected city, not only against street/house text. func TestRunDetectsWrongCity(t *testing.T) { parser := address.NewParser(address.NewDictionary([]address.City{{Name: "Бердск"}}), "") p := parser.ParseInCity("Ленина улица 5", "Бердск") entries := []address.Entry{{ ID: "b1", Address: "Ленина улица 5", City: p.City, CityKey: p.CityKey, Ordinal: p.Ordinal, NameKey: p.NameKey, StreetKey: p.StreetKey, House: p.House, }} resolver := match.NewResolverWithOptions( match.NewIndex("test", entries, match.DefaultOptions()), nil, match.ResolverOptions{Parser: parser}, ) cases := []Case{ {Query: "Ленина 5", Expect: "Ленина улица 5", ExpectCity: "Новосибирск", Category: "wrong_city", RequireExact: true}, {Query: "Ленина 5", Expect: "Ленина улица 5", ExpectCity: "Бердск", Category: "right_city", RequireExact: true}, } rep := Run(resolver, cases) if got := rep.Categories["wrong_city"]; got.WrongCity != 1 || got.Exact != 0 { t.Fatalf("wrong_city = %+v, want WrongCity=1 Exact=0", got) } if got := rep.Categories["right_city"]; got.Exact != 1 || got.WrongCity != 0 { t.Fatalf("right_city = %+v, want Exact=1 WrongCity=0", got) } if rep.Wrong != 1 { t.Fatalf("report Wrong = %d, want 1", rep.Wrong) } }