Pudu programming language
Menu
Package

@chrismichaelps / pudu-lang-docgen

Documentation publishing for Pudu: articles, API references, navigation, search, and static websites

0.1.0Apache-2.01

InstallClose

PathsTest.pudu

Pudu37 lines3.2 KB

GitHub ↗
1/** @Docgen.Paths.Tests — publication boundaries and destination escaping remain observable */2module PuduLangDocgen.PathsTest34import Std.Io as Io5import Std.Test as Test6import PuduLangDocgen.Paths as Paths78/// Runs every output path, destination, fragment, and escaping contract.9fn main() -> Int {10  let checks = Test.suite("Paths", &[11      Test.that("portable relative paths", Paths.relative("articles/hello-world.html")),12      Test.that("unicode path", Paths.relative("guide/été.md")),13      Test.that("invalid publication paths", ["", "/root", "../root", "a/../b", "a/./b", "a//b", "a/", "C:/file", "a\\b", "a%2fb", "a?b", "a#b", "a\n", "CON.txt", "a/lpt9", "a.", "a ", "<a>"].filter(|value: Str| Paths.relative(value)).isEmpty()),14      Test.that("safe browser destinations", ["https://example.org/a?q=1#b", "http://localhost:8080/", "mailto:a@example.org", "../other.md", "#section", "?lang=en", "a.md?x=1#h"].filter(|value: Str| !Paths.href(value)).isEmpty()),15      Test.that("unsafe browser destinations", ["", "javascript:alert(1)", "JaVaScRiPt:alert(1)", "data:text/html,hi", "//example.org", " https://example.org", "a\n", "a\\b", "https://", "https:///host", "https://user@host"].filter(|value: Str| Paths.href(value)).isEmpty()),16      Test.equals("slug separators collapse", &Paths.slug(" Hello,   World! "), &"hello-world"),17      Test.equals("slug unicode preserved", &Paths.slug("Été 中文"), &"été-中文"),18      Test.equals("empty slug fallback", &Paths.slug("---"), &"section"),19      Test.equals("article suffix mapping", &[Paths.output("a.md"), Paths.output("a.MARKDOWN"), Paths.output("a.png")], &["a.html", "a.html", "a.png"]),20      Test.equals("relative resolution and query", &Paths.resolve("guide/start.md", "../api.md?x=1#hello"), &Ok("api.html?x=1#hello")),21      Test.equals("same page fragments", &Paths.resolve("guide/start.md", "#hello"), &Ok("guide/start.html#hello")),22      Test.equals("same page queries", &Paths.resolve("guide/start.md", "?lang=en#hello"), &Ok("guide/start.html?lang=en#hello")),23      Test.equals("external stays external", &Paths.resolve("index.md", "https://example.org/a"), &Ok("https://example.org/a")),24      Test.equals("root escape is refused", &Paths.resolve("index.md", "../secret.md"), &Err("destination escapes docset root")),25      Test.equals("encoded local path refused", &Paths.resolve("index.md", "%2e%2e/secret.md"), &Err("encoded local path is not supported")),26      Test.equals("unsafe source refused", &Paths.resolve("../index.md", "a.md"), &Err("invalid source path")),27      Test.equals("unsafe destination refused", &Paths.resolve("index.md", "javascript:run"), &Err("unsafe destination")),28      Test.equals("dot segments resolve", &Paths.resolve("guide/start.md", "./next.md"), &Ok("guide/next.html")),29      Test.equals("empty destination segment refused", &Paths.resolve("index.md", "a//b.md"), &Err("empty destination segment")),30      Test.equals("invalid local output refused", &Paths.resolve("index.md", "a|b.md"), &Err("invalid local destination")),31      Test.equals("html escaping exact", &Paths.escape("<&\"'>"), &"&lt;&amp;&quot;&#39;&gt;")32    ])33  let ran = Test.run(&checks)34  for failure in Test.failuresOf(&ran) { let _printed = Io.writeErrorLine(failure) }35  Test.report(&ran)36}37