Skip to content Search Apps Documentation Source Content File Folder Download Copy Actions State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

Community realm. Read the code first. Community realm, deployed by its author. Read the code before you interact or send coins.

coin_test.gno

3.75 Kb · 129 lines
  1package coin
  2
  3import (
  4	"strings"
  5	"testing"
  6
  7	"gno.land/p/nt/seqid/v0"
  8	"gno.land/p/nt/testutils/v0"
  9	"gno.land/p/nt/uassert/v0"
 10	"gno.land/p/nt/urequire/v0"
 11)
 12
 13var fullPolicy = Policy{
 14	Mint:  "1 per distinct replier",
 15	Sink:  "burned to pin a thread",
 16	Buyer: "anyone who wants placement",
 17}
 18
 19// newTestCoin builds a Coin from a test. The same-realm cross promotes the
 20// test's EOA-origin cur into a code realm frame, which is what grc20.NewToken
 21// requires: it is the shape grc20's own tests use (vendor/.../token_test.gno).
 22func newTestCoin(t *testing.T, policy Policy, id seqid.ID, rlm realm) (c *Coin) {
 23	t.Helper()
 24	func(cur realm) {
 25		c = New("Test Points", "TEST", 0, id, policy, 0, cur)
 26	}(cross(rlm))
 27	return
 28}
 29
 30func TestPolicyValid(t *testing.T) {
 31	tests := []struct {
 32		name string
 33		p    Policy
 34		want bool
 35	}{
 36		{"complete", fullPolicy, true},
 37		{"no mint rule", Policy{Sink: "s", Buyer: "b"}, false},
 38		{"no sink", Policy{Mint: "m", Buyer: "b"}, false},
 39		{"no buyer", Policy{Mint: "m", Sink: "s"}, false},
 40		{"empty", Policy{}, false},
 41	}
 42	for _, tt := range tests {
 43		uassert.Equal(t, tt.want, tt.p.Valid(), tt.name)
 44	}
 45}
 46
 47// New's refusal is asserted with AbortsContains and not PanicsContains: the
 48// constructor runs behind a same-realm cross (the frame grc20.NewToken
 49// requires), and a panic raised across a crossing call is an abort that no
 50// recover() in the caller can catch.
 51func TestNewRefusesAnIncompletePolicy(cur realm, t *testing.T) {
 52	uassert.AbortsContains(t, cur, "mint rule, a sink and a buyer", func() {
 53		newTestCoin(t, Policy{Mint: "m", Sink: "s"}, 0, cur)
 54	})
 55}
 56
 57func TestEarnAndSpendMoveSupplyInOppositeDirections(cur realm, t *testing.T) {
 58	c := newTestCoin(t, fullPolicy, 1, cur)
 59	alice := testutils.TestAddress("alice")
 60
 61	c.Earn(alice, 10)
 62	uassert.Equal(t, int64(10), c.BalanceOf(alice))
 63	uassert.Equal(t, int64(10), c.Supply())
 64
 65	c.Spend(alice, 4)
 66	uassert.Equal(t, int64(6), c.BalanceOf(alice))
 67	uassert.Equal(t, int64(6), c.Supply())
 68
 69	// The flows stay visible after the fact, which the supply alone cannot
 70	// show: 6 in supply could be 6 earned and nothing burned.
 71	uassert.Equal(t, int64(10), c.Earned())
 72	uassert.Equal(t, int64(4), c.Spent())
 73}
 74
 75func TestEarnOfNothingIsANoOp(cur realm, t *testing.T) {
 76	c := newTestCoin(t, fullPolicy, 2, cur)
 77	alice := testutils.TestAddress("alice")
 78
 79	c.Earn(alice, 0)
 80	c.Earn(alice, -5)
 81	uassert.Equal(t, int64(0), c.Supply())
 82	uassert.Equal(t, int64(0), c.Earned())
 83	uassert.Equal(t, 0, c.Holders())
 84}
 85
 86func TestSpendNamesBothNumbersWhenShort(cur realm, t *testing.T) {
 87	c := newTestCoin(t, fullPolicy, 3, cur)
 88	alice := testutils.TestAddress("alice")
 89	c.Earn(alice, 2)
 90
 91	uassert.PanicsContains(t, cur, "balance 2 is short of 5", func() {
 92		c.Spend(alice, 5)
 93	})
 94	uassert.PanicsContains(t, cur, "must be positive", func() {
 95		c.Spend(alice, 0)
 96	})
 97	uassert.Equal(t, int64(2), c.BalanceOf(alice))
 98}
 99
100func TestRenderCarriesTheThreeDeclarations(cur realm, t *testing.T) {
101	c := newTestCoin(t, fullPolicy, 4, cur)
102	c.Earn(testutils.TestAddress("alice"), 7)
103	c.Spend(testutils.TestAddress("alice"), 3)
104
105	out := c.Render()
106	for _, want := range []string{
107		"Test Points",
108		"TEST",
109		fullPolicy.Mint,
110		fullPolicy.Sink,
111		fullPolicy.Buyer,
112	} {
113		uassert.True(t, strings.Contains(out, want), "render is missing "+want)
114	}
115	// 4 in supply, 7 earned, 3 burned, 1 holder.
116	uassert.True(t, strings.Contains(out, "| 4 | 7 | 3 | 1 |"), "render is missing the flow row: "+out)
117}
118
119func TestTokenIsAnOrdinaryGRC20(cur realm, t *testing.T) {
120	c := newTestCoin(t, fullPolicy, 5, cur)
121	alice := testutils.TestAddress("alice")
122	c.Earn(alice, 3)
123
124	tok := c.Token()
125	urequire.False(t, tok == nil, "token should not be nil")
126	uassert.Equal(t, "TEST", tok.GetSymbol())
127	uassert.Equal(t, int64(3), tok.TotalSupply())
128	uassert.Equal(t, int64(3), tok.BalanceOf(alice))
129}