Sign in

Search issue titles and bodies, change requests and comments. Private repositories you cannot read are not included.

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.

Code

392 commit(s) on main

Merge change request 01M70WES5ZZDJ6RP226WB11BBZ: Let people rename and remove their own passkeys keenan · 1h ago 4b8c9e1d
history blame raw 3.2 KiB
1package 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
8import (
9 "strings"
10 "testing"
11)
12
13func TestMentionsBecomeProfileLinks(t *testing.T) {
14 t.Parallel()
15 s := newSite(t)
16 html := string(s.web.renderMarkdown("demo", "hi @alice, take a look"))
17
18 if !strings.Contains(html, `href="/-/u/alice"`) || !strings.Contains(html, ">@alice</a>") {
19 t.Fatalf("mention was not linked:\n%s", html)
20 }
21}
22
23func 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))
41 if strings.Contains(html, "/-/u/alice") || strings.Contains(html, "/-/u/nobody") {
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.
51func 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.
66func 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
71 if strings.Contains(html, "/-/u/alice") {
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.
78func 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))
86 if !strings.Contains(html, `href="/-/u/alice"`) {
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.
94func TestMentionLinkSurvivesTheSanitizer(t *testing.T) {
95 t.Parallel()
96 s := newSite(t)
97 html := string(s.web.renderMarkdown("demo", "@alice"))
98 if !strings.Contains(html, `href="/-/u/alice"`) {
99 t.Fatalf("the sanitised mention is not a link:\n%s", html)
100 }
101}
102