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

Community realm. Read the code first. Community realm, deployed by its author. Read the code before you interact or send coins.

administration_test.gno

7.00 Kb · 197 lines
  1package bolo
  2
  3import (
  4	"chain"
  5	"testing"
  6
  7	"gno.land/p/nt/testutils/v0"
  8)
  9
 10// TestAdministration walks the admin's writes on a fresh deployment, each called
 11// straight from the test's body, as AssertOriginCall requires (plan §3.3): the
 12// launch values, then each write's effect, then the handover to a realm, which
 13// then administers through C11's realm branch. The writes' refusals are tested in
 14// txtar (admin.txtar): a crossing call's panic can't be recovered here.
 15func TestAdministration(cur realm, t *testing.T) {
 16	// The walk changes every setting and the admin: put them back, so later
 17	// tests start from the launch values.
 18	defer restoreSettings(admin, pendingAdmin, params, presets, minDonation, escrowCap, tipRecipient, paused, sunset, categoryOrder)
 19
 20	// The launch values as API §2.2 states them: literals, not the constants under
 21	// test.
 22	if p := GetParams(); p != (Params{1_000_000, 90 * 86400, 60 * 86400, 30 * 86400}) {
 23		t.Errorf("launch params = %v", p)
 24	}
 25	s := GetSettings()
 26	if s.Version != "v0" || s.Presets != [4]int64{5_000_000, 10_000_000, 20_000_000, 50_000_000} ||
 27		s.MinDonation != 1_000_000 || s.MaxEscrowBalance != 1_000_000_000 ||
 28		s.TipRecipient != adminAddr || s.Paused || s.Sunset {
 29		t.Errorf("launch settings = %v", s)
 30	}
 31	launchSet := []string{
 32		"medical", "emergency", "disaster", "humanitarian", "water", "food",
 33		"education", "orphans", "animals", "funeral", "worship", "community",
 34		"sport", "celebration", "personal", "other",
 35	}
 36	if len(s.Categories) != len(launchSet) {
 37		t.Errorf("launch categories = %v", s.Categories)
 38	}
 39	for i, code := range launchSet {
 40		if i >= len(s.Categories) || s.Categories[i] != code || !categories.Has(code) {
 41			t.Errorf("launch category %d: want %s, listed and found", i, code)
 42		}
 43	}
 44	if a, p := GetAdmin(); a != adminAddr || p != "" {
 45		t.Errorf("GetAdmin() = %s, %q", a, p)
 46	}
 47	// GetSettings hands out a copy (C6).
 48	s.Categories[0] = "changed"
 49	if GetSettings().Categories[0] != "medical" {
 50		t.Errorf("GetSettings shares its categories with the realm")
 51	}
 52
 53	testing.SetRealm(testing.NewUserRealm(adminAddr))
 54	SetParams(cross(cur), 2_000_000, 30, 14, 0)
 55	SetMinDonation(cross(cur), 500_000)
 56	SetPresets(cross(cur), 1_000_000, 2_000_000, 3_000_000, 4_000_000)
 57	SetEscrowCap(cross(cur), 0)
 58	AddCategory(cross(cur), "garden")
 59	treasurer := testutils.TestAddress("treasurer")
 60	SetTipRecipient(cross(cur), treasurer)
 61	Pause(cross(cur))
 62	Sunset(cross(cur))
 63	if p := GetParams(); p != (Params{2_000_000, 30 * secondsPerDay, 14 * secondsPerDay, 0}) {
 64		t.Errorf("params = %v", p)
 65	}
 66	s = GetSettings()
 67	if s.MinDonation != 500_000 || s.Presets != [4]int64{1_000_000, 2_000_000, 3_000_000, 4_000_000} ||
 68		s.MaxEscrowBalance != 0 || s.TipRecipient != treasurer || !s.Paused || !s.Sunset ||
 69		len(s.Categories) != 17 || s.Categories[16] != "garden" || !categories.Has("garden") {
 70		t.Errorf("settings = %v", s)
 71	}
 72	Unpause(cross(cur))
 73	if GetSettings().Paused {
 74		t.Errorf("still paused")
 75	}
 76
 77	// The handover (ADR D11): a second proposal replaces the first; accepting ends
 78	// the proposal, and the new admin is a realm.
 79	dao := chain.PackageAddress("gno.land/r/test/dao")
 80	ProposeAdmin(cross(cur), testutils.TestAddress("someone"))
 81	ProposeAdmin(cross(cur), dao)
 82	if a, p := GetAdmin(); a != adminAddr || p != dao {
 83		t.Errorf("after two proposals: GetAdmin() = %s, %s", a, p)
 84	}
 85	testing.SetRealm(testing.NewCodeRealm("gno.land/r/test/dao"))
 86	AcceptAdmin(cross(cur))
 87	if a, p := GetAdmin(); a != dao || p != "" {
 88		t.Errorf("after accepting: GetAdmin() = %s, %q", a, p)
 89	}
 90	SetEscrowCap(cross(cur), 7)
 91	if GetSettings().MaxEscrowBalance != 7 {
 92		t.Errorf("the realm admin's write didn't apply")
 93	}
 94}
 95
 96func TestCheckParams(t *testing.T) {
 97	if got := checkParams(1, 1, 7, 0); got != (Params{1, secondsPerDay, 7 * secondsPerDay, 0}) {
 98		t.Errorf("lower bounds: %v", got)
 99	}
100	if got := checkParams(1, 3650, 3650, 3650); got != (Params{1, 3650 * secondsPerDay, 3650 * secondsPerDay, 3650 * secondsPerDay}) {
101		t.Errorf("upper bounds: %v", got)
102	}
103	for name, c := range map[string]struct {
104		deposit                   int64
105		dormancy, exitDelay, hold int
106	}{
107		"no deposit":           {0, 90, 60, 30},
108		"negative deposit":     {-1, 90, 60, 30},
109		"no dormancy":          {1, 0, 60, 30},
110		"dormancy too long":    {1, 3651, 60, 30},
111		"exit delay too short": {1, 90, 6, 30},
112		"exit delay too long":  {1, 90, 3651, 30},
113		"negative bond hold":   {1, 90, 60, -1},
114		"bond hold too long":   {1, 90, 60, 3651},
115	} {
116		if !panicsWith(func() { checkParams(c.deposit, c.dormancy, c.exitDelay, c.hold) }, ErrSetting) {
117			t.Errorf("%s: not refused", name)
118		}
119	}
120}
121
122func TestCheckPresets(t *testing.T) {
123	if got := checkPresets(1, 2, 3, 4); got != [4]int64{1, 2, 3, 4} {
124		t.Errorf("checkPresets = %v", got)
125	}
126	for name, p := range map[string][4]int64{
127		"zero":        {0, 2, 3, 4},
128		"negative":    {-1, 2, 3, 4},
129		"equal pair":  {1, 2, 2, 4},
130		"last equal":  {1, 2, 3, 3},
131		"first equal": {1, 1, 3, 4},
132		"descending":  {4, 3, 2, 1},
133	} {
134		if !panicsWith(func() { checkPresets(p[0], p[1], p[2], p[3]) }, ErrSetting) {
135			t.Errorf("%s: not refused", name)
136		}
137	}
138}
139
140func TestCheckOutsideBolo(t *testing.T) {
141	checkOutsideBolo(testutils.TestAddress("treasurer"))
142	campaign := escrowAddr(9)
143	derived.Set(campaign.String(), true)
144	defer derived.Remove(campaign.String())
145	for name, a := range map[string]address{
146		"the realm":              realmAddr(),
147		"slashed":                slashedAddr(),
148		"the storage deposit":    depositAddr(),
149		"the registry":           registryAddr(),
150		"the registry's deposit": registryDepositAddr(),
151		"a campaign's escrow":    campaign,
152		"malformed":              "g1notanaddress",
153	} {
154		if !panicsWith(func() { checkOutsideBolo(a) }, ErrSetting) {
155			t.Errorf("%s: not refused", name)
156		}
157	}
158}
159
160func TestCheckNewCategory(t *testing.T) {
161	checkNewCategory("orchard")
162	checkNewCategory("abc")
163	checkNewCategory("abcdefghijklmnopqrst")
164	for name, code := range map[string]string{
165		"too short":      "ab",
166		"too long":       "abcdefghijklmnopqrstu",
167		"capitals":       "Orchard",
168		"a digit":        "orchard2",
169		"a space":        "or chard",
170		"already listed": "water",
171	} {
172		if !panicsWith(func() { checkNewCategory(code) }, ErrSetting) {
173			t.Errorf("%s: not refused", name)
174		}
175	}
176	// The 50th fits, the 51st doesn't (API §3.6, INV-9).
177	saved := categoryOrder
178	defer func() { categoryOrder = saved }()
179	for len(categoryOrder) < 49 {
180		categoryOrder = append(categoryOrder, "filler")
181	}
182	checkNewCategory("orchard")
183	categoryOrder = append(categoryOrder, "orchard")
184	if !panicsWith(func() { checkNewCategory("grove") }, ErrSetting) {
185		t.Errorf("a 51st category: not refused")
186	}
187}
188
189// restoreSettings puts back what TestAdministration changes.
190func restoreSettings(a, pending address, p Params, pr [4]int64, minimum, ceiling int64, tips address, pause, sun bool, order []string) {
191	admin, pendingAdmin, params, presets = a, pending, p, pr
192	minDonation, escrowCap, tipRecipient, paused, sunset = minimum, ceiling, tips, pause, sun
193	for _, code := range categoryOrder[len(order):] {
194		categories.Remove(code)
195	}
196	categoryOrder = order
197}