close_test.gno
5.51 Kb · 154 lines
1package bolo
2
3import (
4 "testing"
5
6 "gno.land/p/nt/testutils/v0"
7)
8
9// TestClose walks each of Close's branches. Before each call, CanClose names the
10// reason Close then records (API §4); the refusals are in txtar (organizer.txtar).
11func TestClose(cur realm, t *testing.T) {
12 closed := func(c *campaign, reason string, at int64) bool {
13 s := c.state
14 return s.status == statusClosed && s.closeReason == reason && s.closedAt == at && !active.Has(c.id.Binary()) &&
15 !activeByCategory.Has(c.category+"/"+c.id.Binary())
16 }
17
18 // The organizer closes an open campaign, now.
19 c := testCampaign(9201, modeEscrow, 0)
20 id, unstore := storeCampaign(c)
21 defer unstore()
22 if ok, why := CanClose(id, c.organizer); !ok || why != reasonOrganizer {
23 t.Errorf("CanClose(organizer) = %t, %q", ok, why)
24 }
25 testing.SetRealm(testing.NewUserRealm(c.organizer))
26 Close(cross(cur), id)
27 if !closed(c, reasonOrganizer, now()) {
28 t.Errorf("organizer: %v", *c.state)
29 }
30 if ok, why := CanClose(id, c.organizer); ok || why != statusClosed {
31 t.Errorf("CanClose once closed = %t, %q", ok, why)
32 }
33
34 // Past dormancy, anyone closes it for dormancy, its organizer too (Q7).
35 d := testCampaign(9202, modeEscrow, 0)
36 idD, unstoreD := storeCampaign(d)
37 defer unstoreD()
38 e := testCampaign(9203, modeEscrow, 0)
39 idE, unstoreE := storeCampaign(e)
40 defer unstoreE()
41 testing.SkipHeights(90 * heightsPerDay)
42 if ok, why := CanClose(idD, passerby); !ok || why != reasonDormant {
43 t.Errorf("CanClose(passerby), dormant = %t, %q", ok, why)
44 }
45 testing.SetRealm(testing.NewUserRealm(passerby))
46 Close(cross(cur), idD)
47 if !closed(d, reasonDormant, now()) {
48 t.Errorf("passerby, dormant: %v", *d.state)
49 }
50 if ok, why := CanClose(idE, e.organizer); !ok || why != reasonDormant {
51 t.Errorf("CanClose(organizer), dormant = %t, %q", ok, why)
52 }
53 testing.SetRealm(testing.NewUserRealm(e.organizer))
54 Close(cross(cur), idE)
55 if !closed(e, reasonDormant, now()) {
56 t.Errorf("organizer, dormant: %v", *e.state)
57 }
58
59 // Past its deadline: closed at the deadline by whoever calls first; a second
60 // call changes nothing, and fails nothing.
61 f := testCampaign(9204, modeEscrow, now()+2*secondsPerDay)
62 idF, unstoreF := storeCampaign(f)
63 defer unstoreF()
64 g := testCampaign(9205, modeEscrow, now()+2*secondsPerDay)
65 idG, unstoreG := storeCampaign(g)
66 defer unstoreG()
67 testing.SetRealm(testing.NewUserRealm(g.organizer))
68 Close(cross(cur), idG)
69 closedG := now()
70 testing.SkipHeights(3 * heightsPerDay)
71 if ok, why := CanClose(idF, passerby); !ok || why != reasonDeadline {
72 t.Errorf("CanClose(passerby), deadline = %t, %q", ok, why)
73 }
74 testing.SetRealm(testing.NewUserRealm(passerby))
75 Close(cross(cur), idF)
76 if !closed(f, reasonDeadline, f.deadline) {
77 t.Errorf("passerby, deadline: %v", *f.state)
78 }
79 Close(cross(cur), idF)
80 if !closed(f, reasonDeadline, f.deadline) {
81 t.Errorf("a second close changed it: %v", *f.state)
82 }
83 // One the organizer closed before its deadline keeps its close after it.
84 Close(cross(cur), idG)
85 if !closed(g, reasonOrganizer, closedG) {
86 t.Errorf("closed before its deadline, then housekept: %v", *g.state)
87 }
88}
89
90// TestDormancy: dormancy counts from the latest of creation, the last gift and the
91// last update, so an update resets it (API §3.1).
92func TestDormancy(cur realm, t *testing.T) {
93 c := testCampaign(9206, modeEscrow, 0)
94 id, unstore := storeCampaign(c)
95 defer unstore()
96 testing.SkipHeights(80 * heightsPerDay)
97 testing.SetRealm(testing.NewUserRealm(c.organizer))
98 PostUpdate(cross(cur), id, "Still here.")
99 testing.SkipHeights(90*heightsPerDay - 1)
100 if ok, why := CanClose(id, passerby); ok || why != closeNotYet {
101 t.Errorf("a height before 90 days from the update: %t, %q", ok, why)
102 }
103 testing.SkipHeights(1)
104 if ok, why := CanClose(id, passerby); !ok || why != reasonDormant {
105 t.Errorf("90 days from the update: %t, %q", ok, why)
106 }
107 c.state.lastDonationAt = now()
108 if ok, why := CanClose(id, passerby); ok || why != closeNotYet {
109 t.Errorf("right after a gift: %t, %q", ok, why)
110 }
111}
112
113func TestCanClose(t *testing.T) {
114 organizer := testutils.TestAddress("organizer")
115 open := testCampaign(9211, modeEscrow, 0)
116 dormant := testCampaign(9212, modeEscrow, 0)
117 dormant.createdAt = now() - 90*secondsPerDay
118 passed := testCampaign(9213, modeEscrow, now()-1)
119 both := testCampaign(9214, modeEscrow, now()-1)
120 both.createdAt = now() - 91*secondsPerDay
121 recorded := testCampaign(9215, modeEscrow, now()-1)
122 recorded.state.status = statusClosed
123 shut := testCampaign(9216, modeEscrow, 0)
124 shut.state.status = statusClosed
125 settled := testCampaign(9217, modeEscrow, 0)
126 settled.state.status = statusSettled
127 for _, k := range []struct {
128 name string
129 c *campaign
130 caller address
131 ok bool
132 why string
133 }{
134 {"open, organizer", open, organizer, true, reasonOrganizer},
135 {"open, passerby", open, passerby, false, closeNotYet},
136 {"dormant, passerby", dormant, passerby, true, reasonDormant},
137 {"dormant, organizer", dormant, organizer, true, reasonDormant},
138 {"deadline passed, unrecorded", passed, passerby, true, reasonDeadline},
139 {"deadline passed and dormant", both, organizer, true, reasonDeadline},
140 {"deadline recorded", recorded, passerby, false, statusClosed},
141 {"closed", shut, organizer, false, statusClosed},
142 {"settled", settled, organizer, false, statusClosed},
143 } {
144 id, unstore := storeCampaign(k.c)
145 ok, why := CanClose(id, k.caller)
146 unstore()
147 if ok != k.ok || why != k.why {
148 t.Errorf("%s: CanClose = %t, %q, want %t, %q", k.name, ok, why, k.ok, k.why)
149 }
150 }
151 if !panicsWith(func() { CanClose("042", organizer) }, ErrNotFound) {
152 t.Errorf("CanClose(\"042\"): not ErrNotFound")
153 }
154}