Kind Realm (renderable)
Name home
Namespace moul
Exported functions 7
Module gno.land/r/moul/home
gno 0.9 home_test.gno gno
⧉
1 package home 2 3 import ( 4 "strings" 5 "testing" 6 7 "gno.land/p/nt/avl/v0" 8 Append (cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, slug string, body string)
Delete (cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, slug string)
Get (slug string) string
Manifest () string
Render (path string) string
Revision () int
Set (cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, slug string, body string)
Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.
"gno.land/p/nt/testutils/v0"
9 "gno.land/p/nt/uassert/v0"
10 )
11
12 var 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.
16 func 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.
23 func seed(slug, body string ) {
24 rev++
25 slots.Set(slug, &slot{body: body, rev: rev, updated: 0 })
26 }
27
28 func 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
50 func 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
64 func 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
80 func 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
109 func 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
134 func 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
150 func 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
163 func 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
174 func 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
189 func TestRenderEmptyIndex(t *testing.T) {
190 reset()
191 uassert.True(t, strings.Contains(Render( "slots" ), "_no slots yet_" ))
192 }
193
vm/qrender output, sanitized (docs/render-security.md) and displayed in an empty-sandbox iframe — scripts, forms and popups cannot run. Links stay inert in-preview; right-click to open.