multisig_test.gno
3.00 Kb · 111 lines
1package multisig
2
3import (
4 "strings"
5 "testing"
6
7 "gno.land/p/nt/avl/v0"
8 "gno.land/p/nt/testutils/v0"
9 "gno.land/p/nt/uassert/v0"
10)
11
12// reset clears package state between tests so each test is independent.
13func reset() {
14 owners = nil
15 proposals = nil
16 ownerCount = 0
17 threshold = 0
18 initialized = false
19 nextID = 0
20 owners = avl.NewTree()
21 proposals = avl.NewTree()
22}
23
24func TestSetupAndPropose(cur realm, t *testing.T) {
25 reset()
26
27 a := testutils.TestAddress("alice")
28 b := testutils.TestAddress("bob")
29 c := testutils.TestAddress("carol")
30 csv := a.String() + "," + b.String() + "," + c.String()
31
32 testing.SetRealm(testing.NewUserRealm(a))
33 Setup(cross(cur), csv, 2)
34
35 uassert.True(t, initialized, "should be initialized")
36 uassert.Equal(t, 3, ownerCount)
37 uassert.Equal(t, 2, threshold)
38
39 // alice (an owner) proposes
40 testing.SetRealm(testing.NewUserRealm(a))
41 id := Propose(cross(cur), "send funds to treasury")
42 uassert.Equal(t, 0, id)
43
44 // a non-owner cannot propose
45 dave := testutils.TestAddress("dave")
46 testing.SetRealm(testing.NewUserRealm(dave))
47 uassert.AbortsWithMessage(t, cur, errNotOwner.Error(), func() {
48 Propose(cross(cur), "sneaky proposal")
49 })
50}
51
52func TestApproveReachesThreshold(cur realm, t *testing.T) {
53 reset()
54
55 a := testutils.TestAddress("alice")
56 b := testutils.TestAddress("bob")
57 c := testutils.TestAddress("carol")
58 csv := a.String() + "," + b.String() + "," + c.String()
59
60 testing.SetRealm(testing.NewUserRealm(a))
61 Setup(cross(cur), csv, 2)
62
63 testing.SetRealm(testing.NewUserRealm(a))
64 id := Propose(cross(cur), "upgrade contract")
65
66 // first approval: still pending
67 testing.SetRealm(testing.NewUserRealm(a))
68 Approve(cross(cur), id)
69 v := proposals.Get("0")
70 p := v.(*proposal)
71 uassert.Equal(t, statePending.String(), p.state.String())
72 uassert.Equal(t, 1, p.approvals.Size())
73
74 // duplicate approval by same owner aborts
75 testing.SetRealm(testing.NewUserRealm(a))
76 uassert.AbortsWithMessage(t, cur, errDupApproval.Error(), func() {
77 Approve(cross(cur), id)
78 })
79
80 // second distinct approval hits threshold -> executed
81 testing.SetRealm(testing.NewUserRealm(b))
82 Approve(cross(cur), id)
83 uassert.Equal(t, stateExecuted.String(), p.state.String())
84 uassert.Equal(t, 2, p.approvals.Size())
85
86 // approving an executed proposal aborts
87 testing.SetRealm(testing.NewUserRealm(c))
88 uassert.AbortsWithMessage(t, cur, errExecuted.Error(), func() {
89 Approve(cross(cur), id)
90 })
91}
92
93func TestRenderShows(cur realm, t *testing.T) {
94 reset()
95
96 a := testutils.TestAddress("alice")
97 b := testutils.TestAddress("bob")
98 csv := a.String() + "," + b.String()
99
100 testing.SetRealm(testing.NewUserRealm(a))
101 Setup(cross(cur), csv, 2)
102
103 testing.SetRealm(testing.NewUserRealm(a))
104 Propose(cross(cur), "hello world")
105
106 out := Render("")
107 uassert.True(t, strings.Contains(out, "Threshold:"), "render shows threshold")
108 uassert.True(t, strings.Contains(out, "2 of 2"), "render shows M-of-N")
109 uassert.True(t, strings.Contains(out, "hello world"), "render shows proposal description")
110 uassert.True(t, strings.Contains(out, "Pending"), "render shows state")
111}