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

ServicesTest.pudu

Pudu119 lines8.3 KB

GitHub ↗
1/** @Test.Services.ServicesTest.Suite — processes, discovery, and module files */2module PuduLangMcp.Services.ServicesTest34import Std.Bytes as ByteSeq5import Std.Env as Env6import Std.Fs as Fs7import Std.Io as Io8import Std.Path as Path9import Std.Result as Result10import Std.Test as Test11import PuduLangMcp.Services.Process.Bounded as Bounded12import PuduLangMcp.Services.Reference as Reference13import PuduLangMcp.Services.Toolchain as Toolchain14import PuduLangMcp.Services.Workspace as Workspace1516/// A finished shell command, or a marker for one that could not start.17fn shell(script: Str, input: Str, millis: Int, cap: Int) -> Bounded.Finished {18  Result.unwrapOr(Bounded.run("/bin/sh", &["-c", script], input, "", millis, cap), Bounded.Finished{status: -99, output: "", errors: "", timedOut: false, truncated: false, millis: 0})19}2021/// Writes a file, creating its directory.22fn place(path: Str, text: Str) -> () {23  let _made = Io.makeDirectory(Path.directoryOf(path))24  let _written = Io.write(path, text)25}2627/// Runs the suite.28fn main() -> Int {29  let temporary = Env.temporaryDirectory()30  let mixed = shell("echo out; echo err >&2; exit 3", "", 5000, 4096)31  let echoed = shell("cat", "line one\nline two", 5000, 4096)32  let slow = shell("sleep 5", "", 200, 4096)33  let held = shell("echo early; sleep 5; true", "", 200, 4096)34  let quiet = shell("sleep 5 2>/dev/null; true", "", 200, 4096)35  let late = shell("echo first; (sleep 0.05; echo second) &", "", 5000, 4096)36  let flood = shell("yes x | head -c 100000", "", 5000, 1000)37  let missing = Bounded.run("/nonexistent/program", &[], "", "", 1000, 1000)38  let accent = ByteSeq.fromText("é")39  let euro = ByteSeq.fromText("€")40  let emoji = ByteSeq.fromText("😀")41  let mixedText = ByteSeq.fromText("a😀")42  let exactCap = shell("head -c 1000 /dev/zero | tr '\\000' x", "", 5000, 1000)43  let pastCapLater = shell("head -c 1000 /dev/zero | tr '\\000' x; sleep 0.3; printf y", "", 5000, 1000)44  let archive = Result.unwrapOr(Fs.temporaryDirectoryIn(temporary, "pudu-mcp-archive-"), "/nonexistent")45  place(archive + "/bin/pudu", "")46  place(archive + "/lib/pudu/Std/Io.pudu", "module Std.Io\n")47  let checkout = Result.unwrapOr(Fs.temporaryDirectoryIn(temporary, "pudu-mcp-checkout-"), "/nonexistent")48  place(checkout + "/dist/build/x/pudu", "")49  place(checkout + "/packages/pudu/v0.1/lib/Std/Io.pudu", "module Std.Io\n")50  place(checkout + "/packages/pudu/v0.2/lib/Std/Io.pudu", "module Std.Io\n")51  let lonely = Result.unwrapOr(Fs.temporaryDirectoryIn(temporary, "pudu-mcp-lonely-"), "/nonexistent")52  place(lonely + "/bin/pudu", "")53  let workspace = Result.unwrapOr(Fs.temporaryDirectoryIn(temporary, "pudu-mcp-deps-"), "/nonexistent")54  place(workspace + "/deps/shapes/src/Shapes.pudu", "module Shapes\n")55  place(workspace + "/deps/shapes/src/Shapes/Area.pudu", "module Shapes.Area\n")56  place(workspace + "/deps/shapes/README.md", "no module")57  place(workspace + "/deps/flat/Flat.pudu", "module Flat\n")58  place(workspace + "/deps/clash/src/Std/Io.pudu", "module Std.Io\n")59  place(workspace + "/deps/deep/src/" + "D/".repeat(12) + "Found.pudu", "module Found\n")60  place(workspace + "/deps/deeper/src/" + "E/".repeat(13) + "Lost.pudu", "module Lost\n")61  let files = Reference.moduleFiles(Some(archive + "/lib/pudu"), workspace)62  let names = files.map(|held: Reference.ModuleFile| held.moduleName)63  let stdIo = Reference.fileOf(&files, "Std.Io")64  let located = Workspace.at(workspace)65  let checks = Test.suite("Services", &[66      Test.equals("a run answers its exit status", &mixed.status, &3),67      Test.equals("a run answers its standard output", &mixed.output.trim(), &"out"),68      Test.equals("a run answers its standard error", &mixed.errors.trim(), &"err"),69      Test.not("a finished run did not time out", mixed.timedOut),70      Test.equals("input reaches the child", &echoed.output, &"line one\nline two"),71      Test.that("a slow child is stopped at its deadline", slow.timedOut && slow.status == -1),72      Test.that("a stopped child costs about its deadline", slow.millis < 3000),73      Test.that("a grandchild holding the streams does not outlast the deadline", held.timedOut && held.millis < 3000),74      Test.equals("output written before the deadline is kept", &held.output.trim(), &"early"),75      Test.that("a stream left open past the grace is marked cut", held.truncated),76      Test.not("a run whose streams closed is not marked cut", mixed.truncated),77      Test.that("a silent stream held open alone still ends near the deadline", quiet.timedOut && quiet.millis < 3000),78      Test.that("one stream left open is enough to mark the run cut", quiet.truncated),79      Test.equals("a stream that closes within the grace is read to its end", &late.output.trim(), &"first\nsecond"),80      Test.not("a stream that closes within the grace is not marked cut", late.truncated),81      Test.that("output past the cap is cut and marked", flood.truncated && flood.output.length() == 1000),82      Test.errored("a program that cannot start is an error", &missing),83      Test.equals("a cut inside a character backs off to its start", &Bounded.textWithin(&accent, 1), &("", true)),84      Test.equals("a cut inside a three-byte character backs off", &[Bounded.textWithin(&euro, 1), Bounded.textWithin(&euro, 2)], &[("", true), ("", true)]),85      Test.equals("a cut inside a four-byte character backs off", &Bounded.textWithin(&emoji, 3), &("", true)),86      Test.equals("a cut after text keeps the text before the broken character", &Bounded.textWithin(&mixedText, 4), &("a", true)),87      Test.equals("a four-byte character within the cap is whole", &Bounded.textWithin(&emoji, 4), &("😀", false)),88      Test.that("output exactly at the cap is whole", !exactCap.truncated && exactCap.output.length() == 1000),89      Test.that("output past the cap in a later write is still cut", pastCapLater.truncated && pastCapLater.output.length() == 1000),90      Test.equals("text within the cap is whole", &Bounded.textWithin(&accent, 2), &("é", false)),91      Test.equals("bytes that are not text are marked", &Bounded.textWithin(&ByteSeq.fromArray(&[255u8, 254u8, 253u8, 252u8, 251u8]), 8), &("[output that is not UTF-8 text]", false)),92      Test.equals("one invalid byte is not a truncated character", &Bounded.textWithin(&ByteSeq.fromArray(&[255u8]), 8), &("[output that is not UTF-8 text]", false)),93      Test.not("a child has time before its deadline", Bounded.deadlineReached(99, 100)),94      Test.that("a child expires at and after its deadline", Bounded.deadlineReached(100, 100) && Bounded.deadlineReached(101, 100)),95      Test.not("scripted finished output is not truncated", Toolchain.finished(0, "x").truncated),96      Test.equals("an archive's library is beside its bin directory", &Toolchain.libraryFrom(archive + "/bin/pudu"), &Some(archive + "/lib/pudu")),97      Test.equals("a checkout's newest series is chosen", &Toolchain.libraryFrom(checkout + "/dist/build/x/pudu"), &Some(checkout + "/packages/pudu/v0.2/lib")),98      Test.equals("no library anywhere above is none", &Toolchain.libraryFrom(lonely + "/bin/pudu"), &None),99      Test.that("installed packages are importable modules", names.contains("Shapes") && names.contains("Shapes.Area")),100      Test.that("a package without src is read from its root", names.contains("Flat")),101      Test.equals("the library wins a duplicate module name", &match stdIo { case Some(held) => held.origin case None => "" }, &"Std"),102      Test.equals("module files are sorted by name", &names.filter(|name: Str| !name.startsWith("D.") && !name.startsWith("E.")), &["Flat", "Shapes", "Shapes.Area", "Std.Io"]),103      Test.that("a module twelve directories deep is found", names.contains("D.D.D.D.D.D.D.D.D.D.D.D.Found")),104      Test.not("a module thirteen directories deep is not", names.contains("E.E.E.E.E.E.E.E.E.E.E.E.E.Lost")),105      Test.succeeded("a workspace path resolves inside it", &Workspace.resolve(&located, "deps/flat/Flat.pudu")),106      Test.equals("a relative path is shown from the root", &Workspace.relative(&located, located.root + "/deps/flat/Flat.pudu"), &"deps/flat/Flat.pudu"),107      Test.equals("a path outside is shown whole", &Workspace.relative(&located, "/etc/hosts"), &"/etc/hosts")108    ])109  let _a = Fs.removeTree(archive)110  let _b = Fs.removeTree(checkout)111  let _c = Fs.removeTree(lonely)112  let _d = Fs.removeTree(workspace)113  let report = Test.run(&checks)114  for failure in Test.failuresOf(&report) {115    let _reported = Io.writeErrorLine(failure)116  }117  Test.report(&report)118}119