Pudu programming language
Menu
Package

@chrismichaelps / pudu-lang-httpclient

Named HTTP clients for Pudu: a client factory, delegating handlers, pooled keep-alive connections, handler lifetimes, logging, and resilience

0.1.1Apache-2.01

InstallClose

ContentTest.pudu

Pudu52 lines4.0 KB

GitHub ↗
1/** @Test.Content.Suite — message bodies and the headers describing them */2module PuduLangHttpClient.ContentTest34import Std.Io as Io5import Std.Json as Json6import Std.Test as Test7import PuduLangHttpClient.Content as Content8import PuduLangHttpClient as HttpClient910/** @Test.Content.Order — a body written and read as JSON through derived implementations */11type Order = { id: Int, item: Str, gift: Option[Bool] } derives Json.Encode, Json.Decode1213/// Runs the suite.14fn main() -> Int {15  let order = Order{id: 7, item: "tea", gift: None}16  let multipart = Content.multipartWith("b0", &[Content.field("note", "hi"), Content.file("doc", "a\"b.txt", "text/plain", &"x".toBytes())])17  let random = Content.multipart(&[Content.field("a", "1")])18  let checks = Test.suite("Content", &[19      Test.equals("an empty body has no bytes and no headers", &Content.empty(), &Content.Content{payload: "".toBytes(), headers: [], stream: None}),20      Test.equals("plain text is UTF-8 text", &Content.plain("héllo"), &Content.Content{payload: "héllo".toBytes(), headers: [("content-type", "text/plain; charset=utf-8")], stream: None}),21      Test.equals("text gains a charset only when it names none", &(Content.text("<p/>", "text/html").headers, Content.text("x", "text/csv; charset=latin1").headers), &([("content-type", "text/html; charset=utf-8")], [("content-type", "text/csv; charset=latin1")])),22      Test.equals("bytes keep their media type", &(Content.bytes(&"ab".toBytes(), "image/png").headers, Content.octets(&"ab".toBytes()).headers), &([("content-type", "image/png")], [("content-type", "application/octet-stream")])),23      Test.equals("a derived value is written as JSON", &Content.readText(&Content.jsonOf(&order)), &Ok("\{\"id\":7,\"item\":\"tea\",\"gift\":null\}")),24      Test.equals("JSON reads back into a derived value", &Content.readAs(&Content.jsonOf(&order)), &Ok(order)),25      Test.equals("a form is url-encoded", &Content.readText(&Content.form(&[("q", "a b"), ("x", "1&2")])), &Ok("q=a+b&x=1%262")),26      Test.equals("a form reads back into fields", &Content.readForm(&Content.form(&[("q", "a b"), ("x", "1&2")])), &Ok([("q", "a b"), ("x", "1&2")])),27      Test.equals("a multipart body frames each part", &Content.readText(&multipart), &Ok("--b0\r\ncontent-disposition: form-data; name=\"note\"\r\n\r\nhi\r\n--b0\r\ncontent-disposition: form-data; name=\"doc\"; filename=\"a\\\"b.txt\"\r\ncontent-type: text/plain\r\n\r\nx\r\n--b0--\r\n")),28      Test.equals("a multipart body names its boundary", &Content.mediaTypeOf(&multipart), &Some("multipart/form-data")),29      Test.that("a random boundary is used when none is given", match random.headers {30          case [(_, value)] => value.startsWith("multipart/form-data; boundary=pudu-")31          case _ => false32        }),33      Test.equals("a header is set once", &Content.withHeader(&Content.plain("x"), "Content-Type", "text/csv").headers, &[("Content-Type", "text/csv")]),34      Test.that("a streamed body holds a producer and no bytes", Content.isStreamed(&Content.streamed("text/csv", || None)) && Content.streamed("text/csv", || None).payload.isEmpty() && !Content.isStreamed(&Content.plain("x"))),35      Test.equals("the length counts bytes", &Content.length(&Content.plain("é")), &2),36      Test.equals("bytes that are not text are unreadable as text", &Content.readText(&Content.octets(&"é".toBytes().take(1))), &Err(HttpClient.Unreadable("the body is not UTF-8 text"))),37      Test.that("text that is not JSON is unreadable as JSON", match Content.readJson(&Content.plain("\{nope")) {38          case Err(HttpClient.Unreadable(reason)) => reason.startsWith("the body is not JSON: ")39          case _ => false40        }),41      Test.that("JSON of another shape is unreadable as the type", match Content.readAs[Order](&Content.plain("\{\"id\":\"x\"\}")) {42          case Err(HttpClient.Unreadable(reason)) => reason.startsWith("the body does not decode: ")43          case _ => false44        })45    ])46  let ran = Test.run(&checks)47  for failure in Test.failuresOf(&ran) {48    let _reported = Io.writeErrorLine(failure)49  }50  Test.report(&ran)51}52