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

Community realm. Read the code first. Community realm, deployed by its author. Read the code before you interact or send coins.

links_test.gno

4.33 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/nym-moultest123/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/nym-moultest123/x/wiki/v0:Gno_land)"), "existing page links plainly")
 90	uassert.True(t, contains(got, "[Missing page](/r/nym-moultest123/x/wiki/v0:Missing_page) ⁺"), "a redlink is marked")
 91	uassert.True(t, contains(got, "[the chain](/r/nym-moultest123/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/nym-moultest123/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/nym-moultest123/x/wiki/v0:Mercury_%28planet%29)"), got)
101}
102
103func TestRewriteLinksLeavesNonTitlesAlone(t *testing.T) {
104	c := Ctx{Base: "/r/nym-moultest123/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}