nativereg_test.gno
5.34 Kb · 132 lines
1package nativereg
2
3import (
4 "strings"
5 "testing"
6
7 "gno.land/p/nt/testutils/v0"
8 "gno.land/p/nt/uassert/v0"
9)
10
11const (
12 issuerPath = "gno.land/r/test/coiner"
13 issuerCoin = "/gno.land/r/test/coiner:testcoin"
14 otherPath = "gno.land/r/test/stranger"
15 otherCoin = "/gno.land/r/test/stranger:othercoin"
16)
17
18// testing.SetRealm governs only the crossing calls made from the frame that
19// called it, so each switch below is inline in the test body.
20
21func TestOnlyTheIssuerRegisters(cur realm, t *testing.T) {
22 testing.SetRealm(testing.NewCodeRealm(issuerPath))
23 Register(cross(cur), issuerCoin, "Test Coin", "TEST", 6, "a coin for a test")
24
25 e := MustGet(issuerCoin)
26 uassert.Equal(t, issuerPath, e.Issuer, "the issuer is read out of the denom, not supplied")
27 uassert.Equal(t, "TEST", e.Symbol)
28 uassert.Equal(t, 6, e.Decimals)
29 uassert.Equal(t, 0, e.Revisions)
30
31 // The same realm cannot describe somebody else's coin.
32 uassert.AbortsContains(t, cur, "is issued by "+otherPath, func() {
33 Register(cross(cur), otherCoin, "Not Mine", "NOPE", 0, "")
34 })
35}
36
37func TestAUserAccountCannotRegister(cur realm, t *testing.T) {
38 alice := testutils.TestAddress("nr-alice")
39 testing.SetRealm(testing.NewUserRealm(alice))
40 // Even for a denom she holds every unit of: what is being described is the
41 // issuance, and a wallet has no package path to prove.
42 uassert.AbortsContains(t, cur, "no package path to prove", func() {
43 Register(cross(cur), issuerCoin, "Mine Now", "MINE", 0, "")
44 })
45}
46
47func TestReregisteringBumpsRevisions(cur realm, t *testing.T) {
48 testing.SetRealm(testing.NewCodeRealm(issuerPath))
49 before := Count()
50 Register(cross(cur), issuerCoin, "Test Coin v2", "TEST2", 4, "renamed")
51
52 e := MustGet(issuerCoin)
53 uassert.Equal(t, "TEST2", e.Symbol, "an issuer can always re-describe its own coin")
54 uassert.Equal(t, 1, e.Revisions)
55 uassert.Equal(t, before, Count(), "a rewrite is not a second entry")
56 uassert.Equal(t, 1, len(ByIssuer(issuerPath)))
57 uassert.Equal(t, 0, len(ByIssuer(otherPath)))
58}
59
60func TestBounds(cur realm, t *testing.T) {
61 testing.SetRealm(testing.NewCodeRealm(issuerPath))
62 uassert.AbortsContains(t, cur, "name is", func() {
63 Register(cross(cur), issuerCoin, strings.Repeat("x", MaxName+1), "T", 0, "")
64 })
65 uassert.AbortsContains(t, cur, "symbol is", func() {
66 Register(cross(cur), issuerCoin, "n", strings.Repeat("x", MaxSymbol+1), 0, "")
67 })
68 uassert.AbortsContains(t, cur, "doc is", func() {
69 Register(cross(cur), issuerCoin, "n", "T", 0, strings.Repeat("x", MaxDoc+1))
70 })
71 uassert.AbortsContains(t, cur, "decimals is 19", func() {
72 Register(cross(cur), issuerCoin, "n", "T", MaxDecimals+1, "")
73 })
74 uassert.AbortsContains(t, cur, "decimals is -1", func() {
75 Register(cross(cur), issuerCoin, "n", "T", -1, "")
76 })
77}
78
79func TestIssuerOfReadsTheDenom(cur realm, t *testing.T) {
80 // The relation is in the string, so this answers for a denom nobody ever
81 // registered, which is the case that matters: given a balance you did not
82 // ask for, this is how you find the code that can take it away.
83 uassert.Equal(t, "gno.land/r/nobody/here/v3", IssuerOf("/gno.land/r/nobody/here/v3:ghost"))
84 uassert.Equal(t, issuerPath, IssuerOf(issuerCoin))
85
86 uassert.PanicsContains(t, cur, "must start with /", func() { IssuerOf("ugnot") })
87 uassert.PanicsContains(t, cur, "must contain :", func() { IssuerOf("/gno.land/r/a/v0") })
88 uassert.PanicsContains(t, cur, "malformed", func() { IssuerOf("/gno.land/r/a/v0:") })
89 uassert.PanicsContains(t, cur, "malformed", func() { IssuerOf("/:x") })
90}
91
92func TestUnregisteredReadsCleanly(cur realm, t *testing.T) {
93 _, ok := Get("/gno.land/r/nobody/here/v3:ghost")
94 uassert.False(t, ok)
95 uassert.False(t, IsRegistered("/gno.land/r/nobody/here/v3:ghost"))
96 uassert.PanicsContains(t, cur, "no entry for", func() { MustGet("/gno.land/r/x/y/v0:zz") })
97}
98
99func TestRender(cur realm, t *testing.T) {
100 testing.SetRealm(testing.NewCodeRealm(otherPath))
101 Register(cross(cur), otherCoin, "Other Coin", "OTHER", 0, "the second one")
102
103 index := Render("")
104 uassert.True(t, strings.Contains(index, "# nativereg"), index)
105 uassert.True(t, strings.Contains(index, "OTHER"), "the index lists entries:\n"+index)
106
107 one := Render(otherCoin)
108 uassert.True(t, strings.Contains(one, "the second one"), one)
109 uassert.True(t, strings.Contains(one, otherPath), one)
110
111 byIssuer := Render(issuerPath)
112 uassert.True(t, strings.Contains(byIssuer, "TEST2"), byIssuer)
113 uassert.False(t, strings.Contains(byIssuer, "OTHER"), "one issuer's page shows only its own")
114
115 // A Render never aborts on a path a reader typed, registered or not.
116 uassert.True(t, strings.Contains(Render("/gno.land/r/x/y/v0:nope"), "Not registered"))
117 uassert.True(t, strings.Contains(Render("ugnot"), "registered nothing"),
118 "a non-denom path falls through to the issuer view rather than aborting")
119 uassert.True(t, strings.Contains(Render("/garbage"), "not a realm denom"))
120}
121
122func TestRenderEscapesWhatAnIssuerWrote(cur realm, t *testing.T) {
123 // An issuer's own name and doc are still caller-supplied text, and a realm
124 // that can register can write a table-breaking pipe as easily as a name.
125 const nasty = "gno.land/r/test/nasty"
126 testing.SetRealm(testing.NewCodeRealm(nasty))
127 Register(cross(cur), "/gno.land/r/test/nasty:nastycoin", "a|b", "x|y", 0, "")
128
129 index := Render("")
130 uassert.False(t, strings.Contains(index, "| a|b |"), "a raw pipe would open a column:\n"+index)
131 uassert.True(t, strings.Contains(index, "a\\|b"), "it is escaped instead:\n"+index)
132}