Pudu programming language
Menu
Package

@chrismichaelps / pudu-lang-mcp

Model Context Protocol server for Pudu language documentation and compiler tools

0.1.1Apache-2.01

InstallClose

SearchTest.pudu

Pudu59 lines4.4 KB

GitHub ↗
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 Docs1011/// The addresses of the best sections for a query over the corpus.12fn 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}1516/// Runs the suite.17fn 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(&sections, "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(&sections, "ownership", 0), &[]),47      Test.equals("the limit bounds the answer", &top(&sections, "error", 3).length(), &3),48      Test.that("error handling finds the errors chapter", top(&sections, "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(&sections, "async scope", 1)) == Some("concurrency#structured-scopes")),50      Test.that("installing a package finds the dependencies chapter", List.first(&top(&sections, "install a package", 1)) == Some("dependencies#installing-a-dependency")),51      Test.that("a search is repeatable", top(&sections, "traits generics", 5) == top(&sections, "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