Search Apps Documentation Source Content File Folder Download Copy Actions Download State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

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}