tinyrelayfile
tinyrelay/tinyclient/markdown_test.go/

tinyclient/markdown_test.go raw
1package tinyclient
2
3import (
4 "net/url"
5 "strings"
6 "testing"
7)
8
9func TestMarkdownRendersCommonFormsAndEscapesTheRest(t *testing.T) {
10 got := string(renderMarkdown("# Title\n\nA `code` span with **bold** and *em* and [a link](https://example.com).\n\n```sh\ngo build <x>\n```\n\n- one\n- two\n\n1. first\n2. second\n\n<script>alert(1)</script> and [bad](javascript:alert(1))"))
11 for _, want := range []string{"<h1>Title</h1>", "<code>code</code>", "<strong>bold</strong>", "<em>em</em>", `<a href="https://example.com">a link</a>`, `<pre><code data-lang="sh">go build &lt;x&gt;</code></pre>`, "<ul><li>one</li><li>two</li></ul>", "<ol><li>first</li><li>second</li></ol>", "&lt;script&gt;alert(1)&lt;/script&gt;"} {
12 if !strings.Contains(got, want) {
13 t.Errorf("missing %q in %s", want, got)
14 }
15 }
16 if strings.Contains(got, "<script>") || strings.Contains(got, `href="javascript:`) {
17 t.Fatalf("unsafe markup leaked: %s", got)
18 }
19}
20
21func TestRepositoryMarkdownResolvesRelativeLinks(t *testing.T) {
22 query := url.Values{"owner": {"alice"}, "repo": {"notes"}, "ref": {"refs/heads/main"}}
23 got := string(renderRepositoryMarkdown("[guide](docs/guide.md) [up](../secret.md) [site](https://example.com)", query))
24 if !strings.Contains(got, `href="/repo?owner=alice&amp;path=docs%2Fguide.md&amp;ref=refs%2Fheads%2Fmain&amp;repo=notes&amp;view=file"`) {
25 t.Fatalf("relative link was not mapped to repository viewer: %s", got)
26 }
27 if !strings.Contains(got, `href="https://example.com"`) {
28 t.Fatalf("repository link handling changed unsafe or external links: %s", got)
29 }
30}
31
32func TestRepositoryMarkdownDecodesPathsAndPreservesFragments(t *testing.T) {
33 query := url.Values{"owner": {"alice"}, "repo": {"notes"}, "ref": {"refs/heads/main"}}
34 got := string(renderRepositoryMarkdown("[guide](docs/caf%C3%A9%20guide.md?download=1#L2)", query))
35 want := `href="/repo?download=1&amp;owner=alice&amp;path=docs%2Fcaf%C3%A9+guide.md&amp;ref=refs%2Fheads%2Fmain&amp;repo=notes&amp;view=file#L2"`
36 if !strings.Contains(got, want) {
37 t.Fatalf("encoded README link lost its resource or fragment: %s", got)
38 }
39}
40
41func TestChatMarkdownBreaksLinesAndAutolinksOutsideLinksAndCode(t *testing.T) {
42 got := string(renderChatMarkdown("It works: **[the page](https://012.run/wiki/agents)**.\nsee https://example.com/x, and nostr:npub1ttrypewl3au52wqux86r22yt506c077k3maj02a0jste97wrvd5sjfutc2\n\n- `code https://not.a.link`\n- [x](javascript:alert(1))\n\n```\nhttps://in.code\n```"))
43 for _, want := range []string{
44 `<strong><a href="https://012.run/wiki/agents">the page</a></strong>.<br>see <a href="https://example.com/x" rel="noopener">https://example.com/x</a>, and <a href="/open?target=nostr%3Anpub1ttrypewl3au52wqux86r22yt506c077k3maj02a0jste97wrvd5sjfutc2">nostr:npub1ttrypewl3au52wqux86r22yt506c077k3maj02a0jste97wrvd5sjfutc2</a></p>`,
45 "<li><code>code https://not.a.link</code></li>",
46 "<li>[x](javascript:alert(1))</li>",
47 "<pre><code>https://in.code</code></pre>",
48 } {
49 if !strings.Contains(got, want) {
50 t.Errorf("missing %q in %s", want, got)
51 }
52 }
53 if strings.Count(got, "<a ") != 3 {
54 t.Fatalf("expected three links, got %s", got)
55 }
56}
57
58func TestMarkdownRendersTablesWithAlignmentAndInlineMarkdown(t *testing.T) {
59 source := "| Name | Count | Notes |\n| :--- | ---: | :---: |\n| **Ada** | 3 | [docs](https://example.com) |\n| Grace | | `a | b` |"
60 got := string(renderMarkdown(source))
61 for _, want := range []string{
62 `<div data-markdown-table="" role="region" aria-label="Table" tabindex="0"><table>`,
63 `<thead><tr><th scope="col" data-align="left">Name</th><th scope="col" data-align="right">Count</th><th scope="col" data-align="center">Notes</th></tr></thead>`,
64 `<tbody><tr><td data-align="left"><strong>Ada</strong></td><td data-align="right">3</td><td data-align="center"><a href="https://example.com">docs</a></td></tr>`,
65 `<tr><td data-align="left">Grace</td><td data-align="right"></td><td data-align="center"><code>a | b</code></td></tr></tbody></table></div>`,
66 } {
67 if !strings.Contains(got, want) {
68 t.Errorf("missing %q in %s", want, got)
69 }
70 }
71}
72
73func TestMarkdownTableEscapesPipesAndLeavesMalformedInputAsText(t *testing.T) {
74 got := string(renderMarkdown("a \\| b\n---\n\n| one | two |\n| --- |\n| three | four | five |"))
75 if strings.Contains(got, `data-markdown-table`) {
76 t.Fatalf("malformed table was rendered: %s", got)
77 }
78 if !strings.Contains(got, `a \| b ---`) || !strings.Contains(got, `| one | two |`) {
79 t.Fatalf("malformed table was not preserved as text: %s", got)
80 }
81
82 got = string(renderMarkdown("a \\| b | c\n--- | ---\nvalue \\| kept | ok"))
83 if !strings.Contains(got, `<th scope="col">a | b</th>`) || !strings.Contains(got, `<td>value | kept</td>`) {
84 t.Fatalf("escaped pipe was split or escaped incorrectly: %s", got)
85 }
86}
87
88func TestChatMarkdownAutolinksTableText(t *testing.T) {
89 got := string(renderChatMarkdown("| Link |\n| --- |\n| https://example.com/path |"))
90 if !strings.Contains(got, `<td><a href="https://example.com/path" rel="noopener">https://example.com/path</a></td>`) {
91 t.Fatalf("table cell was not autolinked: %s", got)
92 }
93}
94
95func TestMarkdownTableStopsBeforeHeadingsAndFences(t *testing.T) {
96 got := string(renderMarkdown("| Name | Value |\n| --- | --- |\n| one | two |\n# | Heading |\n\n```sh | example\n| code |\n```"))
97 if strings.Contains(got, "<td># | Heading |</td>") || strings.Contains(got, "<td>```sh | example</td>") {
98 t.Fatalf("table consumed a following block: %s", got)
99 }
100 if !strings.Contains(got, "<h1>| Heading |</h1>") || !strings.Contains(got, "<pre><code data-lang=\"sh\">| code |</code></pre>") {
101 t.Fatalf("following heading or fence was not rendered separately: %s", got)
102 }
103}

About

ownerc01503e8035f
visibilitypublic
headd730679639bf

Maintainers

  • c01503e8035f owner
  • ba1b5beed5b5 agent hermes

Clone

  • https://012.run/npub1cq2s86qrtadf36eqq3epm38wmhdynrrcwxf84eldk3f94dkv7ttsrulrz5/tinyrelay.git

Refs