Kind Realm (renderable)
Name definition
Namespace akkadia / beta
Exported functions 7
Module gno.land/r/akkadia/beta/definition
gno 0.9 gno
definition_test.gno gno
⧉
1 package definition 2 3 import ( 4 "chain" 5 "net/url" 6 "strconv" 7 "strings" 8 DeleteAll (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})
Get (key string) []map[string]string
GetField (key string, fieldKey string) map[string]string
GetKeyCount () int
ListKeys (page int, count int) []string
Render (path string) string
SetDefinitions (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}, keys string, values string)
Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.
"testing"
9
10 "gno.land/p/nt/bptree/v0"
11 "gno.land/p/nt/testutils/v0"
12 "gno.land/p/nt/uassert/v0"
13 "gno.land/r/akkadia/beta/admin"
14 )
15
16 var definitionAdmin = testutils.TestAddress( "definitionAdmin" )
17
18 // Call with cross(cur); each test gets fresh state and a direct admin caller.
19 func setupDefinition(cur realm, t *testing.T) {
20 t.Helper()
21 definitions = bptree.NewBPTree32()
22 testing.SetOriginSend(chain.Coins{})
23 if admin.GetAdmin() != definitionAdmin {
24 testing.SetOriginCaller(admin.GetAdmin())
25 testing.SetRealm(testing.NewUserRealm(admin.GetAdmin()))
26 admin.TransferAdmin(cross(cur), definitionAdmin)
27 testing.SetOriginCaller(definitionAdmin)
28 testing.SetRealm(testing.NewUserRealm(definitionAdmin))
29 admin.AcceptAdmin(cross(cur))
30 }
31 testing.SetOriginCaller(definitionAdmin)
32 testing.SetRealm(testing.NewUserRealm(definitionAdmin))
33 }
34
35 func TestStorageMergeAndCopies(cur realm, t *testing.T) {
36 setupDefinition(cross(cur), t)
37 testing.SetRealm(testing.NewUserRealm(definitionAdmin))
38 uassert.Equal(t, 0 , GetKeyCount())
39 fields := []Field{{ "z" , "" }, { "name" , "돌" }, { "description" , " 줄\n바꿈 ` <tag> " }}
40 setTestDefinition(cross(cur), "1101000" , fields)
41 fields[ 1 ].Value = "changed"
42 setTestDefinition(cross(cur), "1101000" , []Field{{ "name" , "Stone" }, { "a" , "added" }})
43 got := Get( "1101000" )
44 assertFieldList(t, []Field{{ "a" , "added" }, { "description" , " 줄\n바꿈 ` <tag> " }, { "name" , "Stone" }, { "z" , "" }}, got)
45 got[ 0 ][ "value" ] = "mutated return"
46 field := GetField( "1101000" , "a" )
47 field[ "value" ] = "mutated field return"
48 value, found := GetField( "1101000" , "a" )[ "value" ]
49 uassert.True(t, found)
50 uassert.Equal(t, "added" , value)
51 value, found = GetField( "1101000" , "z" )[ "value" ]
52 uassert.True(t, found)
53 uassert.Equal(t, "" , value)
54 _, found = GetField( "1101000" , "missing" )[ "value" ]
55 uassert.False(t, found)
56 uassert.Equal(t, len(Get( "missing" )), 0 )
57 uassert.Equal(t, 1 , GetKeyCount())
58 setTestDefinition(cross(cur), " A : 한글 " , []Field{{ " 이름 " , "" }})
59 assertStrings(t, [] string { "1101000" , " A : 한글 " }, ListKeys( 1 , 50 ))
60 }
61
62 func TestDeleteAllAndReload(cur realm, t *testing.T) {
63 setupDefinition(cross(cur), t)
64 testing.SetRealm(testing.NewUserRealm(definitionAdmin))
65 batch := []testEntry{}
66 for i := 100 ; i < 200 ; i++ {
67 batch = append(batch, testEntry{strconv.Itoa(i), []Field{{ "old" , "discard" }}})
68 }
69 setTestDefinitions(cross(cur), batch)
70 uassert.Equal(t, 100 , GetKeyCount())
71 DeleteAll(cross(cur))
72 uassert.Equal(t, 0 , GetKeyCount())
73 assertStrings(t, [] string {}, ListKeys( 1 , 50 ))
74 for _, entry := range batch {
75 uassert.Equal(t, len(Get(entry.Key)), 0 )
76 _, found := GetField(entry.Key, "old" )[ "value" ]
77 uassert.False(t, found)
78 }
79 uassert.True(t, strings.Contains(Render( "" ), "No entries" ))
80 DeleteAll(cross(cur))
81 setTestDefinition(cross(cur), "100" , []Field{{ "new" , "replacement" }})
82 fields := Get( "100" )
83 assertFieldList(t, []Field{{ "new" , "replacement" }}, fields)
84 uassert.Equal(t, 1 , GetKeyCount())
85 }
86
87 func TestBatchIdempotenceAndAtomicValidation(cur realm, t *testing.T) {
88 setupDefinition(cross(cur), t)
89 testing.SetRealm(testing.NewUserRealm(definitionAdmin))
90 entries := []testEntry{{ "a" , []Field{{ "name" , "old" }}}, { "b" , []Field{{ "name" , "other" }}}}
91 setTestDefinitions(cross(cur), entries)
92 setTestDefinitions(cross(cur), entries)
93 uassert.Equal(t, 2 , GetKeyCount())
94 for _, tc := range [] struct {
95 name string
96 entry testEntry
97 errMsg string
98 }{
99 { "duplicate entry" , testEntry{ "a" , []Field{{ "n" , "v" }}}, "duplicate entry" },
100 { "duplicate field" , testEntry{ "c" , []Field{{ "n" , "v" }, { "n" , "v" }}}, "duplicate field key" },
101 { "invalid key" , testEntry{ "" , []Field{{ "n" , "v" }}}, "empty entry token" },
102 { "invalid field" , testEntry{ "c" , []Field{{ "\n" , "v" }}}, "field key is required" },
103 { "empty fields" , testEntry{ "c" , nil }, "empty entry token" },
104 } {
105 t.Run(tc.name, func (t *testing.T) {
106 testing.SetRealm(testing.NewUserRealm(definitionAdmin))
107 batch := []testEntry{{ "a" , []Field{{ "name" , "new" }}}, tc.entry}
108 uassert.AbortsWithMessage(t, cur, tc.errMsg, func () { setTestDefinitions(cross(cur), batch) })
109 value, _ := GetField( "a" , "name" )[ "value" ]
110 uassert.Equal(t, "old" , value)
111 uassert.Equal(t, 2 , GetKeyCount())
112 })
113 }
114 }
115
116 func TestLimitsAndMergedRecord(cur realm, t *testing.T) {
117 setupDefinition(cross(cur), t)
118 testing.SetRealm(testing.NewUserRealm(definitionAdmin))
119 full := []Field{}
120 for i := 0 ; i < 32 ; i++ {
121 full = append(full, Field{strconv.Itoa(i), "v" })
122 }
123 setTestDefinition(cross(cur), "full" , full)
124 uassert.AbortsWithMessage(t, cur, "field count must be between 1 and 32" , func () {
125 setTestDefinition(cross(cur), "full" , []Field{{ "extra" , "v" }})
126 })
127 setTestDefinition(cross(cur), "bytes" , []Field{{ "a" , strings.Repeat( "x" , 16383 )}})
128 uassert.AbortsWithMessage(t, cur, "entry bytes exceeds 16384" , func () {
129 setTestDefinition(cross(cur), "bytes" , []Field{{ "b" , "" }})
130 })
131 setTestDefinition(cross(cur), "bytes" , []Field{{ "a" , "small" }, { "b" , "" }})
132 for _, tc := range [] struct { key, errMsg string }{
133 { "" , "keys and values count mismatch" }, { " \t" , "key is required" }, { "x\n" , "invalid key" },
134 { string ([] byte { 255 }), "invalid key" }, {strings.Repeat( "가" , 43 ), "key bytes exceeds 128" },
135 } {
136 uassert.AbortsWithMessage(t, cur, tc.errMsg, func () { setTestDefinition(cross(cur), tc.key, []Field{{ "n" , "v" }}) })
137 }
138 setTestDefinition(cross(cur), strings.Repeat( "k" , 128 ), []Field{{strings.Repeat( "f" , 128 ), "" }})
139 uassert.AbortsWithMessage(t, cur, "field key bytes exceeds 128" , func () { setTestDefinition(cross(cur), "x" , []Field{{strings.Repeat( "f" , 129 ), "" }}) })
140 uassert.AbortsWithMessage(t, cur, "invalid field value" , func () { setTestDefinition(cross(cur), "x" , []Field{{ "n" , string ([] byte { 255 })}}) })
141 uassert.AbortsWithMessage(t, cur, "batch count must be between 1 and 100" , func () { setTestDefinitions(cross(cur), nil ) })
142 uassert.AbortsWithMessage(t, cur, "batch count must be between 1 and 100" , func () { SetDefinitions(cross(cur), strings.Repeat( "x," , 100 )+ "x" , strings.Repeat( "n=v," , 100 )+ "n=v" ) })
143 total := GetKeyCount()
144 batch := []testEntry{}
145 for i := 0 ; i < 5 ; i++ {
146 batch = append(batch, testEntry{strconv.Itoa(i), []Field{{ "a" , strings.Repeat( "x" , 16383 )}}})
147 }
148 uassert.AbortsWithMessage(t, cur, "batch bytes exceeds 65536" , func () { setTestDefinitions(cross(cur), batch) })
149 uassert.Equal(t, total, GetKeyCount())
150 }
151
152 func TestPagination(cur realm, t *testing.T) {
153 setupDefinition(cross(cur), t)
154 testing.SetRealm(testing.NewUserRealm(definitionAdmin))
155 assertStrings(t, [] string {}, ListKeys( 1 , 50 ))
156 batch := []testEntry{}
157 for i := 99 ; i >= 0 ; i-- {
158 batch = append(batch, testEntry{strconv.Itoa(i + 100 ), []Field{{ "n" , "v" }}})
159 }
160 setTestDefinitions(cross(cur), batch)
161 uassert.Equal(t, 100 , GetKeyCount())
162 assertStrings(t, [] string { "100" , "101" }, ListKeys( 1 , 2 ))
163 assertStrings(t, [] string { "198" , "199" }, ListKeys( 50 , 2 ))
164 assertStrings(t, [] string {}, ListKeys( 51 , 2 ))
165 assertStrings(t, [] string {}, ListKeys( int ( 9223372036854775807 ), 50 ))
166 uassert.PanicsWithMessage(t, cur, "page must be positive" , func () { ListKeys( 0 , 1 ) })
167 uassert.PanicsWithMessage(t, cur, "count must be between 1 and 50" , func () { ListKeys( 1 , 51 ) })
168 keys := ListKeys( 1 , 1 )
169 keys[ 0 ] = "changed"
170 assertStrings(t, [] string { "100" }, ListKeys( 1 , 1 ))
171 }
172
173 func TestWriteAuthorityAndPayment(cur realm, t *testing.T) {
174 setupDefinition(cross(cur), t)
175 testing.SetRealm(testing.NewUserRealm(definitionAdmin))
176 setTestDefinition(cross(cur), "kept" , []Field{{ "name" , "preserved" }})
177 operator := testutils.TestAddress( "definitionOperator" )
178 admin.SetOperator(cross(cur), operator)
179 for _, caller := range []address{testutils.TestAddress( "definitionUser" ), operator} {
180 testing.SetOriginCaller(caller)
181 testing.SetRealm(testing.NewUserRealm(caller))
182 uassert.AbortsWithMessage(t, cur, "admin access required" , func () { DeleteAll(cross(cur)) })
183 uassert.AbortsWithMessage(t, cur, "admin access required" , func () { SetDefinitions(cross(cur), "x" , "n=v" ) })
184 }
185 testing.SetOriginCaller(definitionAdmin)
186 testing.SetRealm(testing.NewCodeRealm( "gno.land/r/example/definition_relay" ))
187 uassert.AbortsWithMessage(t, cur, "admin access required" , func () { DeleteAll(cross(cur)) })
188 uassert.AbortsWithMessage(t, cur, "admin access required" , func () { SetDefinitions(cross(cur), "x" , "n=v" ) })
189 testing.SetRealm(testing.NewUserRealm(definitionAdmin))
190 testing.SetOriginSend(chain.Coins{{ "ugnot" , 1 }})
191 uassert.AbortsWithMessage(t, cur, "attached coins not allowed" , func () { DeleteAll(cross(cur)) })
192 uassert.AbortsWithMessage(t, cur, "attached coins not allowed" , func () { SetDefinitions(cross(cur), "x" , "n=v" ) })
193 testing.SetOriginSend(chain.Coins{})
194 uassert.Equal(t, 1 , GetKeyCount())
195 value, found := GetField( "kept" , "name" )[ "value" ]
196 uassert.True(t, found)
197 uassert.Equal(t, "preserved" , value)
198 stale := captureDefinitionRealm(cross(cur))
199 uassert.PanicsWithMessage(t, cur, "spoofed realm" , func () { assertCanWrite( 0 , stale) })
200 }
201
202 func assertStrings(t *testing.T, expected, actual [] string ) {
203 t.Helper()
204 if !uassert.Equal(t, len(expected), len(actual)) {
205 return
206 }
207 for i := range expected {
208 uassert.Equal(t, expected[i], actual[i])
209 }
210 }
211
212 func assertFieldList(t *testing.T, expected []Field, actual [] map [ string ] string ) {
213 t.Helper()
214 if !uassert.Equal(t, len(expected), len(actual)) {
215 return
216 }
217 for i := range expected {
218 uassert.Equal(t, expected[i].Key, actual[i][ "key" ])
219 uassert.Equal(t, expected[i].Value, actual[i][ "value" ])
220 }
221 }
222
223 func captureDefinitionRealm(cur realm) realm { return cur }
224
225 func TestSetDefinitionsAndEscapedFields(cur realm, t *testing.T) {
226 setupDefinition(cross(cur), t)
227 testing.SetRealm(testing.NewUserRealm(definitionAdmin))
228 key := "한글 😀,+&=%;"
229 fieldKey := "field,+&=%;"
230 value := "한글 😀\n\"\\`\x00,+&=%; } //"
231 SetDefinitions(cross(cur), url.QueryEscape(key)+ ",1101000" , url.QueryEscape(fieldKey)+ "=" +url.QueryEscape(value)+ "&empty=,key=wooden_sword" )
232 got, found := GetField(key, fieldKey)[ "value" ]
233 uassert.True(t, found)
234 uassert.Equal(t, value, got)
235 got, found = GetField(key, "empty" )[ "value" ]
236 uassert.True(t, found)
237 uassert.Equal(t, "" , got)
238 SetDefinitions(cross(cur), url.QueryEscape(key), "new=added" )
239 got, _ = GetField(key, fieldKey)[ "value" ]
240 uassert.Equal(t, value, got)
241 uassert.Equal(t, 2 , GetKeyCount())
242 got, _ = GetField( "1101000" , "key" )[ "value" ]
243 uassert.Equal(t, "wooden_sword" , got)
244 DeleteAll(cross(cur))
245 SetDefinitions(cross(cur), "1101000" , "fresh=value" )
246 _, found = GetField( "1101000" , "key" )[ "value" ]
247 uassert.False(t, found)
248 }
249
250 func TestSetDefinitionsRejectsInvalidInputAtomically(cur realm, t *testing.T) {
251 setupDefinition(cross(cur), t)
252 testing.SetRealm(testing.NewUserRealm(definitionAdmin))
253 setTestDefinition(cross(cur), "kept" , []Field{{ "name" , "old" }})
254 for _, tc := range [] struct { name, keys, values, errMsg string }{
255 { "empty" , "" , "" , "batch count must be between 1 and 100" },
256 { "missing keys" , "" , "n=v" , "keys and values count mismatch" },
257 { "missing values" , "x" , "" , "keys and values count mismatch" },
258 { "short values" , "kept,x" , "name=new" , "keys and values count mismatch" },
259 { "short keys" , "kept" , "name=new,n=v" , "keys and values count mismatch" },
260 { "empty key" , "kept,,x" , "name=new,n=v,n=v" , "empty entry token" },
261 { "empty fields" , "kept,x" , "name=new," , "empty entry token" },
262 { "trailing comma" , "kept," , "name=new," , "empty entry token" },
263 { "duplicate key" , "kept,k%65pt" , "name=new,n=v" , "duplicate entry" },
264 { "duplicate field" , "kept" , "name=new&n=1&%6E=2" , "duplicate field key" },
265 { "invalid escape key" , "kept,%zz" , "name=new,n=v" , "invalid encoded key" },
266 { "invalid escape value" , "kept,x" , "name=new,n=%zz" , "invalid encoded fields" },
267 { "invalid utf8 key" , "kept,%FF" , "name=new,n=v" , "invalid key" },
268 { "invalid utf8 value" , "kept,x" , "name=new,n=%FF" , "invalid field value" },
269 { "invalid field" , "kept,x" , "name=new,%0A=v" , "field key is required" },
270 { "encoded empty key" , "kept,+" , "name=new,n=v" , "key is required" },
271 { "no fields" , "kept,x" , "name=new,&" , "field count must be between 1 and 32" },
272 { "encoded limit" , strings.Repeat( "x" , 131072 ), "n=v" , "call bytes exceeds 131071" },
273 { "count limit" , strings.Repeat( "x," , 100 ) + "last" , strings.Repeat( "n=v," , 100 ) + "n=v" , "batch count must be between 1 and 100" },
274 { "raw limit" , "a,b,c,d,e" , strings.Repeat( "a=" +strings.Repeat( "x" , 16383 )+ "," , 4 ) + "a=" + strings.Repeat( "x" , 16383 ), "batch bytes exceeds 65536" },
275 } {
276 t.Run(tc.name, func (t *testing.T) {
277 testing.SetRealm(testing.NewUserRealm(definitionAdmin))
278 uassert.AbortsWithMessage(t, cur, tc.errMsg, func () { SetDefinitions(cross(cur), tc.keys, tc.values) })
279 value, found := GetField( "kept" , "name" )[ "value" ]
280 uassert.True(t, found)
281 uassert.Equal(t, "old" , value)
282 uassert.Equal(t, 1 , GetKeyCount())
283 })
284 }
285 }
286
287 func TestSetDefinitionsBatchAndMergedLimits(cur realm, t *testing.T) {
288 setupDefinition(cross(cur), t)
289 testing.SetRealm(testing.NewUserRealm(definitionAdmin))
290 keys, values, fields := "" , "" , ""
291 for i := 0 ; i < 32 ; i++ {
292 if i > 0 {
293 fields += "&"
294 }
295 fields += strconv.Itoa(i) + "=value"
296 }
297 for i := 0 ; i < 100 ; i++ {
298 if i > 0 {
299 keys += ","
300 values += ","
301 }
302 keys += strconv.Itoa(i)
303 values += fields
304 }
305 SetDefinitions(cross(cur), keys, values)
306 uassert.Equal(t, 100 , GetKeyCount())
307 uassert.AbortsWithMessage(t, cur, "field count must be between 1 and 32" , func () {
308 SetDefinitions(cross(cur), "0" , "extra=value" )
309 })
310 got := Get( "0" )
311 uassert.Equal(t, 32 , len(got))
312 uassert.AbortsWithMessage(t, cur, "field count must be between 1 and 32" , func () {
313 SetDefinitions(cross(cur), "new" , fields+ "&extra=value" )
314 })
315 }
316
317 // Test fixtures use the same encoded input boundary as the importer.
318 type testEntry struct {
319 Key string
320 Fields []Field
321 }
322
323 func setTestDefinition(cur realm, key string , fields []Field) {
324 setTestDefinitions(cur, []testEntry{{key, fields}})
325 }
326
327 func setTestDefinitions(cur realm, entries []testEntry) {
328 keys, values := "" , ""
329 for i, entry := range entries {
330 if i > 0 {
331 keys += ","
332 values += ","
333 }
334 keys += url.QueryEscape(entry.Key)
335 for j, field := range entry.Fields {
336 if j > 0 {
337 values += "&"
338 }
339 values += url.QueryEscape(field.Key) + "=" + url.QueryEscape(field.Value)
340 }
341 }
342 SetDefinitions(cur, keys, values)
343 }
344
345 func TestNumericKeyPagination(cur realm, t *testing.T) {
346 setupDefinition(cross(cur), t)
347 testing.SetRealm(testing.NewUserRealm(definitionAdmin))
348 huge := strings.Repeat( "9" , 128 )
349 keys := [] string { "1000000" , "100" , "10" , "2" , "1" , "0" , "01" , "00" , "item:2" , "item:10" , "18446744073709551616" , huge}
350 entries := []testEntry{}
351 for _, key := range keys {
352 entries = append(entries, testEntry{key, []Field{{ "name" , key}}})
353 }
354 setTestDefinitions(cross(cur), entries)
355 assertStrings(t, [] string { "0" , "00" , "01" , "1" , "2" }, ListKeys( 1 , 5 ))
356 assertStrings(t, [] string { "10" , "100" , "1000000" , "18446744073709551616" , huge}, ListKeys( 2 , 5 ))
357 assertStrings(t, [] string { "item:10" , "item:2" }, ListKeys( 3 , 5 ))
358 assertStrings(t, [] string {}, ListKeys( 4 , 5 ))
359 for _, key := range keys {
360 value, found := GetField(key, "name" )[ "value" ]
361 uassert.True(t, found)
362 uassert.Equal(t, key, value)
363 }
364 SetDefinitions(cross(cur), "2" , "name=updated" )
365 uassert.Equal(t, len(keys), GetKeyCount())
366 assertStrings(t, [] string { "0" , "00" , "01" , "1" , "2" }, ListKeys( 1 , 5 ))
367 DeleteAll(cross(cur))
368 assertStrings(t, [] string {}, ListKeys( 1 , 5 ))
369 }
370
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.