grc20reg_test.gno
4.44 Kb · 141 lines
1package grc20reg
2
3import (
4 "strings"
5 "testing"
6
7 "gno.land/p/demo/tokens/grc20"
8 "gno.land/p/nt/urequire/v0"
9)
10
11func TestRegistry(cur realm, t *testing.T) {
12 testing.SetRealm(testing.NewCodeRealm("gno.land/r/demo/foo"))
13 token, ledger := grc20.NewToken("TestToken", "TST", 4, 0, cur)
14 ledger.Mint(cur.Address(), 1234567)
15 // register
16 key := Register(cross(cur), token, "mySlug")
17 regToken := Get(key)
18 urequire.True(t, regToken != nil, "expected to find a token") // fixme: use urequire.NotNil
19 urequire.Equal(t, regToken.GetSymbol(), "TST")
20
21 expected := `- **TestToken** - [gno.land/r/demo/foo](/r/demo/foo).TST - [info](/r/demo/grc20reg:gno.land/r/demo/foo.TST)
22`
23 got := Render("")
24 urequire.True(t, strings.Contains(got, expected))
25 // 404
26 invalidToken := Get("0xdeadbeef")
27 urequire.True(t, invalidToken == nil)
28
29 got = Render("")
30 urequire.True(t, strings.Contains(got, expected))
31
32 expected = `# TestToken
33- symbol: **TST**
34- realm: [gno.land/r/demo/foo](/r/demo/foo).TST
35- decimals: 4
36- total supply: 1234567
37`
38 got = Render(key)
39 urequire.Equal(t, expected, got)
40
41 // The registry keys by rlmPath.symbol, so a second token with the same
42 // symbol in the same realm is rejected even though its Token.ID() differs
43 // (distinct trailing sequence id). See TestRegisterRejectsOverwrite.
44 second, _ := grc20.NewToken("Second", "TST", 4, 1, cur)
45 urequire.NotEqual(t, token.ID(), second.ID()) // ids are decoupled from symbol
46 urequire.AbortsContains(t, cur, "token already registered", func() {
47 Register(cross(cur), second, "")
48 })
49}
50
51func TestRegisterRejectsOverwrite(cur realm, t *testing.T) {
52 testing.SetRealm(testing.NewCodeRealm("gno.land/r/demo/grc20reg_overwrite"))
53 token, ledger := grc20.NewToken("Bar", "BAR", 4, 0, cur)
54 ledger.Mint(cur.Address(), 11)
55 key := Register(cross(cur), token, "")
56
57 urequire.Equal(t, "BAR", Get(key).GetSymbol())
58 urequire.Equal(t, int64(11), Get(key).BalanceOf(cur.Address()))
59
60 replacement, _ := grc20.NewToken("Replacement", "BAR", 6, 0, cur)
61 urequire.AbortsContains(t, cur, "token already registered", func() {
62 Register(cross(cur), replacement, "")
63 })
64}
65
66func TestRegisterRejectsAliasedTokenPaths(cur realm, t *testing.T) {
67 testing.SetRealm(testing.NewCodeRealm("gno.land/r/demo/grc20reg_alias"))
68 token, _ := grc20.NewToken("Aliased Token", "ALIAS", 4, 0, cur)
69 Register(cross(cur), token, "first")
70
71 urequire.AbortsContains(t, cur, "token already registered", func() {
72 Register(cross(cur), token, "second")
73 })
74}
75
76func TestRegisterRejectsTokenFromDifferentRealm(cur realm, t *testing.T) {
77 testing.SetRealm(testing.NewCodeRealm("gno.land/r/demo/grc20reg_id_source"))
78 token, _ := grc20.NewToken("Mismatch Token", "MISMATCH", 4, 0, cur)
79
80 testing.SetRealm(testing.NewCodeRealm("gno.land/r/demo/grc20reg_id_target"))
81 urequire.AbortsContains(t, cur, "token must be registered from its own realm", func() {
82 Register(cross(cur), token, "")
83 })
84}
85
86func TestValidateSlug(cur realm, t *testing.T) {
87 // Valid slugs — should not panic
88 valid := []string{"mytoken", "my-token", "my_token", "Token123", "a", "A-B_c", strings.Repeat("a", maxSlugLen)}
89 for _, slug := range valid {
90 validateSlug(slug) // no panic = pass
91 }
92}
93
94func TestValidateSlugPanicsOnTooLong(cur realm, t *testing.T) {
95 defer func() { recover() }()
96 validateSlug(strings.Repeat("a", maxSlugLen+1))
97 t.Errorf("should have panicked")
98}
99
100func TestValidateSlugPanicsOnSpace(cur realm, t *testing.T) {
101 defer func() { recover() }()
102 validateSlug("has space")
103 t.Errorf("should have panicked")
104}
105
106func TestValidateSlugPanicsOnDot(cur realm, t *testing.T) {
107 defer func() { recover() }()
108 validateSlug("has.dot")
109 t.Errorf("should have panicked")
110}
111
112func TestValidateSlugPanicsOnSlash(cur realm, t *testing.T) {
113 defer func() { recover() }()
114 validateSlug("has/slash")
115 t.Errorf("should have panicked")
116}
117
118func TestValidateSlugPanicsOnBrackets(cur realm, t *testing.T) {
119 defer func() { recover() }()
120 validateSlug("[brackets]")
121 t.Errorf("should have panicked")
122}
123
124func TestValidateSlugPanicsOnParens(cur realm, t *testing.T) {
125 defer func() { recover() }()
126 validateSlug("(parens)")
127 t.Errorf("should have panicked")
128}
129
130func TestValidateSlugPanicsOnInjection(cur realm, t *testing.T) {
131 defer func() { recover() }()
132 validateSlug(`) [Claim](https://evil.com`)
133 t.Errorf("should have panicked")
134}
135
136func TestRegisterRejectsNilToken(cur realm, t *testing.T) {
137 testing.SetRealm(testing.NewCodeRealm("gno.land/r/demo/grc20reg_nil"))
138 urequire.AbortsContains(t, cur, "nil token", func() {
139 Register(cross(cur), nil, "")
140 })
141}