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

5.97 Kb · 192 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 stranger = testutils.TestAddress("mallory")
 13
 14// reset clears realm state. Realm globals live for the whole test binary, so
 15// every test that reads Render or Manifest starts from a known tree.
 16func reset() {
 17	slots = avl.NewTree()
 18	rev = 0
 19}
 20
 21// seed writes a slot without going through the admin check, for tests (and the
 22// Example) that only care about the rendering side.
 23func seed(slug, body string) {
 24	rev++
 25	slots.Set(slug, &slot{body: body, rev: rev, updated: 0})
 26}
 27
 28func TestSetGetDelete(cur realm, t *testing.T) {
 29	reset()
 30	testing.SetRealm(testing.NewUserRealm(admin))
 31
 32	Set(cross(cur), "bio", "Building on gno.")
 33	uassert.Equal(t, "Building on gno.", Get("bio"))
 34	uassert.Equal(t, 1, Revision())
 35
 36	// Set is idempotent in shape: a second write replaces, never appends.
 37	Set(cross(cur), "bio", "Still building.")
 38	uassert.Equal(t, "Still building.", Get("bio"))
 39	uassert.Equal(t, 2, Revision())
 40
 41	Delete(cross(cur), "bio")
 42	uassert.Equal(t, "", Get("bio"), "a deleted slot reads as empty")
 43	uassert.Equal(t, 3, Revision())
 44
 45	uassert.AbortsWithMessage(t, cur, "no such slot: bio", func() {
 46		Delete(cross(cur), "bio")
 47	})
 48}
 49
 50func TestAppendChunks(cur realm, t *testing.T) {
 51	reset()
 52	testing.SetRealm(testing.NewUserRealm(admin))
 53
 54	// The escape hatch for a body too large for one transaction.
 55	Set(cross(cur), "long", "part one. ")
 56	Append(cross(cur), "long", "part two.")
 57	uassert.Equal(t, "part one. part two.", Get("long"))
 58
 59	// Append creates the slot when it is absent.
 60	Append(cross(cur), "fresh", "hello")
 61	uassert.Equal(t, "hello", Get("fresh"))
 62}
 63
 64func TestWritesAreAdminOnly(cur realm, t *testing.T) {
 65	reset()
 66	testing.SetRealm(testing.NewUserRealm(stranger))
 67
 68	uassert.AbortsWithMessage(t, cur, "restricted to admin", func() {
 69		Set(cross(cur), "bio", "pwned")
 70	})
 71	uassert.AbortsWithMessage(t, cur, "restricted to admin", func() {
 72		Append(cross(cur), "bio", "pwned")
 73	})
 74	uassert.AbortsWithMessage(t, cur, "restricted to admin", func() {
 75		Delete(cross(cur), "bio")
 76	})
 77	uassert.Equal(t, "", Get("bio"))
 78}
 79
 80func TestSlugRules(cur realm, t *testing.T) {
 81	reset()
 82	testing.SetRealm(testing.NewUserRealm(admin))
 83
 84	uassert.True(t, validSlug("bio"))
 85	uassert.True(t, validSlug("now.2026-09"))
 86	uassert.True(t, validSlug("latest_packages"))
 87	uassert.False(t, validSlug(""), "empty")
 88	uassert.False(t, validSlug("Bio"), "uppercase: a slot must have one name")
 89	uassert.False(t, validSlug("a b"), "space")
 90	uassert.False(t, validSlug("a:b"), "a colon would break out of the :slug: placeholder")
 91	uassert.False(t, validSlug(strings.Repeat("a", maxSlugLen+1)), "too long")
 92
 93	uassert.AbortsContains(t, cur, "invalid slug", func() {
 94		Set(cross(cur), "Bad Slug", "x")
 95	})
 96
 97	// A reserved name would shadow a value computed from chain state.
 98	for _, name := range reservedSlugs {
 99		uassert.AbortsContains(t, cur, "reserved slug", func() {
100			Set(cross(cur), name, "x")
101		})
102	}
103
104	// "layout" is special but NOT reserved: it is a real, writable slot.
105	Set(cross(cur), layoutSlug, "# hi")
106	uassert.Equal(t, "# hi", Get(layoutSlug))
107}
108
109func TestManifestIsTheDiffSurface(cur realm, t *testing.T) {
110	reset()
111	testing.SetRealm(testing.NewUserRealm(admin))
112
113	Set(cross(cur), "bio", "hello")
114	Set(cross(cur), "alpha", "")
115
116	// Sorted by slug (avl order), one line each, four tab-separated fields.
117	lines := strings.Split(strings.TrimSuffix(Manifest(), "\n"), "\n")
118	uassert.Equal(t, 2, len(lines))
119
120	alpha := strings.Split(lines[0], "\t")
121	uassert.Equal(t, 4, len(alpha))
122	uassert.Equal(t, "alpha", alpha[0])
123	uassert.Equal(t, "0", alpha[2], "byte length of an empty body")
124	// sha256(""), pinning that the hash is over the body, not over a wrapper.
125	uassert.Equal(t, "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", alpha[3])
126
127	bio := strings.Split(lines[1], "\t")
128	uassert.Equal(t, "bio", bio[0])
129	uassert.Equal(t, "5", bio[2])
130	// sha256("hello")
131	uassert.Equal(t, "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824", bio[3])
132}
133
134func TestRenderFillsTheLayoutSlot(cur realm, t *testing.T) {
135	reset()
136	testing.SetRealm(testing.NewUserRealm(admin))
137
138	Set(cross(cur), layoutSlug, "# :owner:\n\n:bio:\n\n:missing:\n")
139	Set(cross(cur), "bio", "Building on gno.")
140
141	out := Render("")
142	uassert.True(t, strings.Contains(out, "# "+admin.String()),
143		"a computed placeholder is filled from chain state")
144	uassert.True(t, strings.Contains(out, "Building on gno."),
145		"a slot placeholder is filled from the tree")
146	uassert.True(t, strings.Contains(out, ":missing:"),
147		"an unmatched placeholder survives verbatim, so a gap is visible")
148}
149
150func TestRenderDoesNotRecurse(cur realm, t *testing.T) {
151	reset()
152	testing.SetRealm(testing.NewUserRealm(admin))
153
154	// A slot body that looks like a placeholder must not expand: substitution
155	// is one pass, which is what makes cycles impossible.
156	Set(cross(cur), layoutSlug, ":a:")
157	Set(cross(cur), "a", ":b:")
158	Set(cross(cur), "b", "should not appear")
159
160	uassert.Equal(t, ":b:", Render(""))
161}
162
163func TestRenderUnsetLayoutFallsBack(t *testing.T) {
164	reset()
165	out := Render("")
166	uassert.True(t, strings.Contains(out, "No layout slot yet"))
167	uassert.False(t, strings.Contains(out, ":slots:"),
168		"the default layout must not leave its own placeholders unresolved")
169	uassert.False(t, strings.Contains(out, ":rev:"))
170	uassert.False(t, strings.Contains(out, ":height:"))
171	uassert.False(t, strings.Contains(out, ":chainid:"))
172}
173
174func TestRenderSubPaths(t *testing.T) {
175	reset()
176	seed("bio", "Building on gno.")
177
178	idx := Render("slots")
179	uassert.True(t, strings.Contains(idx, "| [bio](/r/moul/home:slots/bio) |"))
180
181	raw := Render("slots/bio")
182	uassert.True(t, strings.Contains(raw, "Building on gno."))
183	uassert.True(t, strings.Contains(raw, "16 bytes"))
184
185	uassert.True(t, strings.Contains(Render("slots/nope"), "No slot named"))
186	uassert.True(t, strings.Contains(Render("whatever"), "No such path"))
187}
188
189func TestRenderEmptyIndex(t *testing.T) {
190	reset()
191	uassert.True(t, strings.Contains(Render("slots"), "_no slots yet_"))
192}