Artifact 48d4e2978dc6044579fe86b2c9d849f57e20e8fc980df4630ac734fcf612d5d7:
- File
internal/markup/fossilwiki_test.go
— part of check-in
[45c96a506b]
at
2026-08-16 12:45:03
on branch trunk
— markup: render Fossil wiki format; fix mimetype dispatch; GFM completeness
An absent N card means text/x-fossil-wiki, not markdown — fossil's wiki_render_by_mimetype is explicit — but quarry rendered those as markdown, mangling 217 of libfossil's 443 wiki artifacts ([target|label] links came out as literal text). Adds a Fossil wiki renderer (the seven rules from fossil's own wiki.wiki: paragraphs, single-level * and # lists, indented paragraphs, [target|label] links through the existing Resolver, verbatim/nowiki, HTML pass-through gated by the sanitizer), dispatches on mimetype exactly as fossil does, and stores forum posts' N card so they dispatch too. Fossil site-relative targets quarry cannot serve render their label as text rather than showing wiki source.
Also GFM completeness: footnotes and auto heading IDs, with the sanitizer policy widened to admit what goldmark actually emits (a footnotes div, not section — caught by test). (user: dmestas, size: 2954) [annotate] [blame] [check-ins using]
package markup import ( "strings" "testing" ) type fakeRes struct{} func (fakeRes) ResolveHash(p string) string { return "/r/x/checkin/" + p } func (fakeRes) ResolveWiki(n string) string { if n == "Missing" { return "" } return "/r/x/wiki/" + n } func TestFossilWikiParagraphsAndLists(t *testing.T) { src := `First paragraph line one. line two of the same paragraph. Second paragraph. * bullet one * bullet two # first enumerated # second enumerated ` got := string(mustFW(t, src, nil)) if strings.Count(got, "<p>") != 2 { t.Fatalf("want 2 paragraphs:\n%s", got) } if !strings.Contains(got, "<ul>") || strings.Count(got, "<li>") != 4 { t.Fatalf("lists wrong:\n%s", got) } if !strings.Contains(got, "<ol>") { t.Fatalf("enumeration list missing:\n%s", got) } } // The construct that motivated all of this: [target|label] links, which // markdown renders as literal text. func TestFossilWikiLinks(t *testing.T) { got := string(mustFW(t, "See [WikiPage|the page] and [https://example.com|a site].", fakeRes{})) if !strings.Contains(got, `<a href="/r/x/wiki/WikiPage" rel="nofollow">the page</a>`) && !strings.Contains(got, `href="/r/x/wiki/WikiPage"`) { t.Fatalf("wiki link not resolved:\n%s", got) } if !strings.Contains(got, `href="https://example.com"`) || !strings.Contains(got, ">a site<") { t.Fatalf("external link not rendered:\n%s", got) } // Bare [target] uses the target as the label. got = string(mustFW(t, "Go to [WikiPage].", fakeRes{})) if !strings.Contains(got, ">WikiPage<") { t.Fatalf("bare link label:\n%s", got) } // Unresolvable targets stay literal rather than becoming dead links. got = string(mustFW(t, "See [Missing|nope].", fakeRes{})) if strings.Contains(got, "<a ") { t.Fatalf("unresolvable target linked:\n%s", got) } } func TestFossilWikiVerbatimAndHTML(t *testing.T) { got := string(mustFW(t, "<verbatim>[not a link] *not a bullet*</verbatim>", nil)) if !strings.Contains(got, "<pre>") || !strings.Contains(got, "[not a link]") { t.Fatalf("verbatim not preserved:\n%s", got) } if strings.Contains(got, "<a ") { t.Fatal("verbatim content was link-processed") } // Ordinary HTML passes through (rule 6) but still meets the sanitizer. got = string(mustFW(t, "Text with <b>bold</b> and <script>alert(1)</script>.", nil)) if !strings.Contains(got, "<b>bold</b>") { t.Fatalf("inline HTML dropped:\n%s", got) } if strings.Contains(got, "<script") || strings.Contains(got, "alert(1)") { t.Fatalf("sanitizer gate leaked script:\n%s", got) } } func TestFossilWikiIndentedParagraph(t *testing.T) { got := string(mustFW(t, "Normal paragraph.\n\n indented paragraph here\n", nil)) if !strings.Contains(got, "<blockquote>") { t.Fatalf("indented paragraph not rendered:\n%s", got) } } func mustFW(t *testing.T, src string, r Resolver) []byte { t.Helper() out, err := RenderFossilWiki([]byte(src), r) if err != nil { t.Fatal(err) } return out }