z_denied_reason_store_test.gno
1.85 Kb · 48 lines
1package impl
2
3import (
4 "errors"
5 "strings"
6 "testing"
7
8 "gno.land/p/nt/uassert/v0"
9 "gno.land/r/gov/dao"
10 "gno.land/r/gov/dao/memberstore/v0"
11)
12
13// Named z_* so it sorts after govdao_test.gno, whose TestUpgradeDaoImplementation
14// asserts a hard-coded proposal id. This builds its own GovDAO instance and
15// registers a status directly, so it never touches the shared one.
16
17type hugeErrExecutor struct{ msg string }
18
19func (e *hugeErrExecutor) Execute(cur realm) error { return errors.New(e.msg) }
20
21func (e *hugeErrExecutor) String() string { return "" }
22
23func (e *hugeErrExecutor) CreationRealm() string { return "gno.land/r/test/hugeerr" }
24
25// The denial reason is stored, not just shown. It is "execution failed: " plus
26// whatever error the proposal's executor returned, and the executor is
27// third-party code. Whoever executes the proposal pays the storage deposit for
28// it, and that need not be the person who wrote the executor.
29//
30// This has to read the stored value rather than the rendered page. The render
31// clamps to the same bound, so a page rendered from an unclamped store looks
32// exactly like one rendered from a clamped store — testing through Render would
33// pass whether or not the write is bounded.
34func TestDeniedReasonIsClampedBeforeStoring(cur realm, t *testing.T) {
35 g := NewGovDAO()
36 pid := dao.ProposalID(987654)
37 g.pss.Set(pid.String(), newProposalStatus([]string{memberstore.T1}))
38
39 g.ExecuteProposal(0, cur, pid, &hugeErrExecutor{msg: strings.Repeat("E", 50000)})
40
41 stored := g.pss.GetStatus(pid).DeniedReason
42 uassert.True(t, len(stored) < maxRenderedReason+64,
43 "the realm must not store a reason larger than it can display")
44 uassert.True(t, strings.Contains(stored, "… truncated"),
45 "a stored reason that was cut must say so")
46 uassert.True(t, strings.HasPrefix(stored, "execution failed: E"),
47 "the prefix and the start of the error must survive")
48}