lotto_test.gno
8.90 Kb · 237 lines
1package lotto
2
3import (
4 "strconv"
5 "testing"
6
7 "gno.land/p/akkadia/beta/accesscontrol"
8 "gno.land/p/nt/testutils/v0"
9 "gno.land/p/nt/uassert/v0"
10 "gno.land/r/akkadia/beta/admin"
11)
12
13func TestAddNumber(cur realm, t *testing.T) {
14 setupLotto(cross(cur))
15 for _, caller := range []address{testAdmin, testOperator} {
16 testing.SetOriginCaller(caller)
17 testing.SetRealm(testing.NewUserRealm(caller))
18 for i := 0; i < 3; i++ {
19 AddNumber(cross(cur), testOwner, 123456)
20 }
21 }
22 uassert.Equal(t, GetNumberCount(123456, testOwner), uint64(6))
23 uassert.Equal(t, holdings.Size(), 1)
24 testing.SetRealm(testing.NewUserRealm(testAdmin))
25 AddNumber(cross(cur), testOther, 123456)
26 AddNumber(cross(cur), testOwner, 654321)
27 uassert.Equal(t, GetNumberCount(123456, testOwner), uint64(6))
28 uassert.Equal(t, GetNumberCount(123456, testOther), uint64(1))
29 uassert.Equal(t, GetNumberCount(654321, testOwner), uint64(1))
30 uassert.Equal(t, GetNumberCount(654321, testOther), uint64(0))
31 uassert.Equal(t, holdings.Size(), 3)
32 page := ListOwnersByNumber(123456, "", 100)
33 uassert.Equal(t, len(page), 2)
34 uassert.Equal(t, page[0]["nextOwner"], "")
35 for _, item := range page {
36 uassert.Equal(t, item["count"], strconv.FormatUint(GetNumberCount(123456, address(item["owner"])), 10))
37 }
38}
39
40func TestAddNumberAuthority(cur realm, t *testing.T) {
41 setupLotto(cross(cur))
42 testing.SetRealm(testing.NewUserRealm(testAdmin))
43 AddNumber(cross(cur), testOwner, 1)
44 for _, caller := range []address{testOwner, testOther} {
45 testing.SetOriginCaller(caller)
46 testing.SetRealm(testing.NewUserRealm(caller))
47 uassert.AbortsWithMessage(t, cur, "admin or operator access required", func() {
48 AddNumber(cross(cur), testOwner, 1)
49 })
50 uassert.Equal(t, GetNumberCount(1, testOwner), uint64(1))
51 }
52 testing.SetOriginCaller(testAdmin)
53 testing.SetRealm(testing.NewUserRealm(testAdmin))
54 admin.UnsetOperator(cross(cur), testOperator)
55 testing.SetOriginCaller(testOperator)
56 testing.SetRealm(testing.NewUserRealm(testOperator))
57 uassert.AbortsWithMessage(t, cur, "admin or operator access required", func() {
58 AddNumber(cross(cur), testOwner, 1)
59 })
60 testing.SetRealm(testing.NewUserRealm(testAdmin))
61 admin.SetOperator(cross(cur), testOperator)
62 for _, signer := range []address{testAdmin, testOperator} {
63 testing.SetOriginCaller(signer)
64 testing.SetRealm(testing.NewCodeRealm("gno.land/r/example/lotto_relay"))
65 uassert.AbortsWithMessage(t, cur, "admin or operator access required", func() {
66 AddNumber(cross(cur), testOwner, 1)
67 })
68 }
69 // Probe the actual helper with a foreign realm, without cross(stale) masking
70 // its spoofed-realm assertion with a builtin crossing failure.
71 spoofed := cur.Previous()
72 uassert.PanicsWithMessage(t, cur, "spoofed realm", func() {
73 accesscontrol.MustGetAdminOrOperatorCaller(0, spoofed, admin.IsAdmin, admin.IsOperator)
74 })
75 uassert.Equal(t, GetNumberCount(1, testOwner), uint64(1))
76 uassert.Equal(t, holdings.Size(), 1)
77}
78
79func TestAddNumberValidation(cur realm, t *testing.T) {
80 setupLotto(cross(cur))
81 for _, number := range []uint64{0, ^uint64(0)} {
82 testing.SetRealm(testing.NewUserRealm(testAdmin))
83 AddNumber(cross(cur), testOwner, number)
84 uassert.Equal(t, GetNumberCount(number, testOwner), uint64(1))
85 uassert.Equal(t, ListOwnersByNumber(number, "", 1)[0]["owner"], testOwner.String())
86 }
87 for _, owner := range []address{"", "invalid", address(testOwner.String() + "x")} {
88 testing.SetRealm(testing.NewUserRealm(testAdmin))
89 uassert.AbortsWithMessage(t, cur, "invalid address", func() {
90 AddNumber(cross(cur), owner, 1)
91 })
92 uassert.PanicsWithMessage(t, cur, "invalid address", func() { GetNumberCount(1, owner) })
93 if owner != "" {
94 uassert.PanicsWithMessage(t, cur, "invalid address", func() {
95 ListOwnersByNumber(1, owner.String(), 1)
96 })
97 }
98 }
99 uassert.Equal(t, holdings.Size(), 2)
100 // Overflow cannot be reached economically through repeated public calls.
101 holdings.Set("1:"+testOwner.String(), ^uint64(0))
102 testing.SetRealm(testing.NewUserRealm(testAdmin))
103 uassert.AbortsWithMessage(t, cur, "number count overflow", func() {
104 AddNumber(cross(cur), testOwner, 1)
105 })
106 uassert.Equal(t, GetNumberCount(1, testOwner), ^uint64(0))
107 uassert.Equal(t, ListOwnersByNumber(1, "", 1)[0]["count"], "18446744073709551615")
108 uassert.Equal(t, holdings.Size(), 3)
109}
110
111func TestListOwnersByNumber(cur realm, t *testing.T) {
112 setupLotto(cross(cur))
113 uassert.Equal(t, len(ListOwnersByNumber(1, "", 100)), 0)
114
115 uassert.Equal(t, GetNumberCount(1, testOwner), uint64(0))
116 uassert.Equal(t, holdings.Size(), 0)
117 for _, limit := range []int{-1, 0, 101} {
118 uassert.PanicsWithMessage(t, cur, "limit must be between 1 and 100", func() {
119 ListOwnersByNumber(1, "", limit)
120 })
121 }
122 for _, number := range []uint64{1, 10, 100} {
123 for i := 0; i < 105; i++ {
124 testing.SetRealm(testing.NewUserRealm(testAdmin))
125 owner := testutils.TestAddress("lottoPage" + strconv.FormatUint(number, 10) + ":" + strconv.Itoa(i))
126 AddNumber(cross(cur), owner, number)
127 if i%2 == 0 {
128 AddNumber(cross(cur), owner, number)
129 }
130 }
131 }
132 for _, number := range []uint64{1, 10, 100} {
133 for _, limit := range []int{1, 7, 100} {
134 after := ""
135 seen := 0
136 for {
137 page := ListOwnersByNumber(number, after, limit)
138 for _, item := range page {
139 uassert.True(t, item["owner"] > after)
140 uassert.Equal(t, item["nextOwner"], page[0]["nextOwner"])
141 uassert.Equal(t, item["count"], strconv.FormatUint(GetNumberCount(number, address(item["owner"])), 10))
142 after = item["owner"]
143 seen++
144 }
145 if len(page) == 0 || page[0]["nextOwner"] == "" {
146 break
147 }
148 uassert.Equal(t, len(page), limit)
149 uassert.Equal(t, page[0]["nextOwner"], after)
150 }
151 uassert.Equal(t, seen, 105)
152 uassert.Equal(t, len(ListOwnersByNumber(number, after, limit)), 0)
153 }
154 }
155 uassert.Equal(t, holdings.Size(), 315)
156 uassert.Equal(t, len(ListOwnersByNumber(1000, "", 100)), 0)
157 // A valid cursor between stored owners does not have to be stored itself.
158 missing := testutils.TestAddress("lottoMissing").String()
159 uassert.Equal(t, GetNumberCount(1, address(missing)), uint64(0))
160 first := ListOwnersByNumber(1, "", 100)
161 all := append(first, ListOwnersByNumber(1, first[0]["nextOwner"], 100)...)
162 expected := []map[string]string{}
163 for _, item := range all {
164 if item["owner"] > missing {
165 expected = append(expected, item)
166 }
167 }
168 page := ListOwnersByNumber(1, missing, 100)
169 actual := page
170 if len(page) > 0 && page[0]["nextOwner"] != "" {
171 actual = append(actual, ListOwnersByNumber(1, page[0]["nextOwner"], 100)...)
172 }
173 uassert.Equal(t, len(actual), len(expected))
174 for i, item := range actual {
175 uassert.Equal(t, item["owner"], expected[i]["owner"])
176 uassert.Equal(t, item["count"], expected[i]["count"])
177 }
178 fresh := ListOwnersByNumber(1, "", 1)
179 original := map[string]string{"owner": fresh[0]["owner"], "count": fresh[0]["count"]}
180 fresh[0]["owner"] = testOther.String()
181 fresh[0]["count"] = "999"
182 fresh[0]["nextOwner"] = "changed"
183 uassert.Equal(t, ListOwnersByNumber(1, "", 1)[0]["owner"], original["owner"])
184 uassert.Equal(t, ListOwnersByNumber(1, "", 1)[0]["count"], original["count"])
185 uassert.Equal(t, strconv.FormatUint(GetNumberCount(1, address(original["owner"])), 10), original["count"])
186 uassert.Equal(t, holdings.Size(), 315)
187}
188
189func TestDeleteAll(cur realm, t *testing.T) {
190 setupLotto(cross(cur))
191 testing.SetOriginCaller(testAdmin)
192 testing.SetRealm(testing.NewUserRealm(testAdmin))
193 AddNumber(cross(cur), testOwner, 1)
194 AddNumber(cross(cur), testOwner, 1)
195 AddNumber(cross(cur), testOther, 1)
196 AddNumber(cross(cur), testOwner, 2)
197
198 DeleteAll(cross(cur))
199 uassert.Equal(t, holdings.Size(), 0)
200 for _, number := range []uint64{1, 2} {
201 for _, owner := range []address{testOwner, testOther} {
202 uassert.Equal(t, GetNumberCount(number, owner), uint64(0))
203 }
204 uassert.Equal(t, len(ListOwnersByNumber(number, "", 100)), 0)
205 }
206 DeleteAll(cross(cur))
207 // Operators can register again, starting from one instead of the old count.
208 testing.SetOriginCaller(testOperator)
209 testing.SetRealm(testing.NewUserRealm(testOperator))
210 AddNumber(cross(cur), testOwner, 1)
211 uassert.Equal(t, GetNumberCount(1, testOwner), uint64(1))
212 uassert.Equal(t, holdings.Size(), 1)
213 uassert.Equal(t, len(ListOwnersByNumber(1, "", 100)), 1)
214}
215
216func TestDeleteAllAuthority(cur realm, t *testing.T) {
217 setupLotto(cross(cur))
218 testing.SetOriginCaller(testAdmin)
219 testing.SetRealm(testing.NewUserRealm(testAdmin))
220 AddNumber(cross(cur), testOwner, 1)
221 for _, caller := range []address{testOwner, testOperator} {
222 testing.SetOriginCaller(caller)
223 testing.SetRealm(testing.NewUserRealm(caller))
224 uassert.AbortsWithMessage(t, cur, "admin access required", func() {
225 DeleteAll(cross(cur))
226 })
227 uassert.Equal(t, GetNumberCount(1, testOwner), uint64(1))
228 uassert.Equal(t, holdings.Size(), 1)
229 }
230 testing.SetOriginCaller(testAdmin)
231 testing.SetRealm(testing.NewCodeRealm("gno.land/r/example/lotto_relay"))
232 uassert.AbortsWithMessage(t, cur, "admin access required", func() {
233 DeleteAll(cross(cur))
234 })
235 uassert.Equal(t, GetNumberCount(1, testOwner), uint64(1))
236 uassert.Equal(t, holdings.Size(), 1)
237}