
SearchTest.pudu
Pudu59 lines4.4 KB
1/** @Test.Domain.Docs.SearchTest.Suite — documentation ranking */2module PuduLangMcp.Domain.Docs.SearchTest34import Std.Io as Io5import Std.List as List6import Std.Test as Test7import PuduLangMcp.Domain.Docs.Chapter as Chapter8import PuduLangMcp.Domain.Docs.Search as Search9import PuduLangMcp.Generated.Docs as Docs101112fn top(sections: &Array[Chapter.Section], query: Str, limit: Int) -> Array[Str] {13 Search.search(sections, query, limit).map(|hit: Search.Hit| hit.section.chapter + "#" + hit.section.anchor)14}151617fn main() -> Int {18 let sections = Chapter.allSections(&Docs.CHAPTERS)19 let heading = Chapter.Section{group: "docs", chapter: "a", chapterTitle: "A", heading: "Traits", anchor: "traits", text: "nothing"}20 let body = Chapter.Section{group: "docs", chapter: "b", chapterTitle: "B", heading: "Other", anchor: "other", text: "traits traits"}21 let traits = Chapter.Section{..heading, text: "x"}22 let six = Chapter.Section{..heading, heading: "Other", text: "zz zz zz zz zz zz"}23 let five = Chapter.Section{..six, text: "zz zz zz zz zz"}24 let four = Chapter.Section{..six, text: "zz zz zz zz"}25 let first = Chapter.Section{..heading, chapter: "first", heading: "Other", text: "qq"}26 let second = Chapter.Section{..first, chapter: "second"}27 let step = Search.score(&five, "zz", &["zz"]) - Search.score(&four, "zz", &["zz"])28 let checks = Test.suite("Domain.Docs.Search", &[29 Test.equals("stop words are dropped and terms kept once", &Search.terms("How do I use the Result and the Result?"), &["result"]),30 Test.equals("a qualified name stays one term", &Search.terms("Option.unwrapOr"), &["option.unwrapor"]),31 Test.equals("trailing dots are not part of a term", &Search.terms("errors."), &["errors"]),32 Test.equals("a query of stop words has no terms", &Search.terms("how do I"), &[]),33 Test.equals("a query of stop words finds nothing", &top(§ions, "what is the", 5), &[]),34 Test.equals("no terms score zero", &Search.score(&heading, "", &[]), &0),35 Test.that("a heading match outranks text matches", Search.score(&heading, "traits", &["traits"]) > Search.score(&body, "traits", &["traits"])),36 Test.equals("a section without the term scores zero", &Search.score(&body, "ownership", &["ownership"]), &0),37 Test.equals("a three-character phrase in a heading earns the phrase points", &Search.score(&traits, "tra", &["tra"]), &65),38 Test.equals("a two-character query is not scored as a phrase", &Search.score(&traits, "tr", &["tr"]), &25),39 Test.equals("a phrase in the text earns its points", &Search.score(&Chapter.Section{..six, text: "abc"}, "abc", &["abc"]), &29),40 Test.equals("occurrences past five stop adding points", &Search.score(&six, "zz", &["zz"]), &Search.score(&five, "zz", &["zz"])),41 Test.equals("each occurrence up to five adds two points", &step, &2),42 Test.equals("a missing term forfeits the every-term points", &Search.score(&four, "zz yy", &["zz", "yy"]), &8),43 Test.equals("equal scores keep corpus order", &Search.search(&[first, second], "qq", 5).map(|hit: Search.Hit| hit.section.chapter), &["first", "second"]),44 Test.equals("only matching sections are answered", &Search.search(&[first, heading], "qq", 50).length(), &1),45 Test.equals("term characters are letters, digits, underscore, and dot", &Search.terms("Zeta9 alpha_beta x.y q@w r[s t`u v\{z k/l m:n"), &["zeta9", "alpha_beta", "x.y", "q", "w", "r", "s", "t", "u", "v", "z", "k", "l", "m", "n"]),46 Test.equals("a limit of zero answers nothing", &top(§ions, "ownership", 0), &[]),47 Test.equals("the limit bounds the answer", &top(§ions, "error", 3).length(), &3),48 Test.that("error handling finds the errors chapter", top(§ions, "error handling with Result", 3).filter(|at: Str| at.startsWith("errors#")).length() > 0),49 Test.that("structured scopes find the concurrency chapter", List.first(&top(§ions, "async scope", 1)) == Some("concurrency#structured-scopes")),50 Test.that("installing a package finds the dependencies chapter", List.first(&top(§ions, "install a package", 1)) == Some("dependencies#installing-a-dependency")),51 Test.that("a search is repeatable", top(§ions, "traits generics", 5) == top(§ions, "traits generics", 5))52 ])53 let ran = Test.run(&checks)54 for failure in Test.failuresOf(&ran) {55 let _reported = Io.writeErrorLine(failure)56 }57 Test.report(&ran)58}59