Search Apps Documentation Source Content File Folder Download Copy Actions Download State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

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}