links_test.gno
4.25 Kb · 118 lines
1package wiki
2
3import (
4 "testing"
5
6 "gno.land/p/nt/markdown/sanitize/v0"
7 "gno.land/p/nt/uassert/v0"
8)
9
10func TestScanLinks(t *testing.T) {
11 cases := []struct {
12 name string
13 in string
14 targets []string
15 labels []string
16 explicits []bool
17 }{
18 {"none", "plain text", nil, nil, nil},
19 {"one", "see [[Gno land]] here", []string{"Gno land"}, []string{""}, []bool{false}},
20 {"labelled", "[[Gno land|the chain]]", []string{"Gno land"}, []string{"the chain"}, []bool{false}},
21 {"two", "[[A]] and [[B]]", []string{"A", "B"}, []string{"", ""}, []bool{false, false}},
22 {"category", "[[Category:Chains]]", []string{"Category:Chains"}, []string{""}, []bool{false}},
23 {"explicit category", "[[:Category:Chains]]", []string{"Category:Chains"}, []string{""}, []bool{true}},
24 {"whitespace is trimmed", "[[ A | b ]]", []string{"A"}, []string{"b"}, []bool{false}},
25 {"unclosed is not a link", "[[A", nil, nil, nil},
26 {"empty is not a link", "[[]]", nil, nil, nil},
27 {"newline inside is not a link", "[[A\nB]]", nil, nil, nil},
28 {"nested opener wins", "[[a [[b]]", []string{"b"}, []string{""}, []bool{false}},
29 }
30 for _, tc := range cases {
31 got := ScanLinks(tc.in, "[[", "]]")
32 if !uassert.Equal(t, len(tc.targets), len(got), tc.name) {
33 continue
34 }
35 for i, l := range got {
36 uassert.Equal(t, tc.targets[i], l.Target, tc.name)
37 uassert.Equal(t, tc.labels[i], l.Label, tc.name)
38 uassert.Equal(t, tc.explicits[i], l.Explicit, tc.name)
39 }
40 }
41}
42
43func TestScanLinksOffsets(t *testing.T) {
44 in := "see [[A]] end"
45 got := ScanLinks(in, "[[", "]]")
46 uassert.Equal(t, 1, len(got))
47 uassert.Equal(t, "[[A]]", in[got[0].Start:got[0].End])
48}
49
50// TestScanLinksAfterSanitize is the reason ScanLinks takes its delimiters as
51// parameters: the sanitizer escapes every "[", so the rendering pass has to
52// look for a different byte sequence than the indexing pass.
53func TestScanLinksAfterSanitize(t *testing.T) {
54 escaped := sanitize.BlockRich("see [[Gno land|the chain]] here\n")
55 uassert.Equal(t, 0, len(ScanLinks(escaped, "[[", "]]")),
56 "the raw delimiters must find nothing in sanitized text")
57 got := ScanLinks(escaped, `\[\[`, `\]\]`)
58 uassert.Equal(t, 1, len(got))
59 uassert.Equal(t, "Gno land", got[0].Target)
60 uassert.Equal(t, "the chain", got[0].Label)
61}
62
63func TestRedirectTarget(t *testing.T) {
64 cases := []struct{ in, want string }{
65 {"#REDIRECT [[Gno land]]\n", "Gno land"},
66 {"#redirect [[gno_land]]", "Gno land"},
67 {" #REDIRECT [[User:Gno land]] \nrest", "User:Gno land"},
68 {"not a redirect [[Gno land]]", ""},
69 {"#REDIRECT no link", ""},
70 {"#REDIRECT [[bad|title]]", "Bad"},
71 {"text\n#REDIRECT [[Gno land]]", ""},
72 {"", ""},
73 }
74 for _, tc := range cases {
75 uassert.Equal(t, tc.want, redirectTarget(tc.in), tc.in)
76 }
77}
78
79func TestRewriteLinks(t *testing.T) {
80 c := Ctx{
81 Base: "/r/moul/x/wiki/v0",
82 Exists: func(tt Title) bool { return tt.Name == "Gno land" },
83 }
84
85 body := sanitize.BlockRich("See [[Gno land]], [[Missing page]] and [[Gno land|the chain]].\n" +
86 "[[Category:Chains]]\n")
87 got := RewriteLinks(c, body)
88
89 uassert.True(t, contains(got, "[Gno land](/r/moul/x/wiki/v0:Gno_land)"), "existing page links plainly")
90 uassert.True(t, contains(got, "[Missing page](/r/moul/x/wiki/v0:Missing_page) ⁺"), "a redlink is marked")
91 uassert.True(t, contains(got, "[the chain](/r/moul/x/wiki/v0:Gno_land)"), "labels are honored")
92 uassert.False(t, contains(got, "Category:Chains"), "category declarations leave the flow")
93}
94
95func TestRewriteLinksEscapesURLs(t *testing.T) {
96 c := Ctx{Base: "/r/moul/x/wiki/v0"}
97 got := RewriteLinks(c, sanitize.BlockRich("[[Mercury (planet)]]\n"))
98 // An unescaped ")" would terminate the markdown destination early and
99 // leave "planet))" as visible text.
100 uassert.True(t, contains(got, "(/r/moul/x/wiki/v0:Mercury_%28planet%29)"), got)
101}
102
103func TestRewriteLinksLeavesNonTitlesAlone(t *testing.T) {
104 c := Ctx{Base: "/r/moul/x/wiki/v0"}
105 // "[[ ]]" has no usable target, and "[[a/b]]" is not a legal title: both
106 // must render as the literal text the author typed, never as a link.
107 got := RewriteLinks(c, sanitize.BlockRich("[[a/b]]\n"))
108 uassert.True(t, contains(got, `\[\[a/b\]\]`), got)
109}
110
111func contains(haystack, needle string) bool {
112 for i := 0; i+len(needle) <= len(haystack); i++ {
113 if haystack[i:i+len(needle)] == needle {
114 return true
115 }
116 }
117 return false
118}