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.

create_test.gno

7.12 Kb · 189 lines
  1package bolo
  2
  3import (
  4	"chain"
  5	"chain/banker"
  6	"strings"
  7	"testing"
  8
  9	"gno.land/p/nt/avl/v0"
 10	"gno.land/p/nt/seqid/v0"
 11	"gno.land/p/nt/testutils/v0"
 12)
 13
 14// TestCreateCampaign creates campaigns as a user, straight from the test's body as
 15// AssertOriginCall requires (plan §3.3), with the envelope and the realm's coins a
 16// real transaction would bring. Its refusals are in txtar (create.txtar): a test
 17// can't recover a crossing call's panic.
 18func TestCreateCampaign(cur realm, t *testing.T) {
 19	defer restoreCampaigns(nextID)
 20	defer restoreSettings(admin, pendingAdmin, params, presets, minDonation, escrowCap, tipRecipient, paused, sunset, categoryOrder)
 21
 22	organizer := testutils.TestAddress("organizer")
 23	beneficiary := testutils.TestAddress("beneficiary")
 24	deposit := params.CreationDeposit
 25	first := nextID + 1
 26
 27	testing.SetRealm(testing.NewUserRealm(organizer))
 28	testing.SetOriginSend(chain.NewCoins(chain.NewCoin("ugnot", deposit)))
 29	testing.IssueCoins(realmAddr(), chain.NewCoins(chain.NewCoin("ugnot", deposit)))
 30	id := CreateCampaign(cross(cur), "  Clean water for Ndiaganiao ", "A pump.", "water", "", "", beneficiary, 1_500_000_000, modeEscrow, 0)
 31	if id != idString(first) {
 32		t.Fatalf("CreateCampaign returned %q, want %q", id, idString(first))
 33	}
 34
 35	// The deposit went to the bond address; the realm keeps nothing (INV-3).
 36	rb := banker.NewReadonlyBanker()
 37	if got := rb.GetCoin(bondAddr(first), "ugnot"); got != deposit {
 38		t.Errorf("bond address holds %d, want the deposit %d", got, deposit)
 39	}
 40	if got := rb.GetCoin(realmAddr(), "ugnot"); got != 0 {
 41		t.Errorf("the realm kept %d", got)
 42	}
 43
 44	v := GetCampaign(id)
 45	want := CampaignView{
 46		ID: id, Title: "Clean water for Ndiaganiao", Description: "A pump.", Category: "water",
 47		Organizer: organizer, Beneficiary: beneficiary, Mode: modeEscrow, Status: statusOpen, Listed: true,
 48		Goal: 1_500_000_000, Deposit: deposit, CreatedAt: now(),
 49		ClosableByAnyoneAt: now() + params.DormancyPeriod,
 50		EscrowAddress:      escrowAddr(first), BondAddress: bondAddr(first), Params: params,
 51	}
 52	if v != want {
 53		t.Errorf("GetCampaign =\n%v\nwant\n%v", v, want)
 54	}
 55	key := first.Binary()
 56	for name, tree := range map[string]*avl.Tree{
 57		"campaigns":        &campaigns,
 58		"active":           &active,
 59		"activeByCategory": &activeByCategory,
 60		"byOrganizer":      &byOrganizer,
 61		"byBeneficiary":    &byBeneficiary,
 62	} {
 63		k := key
 64		switch name {
 65		case "activeByCategory":
 66			k = "water/" + key
 67		case "byOrganizer":
 68			k = organizer.String() + "/" + key
 69		case "byBeneficiary":
 70			k = beneficiary.String() + "/" + key
 71		}
 72		if !tree.Has(k) {
 73			t.Errorf("campaign %s is missing from %s", id, name)
 74		}
 75	}
 76	if !derived.Has(escrowAddr(first).String()) || !derived.Has(bondAddr(first).String()) {
 77		t.Errorf("campaign %s's escrow and bond addresses aren't recorded as derived", id)
 78	}
 79
 80	// A change of Params applies to campaigns created afterwards only (INV-5).
 81	testing.SetRealm(testing.NewUserRealm(adminAddr))
 82	SetParams(cross(cur), 3_000_000, 30, 14, 7)
 83	testing.SetRealm(testing.NewUserRealm(organizer))
 84	testing.SetOriginSend(chain.NewCoins(chain.NewCoin("ugnot", 3_000_000)))
 85	testing.IssueCoins(realmAddr(), chain.NewCoins(chain.NewCoin("ugnot", 3_000_000)))
 86	second := CreateCampaign(cross(cur), "A second campaign", "", "food", "", "", beneficiary, 0, modeDirect, 0)
 87	if v := GetCampaign(id); v.Params != want.Params || v.Deposit != deposit {
 88		t.Errorf("SetParams changed campaign %s: %v", id, v.Params)
 89	}
 90	if v := GetCampaign(second); v.Params != GetParams() || v.Deposit != 3_000_000 {
 91		t.Errorf("campaign %s didn't get the new Params: %v", second, v.Params)
 92	}
 93}
 94
 95func TestCheckCampaignTerms(t *testing.T) {
 96	checkCampaignTerms("water", modeDirect, 0, 0)
 97	checkCampaignTerms("water", modeEscrow, 1, now()+1)
 98	checkCampaignTerms("water", modeEscrow, 1, now()+maxDeadlineDays*secondsPerDay)
 99	for name, c := range map[string]struct {
100		category, mode string
101		goal, deadline int64
102		err            Error
103	}{
104		"unknown category":  {"rockets", modeDirect, 0, 0, ErrCategory},
105		"no mode":           {"water", "", 0, 0, ErrMode},
106		"unknown mode":      {"water", "both", 0, 0, ErrMode},
107		"negative goal":     {"water", modeDirect, -1, 0, ErrGoal},
108		"deadline now":      {"water", modeDirect, 0, now(), ErrDeadline},
109		"deadline past":     {"water", modeDirect, 0, now() - 1, ErrDeadline},
110		"deadline too far":  {"water", modeDirect, 0, now() + maxDeadlineDays*secondsPerDay + 1, ErrDeadline},
111		"deadline negative": {"water", modeDirect, 0, -1, ErrDeadline},
112	} {
113		if !panicsWith(func() { checkCampaignTerms(c.category, c.mode, c.goal, c.deadline) }, c.err) {
114			t.Errorf("%s: not refused with %s", name, c.err)
115		}
116	}
117}
118
119func TestCheckCampaignText(t *testing.T) {
120	text := checkCampaignText(" Clean water ", " A pump. ", "", "")
121	if text.title != "Clean water" || text.description != "A pump." {
122		t.Errorf("checkCampaignText = %v", text)
123	}
124	for name, c := range map[string]struct {
125		title, description, cid, alt string
126		err                          Error
127	}{
128		"short title":       {"abc", "", "", "", ErrTitle},
129		"image in story":    {"Clean water", "![x](u)", "", "", ErrMarkup},
130		"photo without alt": {"Clean water", "", "QmYwAPJzv5CZsnA625s3Xf2nemtYgPpHdWEz79ojWnPbdG", "", ErrImage},
131	} {
132		if !panicsWith(func() { checkCampaignText(c.title, c.description, c.cid, c.alt) }, c.err) {
133			t.Errorf("%s: not refused with %s", name, c.err)
134		}
135	}
136}
137
138func TestCheckBeneficiary(t *testing.T) {
139	next := seqid.ID(7)
140	checkBeneficiary(testutils.TestAddress("beneficiary"), next)
141	handedOut := escrowAddr(3)
142	derived.Set(handedOut.String(), true)
143	defer derived.Remove(handedOut.String())
144	for name, a := range map[string]address{
145		"malformed":                 "g1notanaddress",
146		"in capitals":               address(strings.ToUpper(string(testutils.TestAddress("beneficiary")))),
147		"the realm":                 realmAddr(),
148		"slashed":                   slashedAddr(),
149		"the storage deposit":       depositAddr(),
150		"the registry":              registryAddr(),
151		"the registry's deposit":    registryDepositAddr(),
152		"an escrow handed out":      handedOut,
153		"the new campaign's escrow": escrowAddr(next),
154		"the new campaign's bond":   bondAddr(next),
155	} {
156		if !panicsWith(func() { checkBeneficiary(a, next) }, ErrBeneficiary) {
157			t.Errorf("%s: not refused", name)
158		}
159	}
160}
161
162func TestGetCampaignNotFound(t *testing.T) {
163	for _, id := range []string{"", "0", "042", "+1", " 1", "999999"} {
164		if !panicsWith(func() { GetCampaign(id) }, ErrNotFound) {
165			t.Errorf("GetCampaign(%q): not ErrNotFound", id)
166		}
167	}
168}
169
170// restoreCampaigns removes every campaign created after last from every tree. IDs
171// keep counting: the bank keeps the coins those campaigns' addresses got, so a later
172// test's campaigns get fresh addresses.
173func restoreCampaigns(last seqid.ID) {
174	for id := last + 1; id <= nextID; id++ {
175		v := campaigns.Get(id.Binary())
176		if v == nil {
177			continue
178		}
179		c := v.(*campaign)
180		key := id.Binary()
181		campaigns.Remove(key)
182		active.Remove(key)
183		activeByCategory.Remove(c.category + "/" + key)
184		byOrganizer.Remove(c.organizer.String() + "/" + key)
185		byBeneficiary.Remove(c.beneficiary.String() + "/" + key)
186		derived.Remove(escrowAddr(id).String())
187		derived.Remove(bondAddr(id).String())
188	}
189}