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

MessageTest.pudu

Pudu94 lines5.7 KB

GitHub ↗
1/** @Test.Domain.Rpc.MessageTest.SuiteJSON-RPC line classification */2module PuduLangMcp.Domain.Rpc.MessageTest34import Std.Io as Io5import Std.Json as Json6import Std.Test as Test7import PuduLangMcp.Constants.Protocol as Protocol8import PuduLangMcp.Domain.Rpc.Message as Message9import PuduLangMcp.Errors.RpcError as RpcError1011/// The code a refused line is answered with, or 0 when it is not refused.12fn refusedCode(line: Str) -> Int {13  match Message.parse(line) {14    case Message.Refused(_, problem) => RpcError.code(&problem)15    case _ => 016  }17}1819/// Whether a refused line kept the id it carried.20fn refusedId(line: Str) -> Option[Message.RequestId] {21  match Message.parse(line) {22    case Message.Refused(id, _) => id23    case _ => None24  }25}2627/// The kind of message a line is, as a word.28fn kindOf(line: Str) -> Str {29  match Message.parse(line) {30    case Message.Request(_, _, _) => "request"31    case Message.Notification(_, _) => "notification"32    case Message.ClientResponse => "response"33    case Message.Refused(_, _) => "refused"34  }35}3637/// The id and method of a request line.38fn requestOf(line: Str) -> Option[(Message.RequestId, Str)] {39  match Message.parse(line) {40    case Message.Request(id, method, _) => Some((id, method))41    case _ => None42  }43}4445/// The params a request line was given.46fn paramsOf(line: Str) -> Json.Json {47  match Message.parse(line) {48    case Message.Request(_, _, params) => params49    case Message.Notification(_, params) => params50    case _ => Json.Null51  }52}5354/// Runs the suite.55fn main() -> Int {56  let checks = Test.suite("Domain.Rpc.Message", &[57      Test.equals("an integer id request", &requestOf("\{\"jsonrpc\":\"2.0\",\"id\":7,\"method\":\"tools/list\"\}"), &Some((Message.NumberId(7), "tools/list"))),58      Test.equals("a string id request", &requestOf("\{\"jsonrpc\":\"2.0\",\"id\":\"a-1\",\"method\":\"x\"\}"), &Some((Message.TextId("a-1"), "x"))),59      Test.equals("id zero is a valid id", &requestOf("\{\"jsonrpc\":\"2.0\",\"id\":0,\"method\":\"x\"\}"), &Some((Message.NumberId(0), "x"))),60      Test.equals("a negative id is kept", &requestOf("\{\"jsonrpc\":\"2.0\",\"id\":-3,\"method\":\"x\"\}"), &Some((Message.NumberId(-3), "x"))),61      Test.differs("string and integer ids differ", &Message.TextId("1"), &Message.NumberId(1)),62      Test.equals("surrounding whitespace is accepted", &kindOf("  \{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"x\"\}\r"), &"request"),63      Test.equals("no id is a notification", &kindOf("\{\"jsonrpc\":\"2.0\",\"method\":\"notifications/initialized\"\}"), &"notification"),64      Test.equals("a result without method is a client response", &kindOf("\{\"jsonrpc\":\"2.0\",\"id\":1,\"result\":\{\}\}"), &"response"),65      Test.equals("an error without method is a client response", &kindOf("\{\"jsonrpc\":\"2.0\",\"id\":1,\"error\":\{\"code\":1,\"message\":\"m\"\}\}"), &"response"),66      Test.equals("text that is not JSON is a parse error", &refusedCode("not json"), &Protocol.PARSE_ERROR),67      Test.equals("an empty line is a parse error", &refusedCode(""), &Protocol.PARSE_ERROR),68      Test.equals("truncated JSON is a parse error", &refusedCode("\{\"jsonrpc\":\"2.0\""), &Protocol.PARSE_ERROR),69      Test.equals("a batch is refused as invalid", &refusedCode("[\{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"x\"\}]"), &Protocol.INVALID_REQUEST),70      Test.equals("a JSON number is not a message", &refusedCode("42"), &Protocol.INVALID_REQUEST),71      Test.equals("a null id is refused", &refusedCode("\{\"jsonrpc\":\"2.0\",\"id\":null,\"method\":\"x\"\}"), &Protocol.INVALID_REQUEST),72      Test.equals("a fractional id is refused", &refusedCode("\{\"jsonrpc\":\"2.0\",\"id\":1.5,\"method\":\"x\"\}"), &Protocol.INVALID_REQUEST),73      Test.equals("a boolean id is refused", &refusedCode("\{\"jsonrpc\":\"2.0\",\"id\":true,\"method\":\"x\"\}"), &Protocol.INVALID_REQUEST),74      Test.equals("a missing jsonrpc member is refused", &refusedCode("\{\"id\":1,\"method\":\"x\"\}"), &Protocol.INVALID_REQUEST),75      Test.equals("jsonrpc 1.0 is refused", &refusedCode("\{\"jsonrpc\":\"1.0\",\"id\":1,\"method\":\"x\"\}"), &Protocol.INVALID_REQUEST),76      Test.equals("a refused envelope keeps its id", &refusedId("\{\"jsonrpc\":\"1.0\",\"id\":9,\"method\":\"x\"\}"), &Some(Message.NumberId(9))),77      Test.equals("a non-string method is refused", &refusedCode("\{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":5\}"), &Protocol.INVALID_REQUEST),78      Test.equals("a missing method is refused", &refusedCode("\{\"jsonrpc\":\"2.0\",\"id\":1\}"), &Protocol.INVALID_REQUEST),79      Test.equals("array params on a request are invalid params", &refusedCode("\{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"x\",\"params\":[1]\}"), &Protocol.INVALID_PARAMS),80      Test.equals("null params on a request are invalid params", &refusedCode("\{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"x\",\"params\":null\}"), &Protocol.INVALID_PARAMS),81      Test.equals("array params on a notification leave it a notification", &kindOf("\{\"jsonrpc\":\"2.0\",\"method\":\"x\",\"params\":[1]\}"), &"notification"),82      Test.equals("absent params are an empty object", &paramsOf("\{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"x\"\}"), &Json.object(&[])),83      Test.equals("object params are kept", &paramsOf("\{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"x\",\"params\":\{\"a\":1\}\}"), &Json.object(&[("a", Json.Number(1))])),84      Test.equals("a unicode method name is kept", &requestOf("\{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"añadir\"\}"), &Some((Message.NumberId(1), "añadir"))),85      Test.equals("an integer id encodes as a number", &Message.idJson(&Message.NumberId(5)), &Json.Number(5)),86      Test.equals("a string id encodes as text", &Message.idJson(&Message.TextId("q")), &Json.Text("q"))87    ])88  let ran = Test.run(&checks)89  for failure in Test.failuresOf(&ran) {90    let _reported = Io.writeErrorLine(failure)91  }92  Test.report(&ran)93}94