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.

moderation_test.gno

6.27 Kb · 163 lines
  1package bolo
  2
  3import (
  4	"chain"
  5	"chain/banker"
  6	"strings"
  7	"testing"
  8
  9	"gno.land/p/nt/seqid/v0"
 10	"gno.land/p/nt/testutils/v0"
 11)
 12
 13// The helpers' tests come first: a write's test that panics through a crossing call
 14// ends the package's unit tests.
 15
 16// TestBookSlash: a slash takes the bond and only the bond, once, while the campaign
 17// is open or within BondHold of its close, settled or not (API §3.5, INV-7).
 18func TestBookSlash(t *testing.T) {
 19	c := testCampaign(9801, modeDirect, 0)
 20	if !panicsWith(func() { bookSlash(c) }, ErrNoBond) {
 21		t.Errorf("no bond: not ErrNoBond")
 22	}
 23	testing.IssueCoins(bondAddr(c.id), chain.NewCoins(chain.NewCoin("ugnot", 1000+300))) // the deposit, the bond
 24	c.state.bond = 300
 25	if got := bookSlash(c); got != 300 || !c.state.bondSlashed {
 26		t.Errorf("open: slashed %d, flagged %t; want the bond, 300", got, c.state.bondSlashed)
 27	}
 28	if !panicsWith(func() { bookSlash(c) }, ErrBondSlashed) {
 29		t.Errorf("a second slash: not ErrBondSlashed")
 30	}
 31
 32	for i, status := range []string{statusClosed, statusSettled} {
 33		d := testCampaign(seqid.ID(9802+i), modeDirect, 0)
 34		testing.IssueCoins(bondAddr(d.id), chain.NewCoins(chain.NewCoin("ugnot", 300)))
 35		d.state.bond, d.state.status, d.state.closedAt = 300, status, now()-d.params.BondHold
 36		if !panicsWith(func() { bookSlash(d) }, ErrHoldEnded) {
 37			t.Errorf("%s, the hold just ended: not ErrHoldEnded", status)
 38		}
 39		d.state.closedAt++
 40		if got := bookSlash(d); got != 300 {
 41			t.Errorf("%s, a second before the hold ends: slashed %d", status, got)
 42		}
 43	}
 44
 45	e := testCampaign(9804, modeDirect, 0)
 46	testing.IssueCoins(bondAddr(e.id), chain.NewCoins(chain.NewCoin("ugnot", 200)))
 47	e.state.bond = 300
 48	if !panicsWith(func() { bookSlash(e) }, ErrBooksMismatch) {
 49		t.Errorf("a bond address holding less than the bond: not ErrBooksMismatch")
 50	}
 51	if e.state.bondSlashed {
 52		t.Errorf("a refused slash marked the bond slashed")
 53	}
 54}
 55
 56// TestCheckNotice: "" clears, except on a delisted campaign; any other notice is
 57// normalized and holds 1–280 characters (API §2.3, §3.5).
 58func TestCheckNotice(t *testing.T) {
 59	c := testCampaign(9805, modeEscrow, 0)
 60	if got := checkNotice(c, ""); got != "" {
 61		t.Errorf(`"" on a listed campaign: %q`, got)
 62	}
 63	if got := checkNotice(c, "  Unverified\tclaims "); got != "Unverified claims" {
 64		t.Errorf("normalized: %q", got)
 65	}
 66	for name, notice := range map[string]string{
 67		"blank":    " \t ",
 68		"too long": strings.Repeat("a", noticeMax+1),
 69	} {
 70		if !panicsWith(func() { checkNotice(c, notice) }, ErrNotice) {
 71			t.Errorf("%s: not ErrNotice", name)
 72		}
 73	}
 74	c.state.listed = false
 75	if !panicsWith(func() { checkNotice(c, "") }, ErrNotice) {
 76		t.Errorf(`"" on a delisted campaign: not ErrNotice`)
 77	}
 78	if got := checkNotice(c, "Fraud reported"); got != "Fraud reported" {
 79		t.Errorf("a delisted campaign's new notice: %q", got)
 80	}
 81}
 82
 83// TestDelist delists as the admin, straight from the test's body: off the active
 84// indexes, with the notice; then again, which replaces the notice and slashes, moving
 85// the bond and only the bond to the slashed address (API §3.5, INV-7).
 86func TestDelist(cur realm, t *testing.T) {
 87	rb := banker.NewReadonlyBanker()
 88	c := testCampaign(9806, modeEscrow, 0)
 89	id, unstore := storeCampaign(c)
 90	defer unstore()
 91	testing.IssueCoins(bondAddr(c.id), chain.NewCoins(chain.NewCoin("ugnot", 1000+300)))
 92	c.state.bond = 300
 93	slashed, key := rb.GetCoin(slashedAddr(), "ugnot"), c.id.Binary()
 94
 95	testing.SetRealm(testing.NewUserRealm(admin))
 96	Delist(cross(cur), id, " Under review ", false)
 97	if s := c.state; s.listed || s.notice != "Under review" || s.bondSlashed || active.Has(key) || activeByCategory.Has(c.category+"/"+key) {
 98		t.Errorf("delisted: listed %t, notice %q, slashed %t, active %t", s.listed, s.notice, s.bondSlashed, active.Has(key))
 99	}
100	Delist(cross(cur), id, "Fraud reported", true)
101	if s := c.state; s.notice != "Fraud reported" || !s.bondSlashed {
102		t.Errorf("delisted again: notice %q, slashed %t", s.notice, s.bondSlashed)
103	}
104	if got := rb.GetCoin(slashedAddr(), "ugnot") - slashed; got != 300 {
105		t.Errorf("the slashed address got %d, want the bond, 300", got)
106	}
107	if got := rb.GetCoin(bondAddr(c.id), "ugnot"); got != 1000 {
108		t.Errorf("the bond address holds %d, want the deposit, 1000", got)
109	}
110}
111
112// TestRelist: back on the lists, and in the active indexes only while still open; the
113// notice stays (API §3.5).
114func TestRelist(cur realm, t *testing.T) {
115	open := testCampaign(9807, modeEscrow, 0)
116	closed := testCampaign(9808, modeEscrow, 0)
117	closed.state.status, closed.state.closedAt = statusClosed, now()
118	testing.SetRealm(testing.NewUserRealm(admin))
119	for _, c := range []*campaign{open, closed} {
120		id, unstore := storeCampaign(c)
121		Delist(cross(cur), id, "Under review", false)
122		Relist(cross(cur), id)
123		key := c.id.Binary()
124		if !c.state.listed || c.state.notice != "Under review" || active.Has(key) != (c == open) || activeByCategory.Has(c.category+"/"+key) != (c == open) {
125			t.Errorf("%s, relisted: listed %t, notice %q, active %t", c.state.status, c.state.listed, c.state.notice, active.Has(key))
126		}
127		unstore()
128	}
129}
130
131// TestSetNotice: a notice without delisting, normalized, then cleared (API §3.5).
132func TestSetNotice(cur realm, t *testing.T) {
133	c := testCampaign(9809, modeEscrow, 0)
134	id, unstore := storeCampaign(c)
135	defer unstore()
136	testing.SetRealm(testing.NewUserRealm(admin))
137	SetNotice(cross(cur), id, " Unverified\tclaims ")
138	if c.state.notice != "Unverified claims" || !c.state.listed || !active.Has(c.id.Binary()) {
139		t.Errorf("noticed: %q, listed %t", c.state.notice, c.state.listed)
140	}
141	SetNotice(cross(cur), id, "")
142	if c.state.notice != "" {
143		t.Errorf("cleared: %q", c.state.notice)
144	}
145}
146
147// TestHideMessage: the view blanks the message and keeps the receipt — its donor, its
148// amount; the stored text stays (API §3.5).
149func TestHideMessage(cur realm, t *testing.T) {
150	c := testCampaign(9810, modeEscrow, 0)
151	id, unstore := storeCampaign(c)
152	defer unstore()
153	donor := testutils.TestAddress("donor")
154	c.receipts.Set(seqid.ID(1).Binary(), &receipt{seq: 1, donor: donor, amount: 500, message: "Courage"})
155	testing.SetRealm(testing.NewUserRealm(admin))
156	HideMessage(cross(cur), id, 1)
157	if v := GetReceipt(id, 1); v.Message != "" || !v.MessageHidden || v.Amount != 500 || v.Donor != donor {
158		t.Errorf("hidden: %v", v)
159	}
160	if r := receiptOf(c, 1); r.message != "Courage" {
161		t.Errorf("the stored text: %q", r.message)
162	}
163}