udao_test.gno
3.04 Kb · 100 lines
1package udao
2
3import (
4 "testing"
5
6 "gno.land/p/nt/uassert/v0"
7)
8
9// stubConstraint is a Constraint whose verdict is fixed at construction.
10type stubConstraint struct {
11 ok bool
12 reason string
13 desc string
14}
15
16func (c stubConstraint) Validate() (bool, string) { return c.ok, c.reason }
17func (c stubConstraint) Description() string { return c.desc }
18
19// stubProposal is a Proposal carrying an arbitrary constraint list.
20type stubProposal struct {
21 title, body string
22 constraints []Constraint
23}
24
25func (p stubProposal) Title() string { return p.title }
26func (p stubProposal) Body() string { return p.body }
27func (p stubProposal) Constraints() []Constraint { return p.constraints }
28
29func TestValidateConstraintsAllMet(t *testing.T) {
30 p := stubProposal{constraints: []Constraint{
31 stubConstraint{ok: true},
32 stubConstraint{ok: true},
33 }}
34
35 ok, reasons := ValidateConstraints(p)
36 uassert.True(t, ok, "every constraint met")
37 uassert.Equal(t, 0, len(reasons))
38}
39
40func TestValidateConstraintsNoConstraints(t *testing.T) {
41 // A proposal with no constraints is vacuously valid.
42 ok, reasons := ValidateConstraints(stubProposal{})
43 uassert.True(t, ok, "no constraints means nothing unmet")
44 uassert.Equal(t, 0, len(reasons))
45}
46
47func TestValidateConstraintsCollectsEveryFailure(t *testing.T) {
48 p := stubProposal{constraints: []Constraint{
49 stubConstraint{ok: false, reason: "quorum not reached"},
50 stubConstraint{ok: true, reason: "ignored when valid"},
51 stubConstraint{ok: false, reason: "voting still open"},
52 }}
53
54 ok, reasons := ValidateConstraints(p)
55 uassert.False(t, ok, "one unmet constraint invalidates the proposal")
56 // It reports *all* failures, not just the first, and in order.
57 uassert.Equal(t, 2, len(reasons))
58 uassert.Equal(t, "quorum not reached", reasons[0])
59 uassert.Equal(t, "voting still open", reasons[1])
60}
61
62func TestValidateConstraintsIgnoresReasonWhenValid(t *testing.T) {
63 p := stubProposal{constraints: []Constraint{
64 stubConstraint{ok: true, reason: "should not be collected"},
65 }}
66
67 ok, reasons := ValidateConstraints(p)
68 uassert.True(t, ok)
69 uassert.Equal(t, 0, len(reasons))
70}
71
72// TestProposalStateValues pins the iota block: these states are likely to be
73// persisted or compared numerically, so inserting one in the middle is breaking.
74func TestProposalStateValues(t *testing.T) {
75 cases := []struct {
76 name string
77 got ProposalState
78 want int
79 }{
80 {"Pending", Pending, 0},
81 {"Active", Active, 1},
82 {"Passed", Passed, 2},
83 {"Rejected", Rejected, 3},
84 {"Executed", Executed, 4},
85 {"Expired", Expired, 5},
86 }
87 for _, c := range cases {
88 uassert.Equal(t, c.want, int(c.got), c.name)
89 }
90}
91
92// TestProposalStatusZeroValue documents that a zero ProposalStatus reads as a
93// Pending proposal with no recorded votes.
94func TestProposalStatusZeroValue(t *testing.T) {
95 var s ProposalStatus
96 uassert.Equal(t, int(Pending), int(s.State))
97 uassert.True(t, s.YeaPercentage == 0.0, "no yea votes recorded")
98 uassert.True(t, s.NayPercentage == 0.0, "no nay votes recorded")
99 uassert.True(t, s.NonVoterPercentage == 0.0, "no non-voters recorded")
100}