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

home_test.gno

6.63 Kb · 177 lines
  1package home
  2
  3import (
  4	"strings"
  5	"testing"
  6
  7	"gno.land/p/nt/avl/v0"
  8	"gno.land/p/nt/testutils/v0"
  9	"gno.land/p/nt/uassert/v0"
 10)
 11
 12var (
 13	alice   = testutils.TestAddress("alice")
 14	bob     = testutils.TestAddress("bob")
 15	mallory = testutils.TestAddress("mallory")
 16)
 17
 18func reset() {
 19	galleries = avl.NewTree()
 20	slots = avl.NewTree()
 21	rev = 0
 22	hearts = avl.NewTree()
 23	recent = nil
 24}
 25
 26func seed(slug, body string) {
 27	rev++
 28	slots.Set(slug, &slot{body: body, rev: rev})
 29}
 30
 31func TestDefaultPageRendersEverySection(t *testing.T) {
 32	// State as left by init: every default slot, no heart yet.
 33	page := Render("")
 34	for _, want := range []string{"data:image/svg+xml;base64,", "Founder, CEO & CTO", "## 今 Now", "## 組 Inside Memba", "BARRICADE", "256 merged pull requests", "Paris P2P Festival", "Contributing on Gno since | 2022", "## 源 Open source", "(https://www.youtube.com/watch?v=aG4M37FX4II)", "**0** hearts so far.", "gno.land/r/g1747t5m2f08plqjlrjk2q0qld7465hxz8gkx59c/home"} {
 35		uassert.True(t, strings.Contains(page, want), "missing: "+want)
 36	}
 37	for _, s := range defaultSlots {
 38		uassert.False(t, strings.Contains(page, ":"+s.slug+":"), "unfilled placeholder :"+s.slug+":")
 39	}
 40	for _, g := range defaultGalleries {
 41		uassert.False(t, strings.Contains(page, ":gallery."+g.name+":"), "unfilled gallery :gallery."+g.name+":")
 42	}
 43	uassert.False(t, strings.Contains(page, ":hero:"))
 44}
 45
 46func TestSetGetDelete(cur realm, t *testing.T) {
 47	reset()
 48	testing.SetRealm(testing.NewUserRealm(admin))
 49
 50	Set(cross(cur), "bio", "Building on gno.")
 51	uassert.Equal(t, "Building on gno.", Get("bio"))
 52	Append(cross(cur), "bio", " Still.")
 53	uassert.Equal(t, "Building on gno. Still.", Get("bio"))
 54	uassert.Equal(t, 2, Revision())
 55
 56	Delete(cross(cur), "bio")
 57	uassert.Equal(t, "", Get("bio"))
 58	uassert.AbortsWithMessage(t, cur, "no such slot: bio", func() {
 59		Delete(cross(cur), "bio")
 60	})
 61}
 62
 63func TestWritesAreAdminOnly(cur realm, t *testing.T) {
 64	reset()
 65	testing.SetRealm(testing.NewUserRealm(mallory))
 66	uassert.AbortsWithMessage(t, cur, "restricted to admin", func() { Set(cross(cur), "bio", "pwned") })
 67	uassert.AbortsWithMessage(t, cur, "restricted to admin", func() { Append(cross(cur), "bio", "pwned") })
 68	uassert.AbortsWithMessage(t, cur, "restricted to admin", func() { Delete(cross(cur), "bio") })
 69}
 70
 71func TestSlugRules(cur realm, t *testing.T) {
 72	reset()
 73	testing.SetRealm(testing.NewUserRealm(admin))
 74	uassert.AbortsContains(t, cur, "invalid slug", func() { Set(cross(cur), "Bad", "x") })
 75	uassert.AbortsContains(t, cur, "invalid slug", func() { Set(cross(cur), "a:b", "x") })
 76	uassert.AbortsContains(t, cur, "invalid slug", func() { Set(cross(cur), "", "x") })
 77	uassert.AbortsWithMessage(t, cur, "reserved slug: hearts", func() { Set(cross(cur), "hearts", "fake 9999") })
 78	uassert.AbortsContains(t, cur, "reserved slug: gallery.", func() { Set(cross(cur), "gallery.x", "fake") })
 79}
 80
 81func TestFillIsSinglePass(t *testing.T) {
 82	reset()
 83	seed("layout", "A :a: B :missing: C 10:30 :b:")
 84	seed("a", "[:b:]")
 85	seed("b", "bee")
 86	uassert.Equal(t, "A [:b:] B :missing: C 10:30 bee", Render(""))
 87}
 88
 89func TestFallbackLayout(t *testing.T) {
 90	reset()
 91	seed("bio", "hi")
 92	uassert.True(t, strings.HasPrefix(Render(""), "# zôÖma\n\nhi\n\n**0** hearts"))
 93}
 94
 95func TestHeartOncePerAddress(cur realm, t *testing.T) {
 96	reset()
 97	seed("layout", ":hearts:")
 98
 99	testing.SetRealm(testing.NewUserRealm(alice))
100	Heart(cross(cur))
101	uassert.Equal(t, 1, Hearts())
102	uassert.True(t, HasHeart(alice))
103	uassert.AbortsWithMessage(t, cur, "already sent: one <3 per address", func() { Heart(cross(cur)) })
104
105	testing.SetRealm(testing.NewUserRealm(bob))
106	Heart(cross(cur))
107	uassert.Equal(t, 2, Hearts())
108	uassert.Equal(t, bob, recent[0], "newest first")
109
110	page := Render("")
111	uassert.True(t, strings.Contains(page, "**2** hearts so far."))
112	uassert.True(t, strings.Contains(page, "/u/"+bob.String()))
113	uassert.True(t, strings.Contains(Render("hearts"), "/u/"+alice.String()))
114}
115
116func TestRecentIsBounded(cur realm, t *testing.T) {
117	reset()
118	for i := 0; i < maxRecent+3; i++ {
119		testing.SetRealm(testing.NewUserRealm(testutils.TestAddress("fan" + string(rune('a'+i)))))
120		Heart(cross(cur))
121	}
122	uassert.Equal(t, maxRecent+3, Hearts())
123	uassert.Equal(t, maxRecent, len(recent))
124}
125
126func TestOtherViews(t *testing.T) {
127	reset()
128	seed("bio", "hello")
129	uassert.True(t, strings.Contains(Render("slots"), "[bio]"))
130	uassert.True(t, strings.Contains(Render("slots/bio"), "hello"))
131	uassert.True(t, strings.Contains(Render("slots/nope"), "Not found"))
132	uassert.True(t, strings.Contains(Render("nope"), "Not found"))
133}
134
135func TestGallery(cur realm, t *testing.T) {
136	reset()
137	seed("layout", ":gallery.demo:")
138
139	testing.SetRealm(testing.NewUserRealm(mallory))
140	uassert.AbortsWithMessage(t, cur, "restricted to admin", func() {
141		SetGallery(cross(cur), "demo", "film | A | b | https://x.y")
142	})
143
144	testing.SetRealm(testing.NewUserRealm(admin))
145	uassert.AbortsContains(t, cur, "needs 4 or 5 fields", func() { SetGallery(cross(cur), "demo", "film | A | b") })
146	uassert.AbortsContains(t, cur, "must be https://", func() { SetGallery(cross(cur), "demo", "film | A | b | javascript:alert(1)") })
147	uassert.AbortsContains(t, cur, "markdown would break", func() { SetGallery(cross(cur), "demo", "film | A | b | https://x.y/a)b") })
148
149	SetGallery(cross(cur), "demo", "# comment\nfilm | One <&> | meta | https://a.b/1\nproduct | Two | m | /r/x\nevent | Three | m | https://a.b/3\nreport | Four | m | https://a.b/4")
150	page := Render("")
151	uassert.Equal(t, 2, strings.Count(page, "<gno-columns>"), "3 per row")
152	uassert.Equal(t, 4, strings.Count(page, "data:image/svg+xml;base64,"))
153	uassert.True(t, strings.Contains(page, "](https://a.b/1)"))
154	uassert.True(t, strings.Contains(page, "](/r/x)"))
155
156	// Titles are XML-escaped inside the poster.
157	svg := poster(card{kind: "film", title: "One <&>", meta: "m", url: "https://a.b"})
158	uassert.True(t, strings.Contains(svg, "One &lt;&amp;&gt;"))
159
160	// An optional fifth field becomes the link's hover text.
161	SetGallery(cross(cur), "demo", "memba | DAO Management | m | https://a.b/dao | Vote, execute, create.")
162	uassert.True(t, strings.Contains(Render(""), `](https://a.b/dao "Vote, execute, create.")`))
163	uassert.Equal(t, "MEMBA · PRODUCT", styleOf("memba").label, "every seeded kind has its own style")
164	uassert.AbortsContains(t, cur, "without quotes", func() {
165		SetGallery(cross(cur), "demo", "memba | A | m | https://a.b | say \"hi\"")
166	})
167
168	DeleteGallery(cross(cur), "demo")
169	uassert.Equal(t, ":gallery.demo:", Render(""), "a missing gallery stays visible")
170}
171
172func TestWrap(t *testing.T) {
173	uassert.Equal(t, 1, len(wrap("Short title", 24)))
174	lines := wrap("The Underground Sistine Chapel is a very long title indeed", 24)
175	uassert.Equal(t, 2, len(lines))
176	uassert.True(t, strings.HasSuffix(lines[1], "…"))
177}