vole
Clone
Read only, no credentials:
https://rodent.software/git/vole.git
Write over SSH with a registered key:
git clone ssh://git@0.0.0.0:2222/vole.git
A free and open-source forge that lives in your Git repo.
|
a6b42433
Keenan Nemetz
8d ago
|
1 | package web |
| 2 | ||
| 3 | // A mention on the page has to mean what a mention means to CI. The scanner is | |
| 4 | // metadata.EachMention, the one the trigger server uses, and the renderer only | |
| 5 | // links names that belong to an account. These tests hold both halves: what is | |
| 6 | // linked, and what deliberately is not. | |
| 7 | ||
| 8 | import ( | |
| 9 | "strings" | |
| 10 | "testing" | |
| 11 | ) | |
| 12 | ||
| 13 | func TestMentionsBecomeProfileLinks(t *testing.T) { | |
| 14 | t.Parallel() | |
| 15 | s := newSite(t) | |
| 16 | html := string(s.web.renderMarkdown("demo", "hi @alice, take a look")) | |
| 17 | ||
|
ed03b3d1
Keenan Nemetz
4h ago
|
18 | if !strings.Contains(html, `href="/-/u/alice"`) || !strings.Contains(html, ">@alice</a>") { |
|
a6b42433
Keenan Nemetz
8d ago
|
19 | t.Fatalf("mention was not linked:\n%s", html) |
| 20 | } | |
| 21 | } | |
| 22 | ||
| 23 | func TestMentionLinksSkipWhatIsNotAnAddress(t *testing.T) { | |
| 24 | t.Parallel() | |
| 25 | s := newSite(t) | |
| 26 | cases := []struct { | |
| 27 | name string | |
| 28 | src string | |
| 29 | }{ | |
| 30 | {"email", "mail alice@example.com about it"}, | |
| 31 | {"url", "see https://example.test/@alice"}, | |
| 32 | {"inline code", "use `@alice` in a sample"}, | |
| 33 | {"fenced block", "```\n@alice\n```"}, | |
| 34 | {"escaped", `write \@alice literally`}, | |
| 35 | {"unknown name", "hi @nobody"}, | |
| 36 | {"path", "look in docs/@alice/readme"}, | |
| 37 | } | |
| 38 | for _, c := range cases { | |
| 39 | t.Run(c.name, func(t *testing.T) { | |
| 40 | html := string(s.web.renderMarkdown("demo", c.src)) | |
|
ed03b3d1
Keenan Nemetz
4h ago
|
41 | if strings.Contains(html, "/-/u/alice") || strings.Contains(html, "/-/u/nobody") { |
|
a6b42433
Keenan Nemetz
8d ago
|
42 | t.Fatalf("%s was linked:\n%s", c.name, html) |
| 43 | } | |
| 44 | }) | |
| 45 | } | |
| 46 | } | |
| 47 | ||
| 48 | // A mention inside an existing link's label must not become a nested link: the | |
| 49 | // browser would close the outer one and the markdown the author wrote would no | |
| 50 | // longer say what the page shows. | |
| 51 | func TestMentionInsideALinkIsLeftAlone(t *testing.T) { | |
| 52 | t.Parallel() | |
| 53 | s := newSite(t) | |
| 54 | html := string(s.web.renderMarkdown("demo", "[ask @alice](https://example.test/ask)")) | |
| 55 | ||
| 56 | if got := strings.Count(html, "<a "); got != 1 { | |
| 57 | t.Fatalf("link count = %d, want 1:\n%s", got, html) | |
| 58 | } | |
| 59 | if !strings.Contains(html, `href="https://example.test/ask"`) { | |
| 60 | t.Fatalf("the author's link was rewritten:\n%s", html) | |
| 61 | } | |
| 62 | } | |
| 63 | ||
| 64 | // A README is documentation, not somebody being addressed, so it is rendered | |
| 65 | // without profile links even though the same account exists. | |
| 66 | func TestDocumentationDoesNotLinkMentions(t *testing.T) { | |
| 67 | t.Parallel() | |
| 68 | s := newSite(t) | |
| 69 | html := string(s.web.renderTreeMarkdown(treeDoc{Repo: "demo"}, "the @alice flag turns it on")) | |
| 70 | ||
|
ed03b3d1
Keenan Nemetz
4h ago
|
71 | if strings.Contains(html, "/-/u/alice") { |
|
a6b42433
Keenan Nemetz
8d ago
|
72 | t.Fatalf("a README mention became a profile link:\n%s", html) |
| 73 | } | |
| 74 | } | |
| 75 | ||
| 76 | // Mentions at the edge of prose still count: after a line break and after | |
| 77 | // punctuation, which is how people actually write them. | |
| 78 | func TestMentionAtLineStartAndAfterPunctuation(t *testing.T) { | |
| 79 | t.Parallel() | |
| 80 | s := newSite(t) | |
| 81 | for _, src := range []string{ | |
| 82 | "first line\n@alice please look", | |
| 83 | "(@alice) please look", | |
| 84 | } { | |
| 85 | html := string(s.web.renderMarkdown("demo", src)) | |
|
ed03b3d1
Keenan Nemetz
4h ago
|
86 | if !strings.Contains(html, `href="/-/u/alice"`) { |
|
a6b42433
Keenan Nemetz
8d ago
|
87 | t.Fatalf("%q was not linked:\n%s", src, html) |
| 88 | } | |
| 89 | } | |
| 90 | } | |
| 91 | ||
| 92 | // The link survives sanitisation: if bluemonday dropped it, the page would show | |
| 93 | // plain text and the test above would still pass on the raw markdown. | |
| 94 | func TestMentionLinkSurvivesTheSanitizer(t *testing.T) { | |
| 95 | t.Parallel() | |
| 96 | s := newSite(t) | |
| 97 | html := string(s.web.renderMarkdown("demo", "@alice")) | |
|
ed03b3d1
Keenan Nemetz
4h ago
|
98 | if !strings.Contains(html, `href="/-/u/alice"`) { |
|
a6b42433
Keenan Nemetz
8d ago
|
99 | t.Fatalf("the sanitised mention is not a link:\n%s", html) |
| 100 | } | |
| 101 | } |