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}