token_test.gno

5.61 Kb ยท 191 lines
  1package grc20
  2
  3import (
  4	"std"
  5	"testing"
  6
  7	"gno.land/p/demo/testutils"
  8	"gno.land/p/demo/uassert"
  9	"gno.land/p/demo/ufmt"
 10	"gno.land/p/demo/urequire"
 11)
 12
 13func TestTestImpl(t *testing.T) {
 14	bank, _ := NewToken("Dummy", "DUMMY", 4)
 15	urequire.False(t, bank == nil, "dummy should not be nil")
 16}
 17
 18func TestToken(t *testing.T) {
 19	var (
 20		alice = testutils.TestAddress("alice")
 21		bob   = testutils.TestAddress("bob")
 22		carl  = testutils.TestAddress("carl")
 23	)
 24
 25	bank, adm := NewToken("Dummy", "DUMMY", 6)
 26
 27	checkBalances := func(aliceEB, bobEB, carlEB uint64) {
 28		t.Helper()
 29		exp := ufmt.Sprintf("alice=%d bob=%d carl=%d", aliceEB, bobEB, carlEB)
 30		aliceGB := bank.BalanceOf(alice)
 31		bobGB := bank.BalanceOf(bob)
 32		carlGB := bank.BalanceOf(carl)
 33		got := ufmt.Sprintf("alice=%d bob=%d carl=%d", aliceGB, bobGB, carlGB)
 34		uassert.Equal(t, got, exp, "invalid balances")
 35	}
 36	checkAllowances := func(abEB, acEB, baEB, bcEB, caEB, cbEB uint64) {
 37		t.Helper()
 38		exp := ufmt.Sprintf("ab=%d ac=%d ba=%d bc=%d ca=%d cb=%s", abEB, acEB, baEB, bcEB, caEB, cbEB)
 39		abGB := bank.Allowance(alice, bob)
 40		acGB := bank.Allowance(alice, carl)
 41		baGB := bank.Allowance(bob, alice)
 42		bcGB := bank.Allowance(bob, carl)
 43		caGB := bank.Allowance(carl, alice)
 44		cbGB := bank.Allowance(carl, bob)
 45		got := ufmt.Sprintf("ab=%d ac=%d ba=%d bc=%d ca=%d cb=%s", abGB, acGB, baGB, bcGB, caGB, cbGB)
 46		uassert.Equal(t, got, exp, "invalid allowances")
 47	}
 48
 49	checkBalances(0, 0, 0)
 50	checkAllowances(0, 0, 0, 0, 0, 0)
 51
 52	urequire.NoError(t, adm.Mint(alice, 1000))
 53	urequire.NoError(t, adm.Mint(alice, 100))
 54	checkBalances(1100, 0, 0)
 55	checkAllowances(0, 0, 0, 0, 0, 0)
 56
 57	urequire.NoError(t, adm.Approve(alice, bob, 99999999))
 58	checkBalances(1100, 0, 0)
 59	checkAllowances(99999999, 0, 0, 0, 0, 0)
 60
 61	urequire.NoError(t, adm.Approve(alice, bob, 400))
 62	checkBalances(1100, 0, 0)
 63	checkAllowances(400, 0, 0, 0, 0, 0)
 64
 65	urequire.Error(t, adm.TransferFrom(alice, bob, carl, 100000000))
 66	checkBalances(1100, 0, 0)
 67	checkAllowances(400, 0, 0, 0, 0, 0)
 68
 69	urequire.NoError(t, adm.TransferFrom(alice, bob, carl, 100))
 70	checkBalances(1000, 0, 100)
 71	checkAllowances(300, 0, 0, 0, 0, 0)
 72
 73	urequire.Error(t, adm.SpendAllowance(alice, bob, 2000000))
 74	checkBalances(1000, 0, 100)
 75	checkAllowances(300, 0, 0, 0, 0, 0)
 76
 77	urequire.NoError(t, adm.SpendAllowance(alice, bob, 100))
 78	checkBalances(1000, 0, 100)
 79	checkAllowances(200, 0, 0, 0, 0, 0)
 80}
 81
 82func TestOverflow(t *testing.T) {
 83	alice := testutils.TestAddress("alice")
 84	bob := testutils.TestAddress("bob")
 85	tok, adm := NewToken("Dummy", "DUMMY", 6)
 86
 87	safeValue := uint64(1 << 62)
 88	urequire.NoError(t, adm.Mint(alice, safeValue))
 89	urequire.Equal(t, tok.BalanceOf(alice), safeValue)
 90
 91	err := adm.Mint(bob, safeValue)
 92	uassert.Error(t, err, "expected ErrOverflow")
 93}
 94
 95func TestTransferFromAtomicity(t *testing.T) {
 96	var (
 97		owner     = testutils.TestAddress("owner")
 98		spender   = testutils.TestAddress("spender")
 99		recipient = testutils.TestAddress("recipient")
100
101		invalidRecipient = std.Address("")
102	)
103
104	token, admin := NewToken("Test", "TEST", 6)
105
106	// owner has 100 tokens, spender has 50 allowance
107	initialBalance := uint64(100)
108	initialAllowance := uint64(50)
109
110	urequire.NoError(t, admin.Mint(owner, initialBalance))
111	urequire.NoError(t, admin.Approve(owner, spender, initialAllowance))
112
113	// transfer to an invalid address to force a transfer failure
114	transferAmount := uint64(30)
115	err := admin.TransferFrom(owner, spender, invalidRecipient, transferAmount)
116	uassert.Error(t, err, "transfer should fail due to invalid address")
117
118	ownerBalance := token.BalanceOf(owner)
119	uassert.Equal(t, ownerBalance, initialBalance, "owner balance should remain unchanged")
120
121	// check if allowance was incorrectly reduced
122	remainingAllowance := token.Allowance(owner, spender)
123	uassert.Equal(t, remainingAllowance, initialAllowance,
124		"allowance should not be reduced when transfer fails")
125}
126
127func TestMintOverflow(t *testing.T) {
128	alice := testutils.TestAddress("alice")
129	bob := testutils.TestAddress("bob")
130	tok, adm := NewToken("Dummy", "DUMMY", 6)
131
132	tests := []struct {
133		name           string
134		address        std.Address
135		amount         uint64
136		expectedError  error
137		expectedSupply uint64
138		description    string
139	}{
140		{
141			name:           "mint value larger than MaxUint64",
142			address:        alice,
143			amount:         MaxUint64 + 1000,
144			expectedError:  ErrOverflow,
145			expectedSupply: 0,
146			description:    "minting a value larger than MaxUint64 should fail with ErrOverflow",
147		},
148		{
149			name:           "mint safe value close to MaxUint64",
150			address:        alice,
151			amount:         MaxUint64 - 1000,
152			expectedError:  nil,
153			expectedSupply: MaxUint64 - 1000,
154			description:    "minting a value close to MaxUint64 should succeed",
155		},
156		{
157			name:           "mint small value",
158			address:        bob,
159			amount:         1000,
160			expectedError:  nil,
161			expectedSupply: MaxUint64,
162			description:    "minting a small value when close to MaxUint64 should succeed",
163		},
164		{
165			name:           "mint value that would exceed MaxUint64",
166			address:        bob,
167			amount:         1,
168			expectedError:  ErrOverflow,
169			expectedSupply: MaxUint64,
170			description:    "minting any value when at MaxUint64 should fail with ErrOverflow",
171		},
172	}
173
174	for _, tt := range tests {
175		t.Run(tt.name, func(t *testing.T) {
176			err := adm.Mint(tt.address, tt.amount)
177
178			if tt.expectedError != nil {
179				uassert.Error(t, err, tt.description)
180				if err.Error() != tt.expectedError.Error() {
181					t.Errorf("expected error %v, got %v", tt.expectedError, err)
182				}
183			} else {
184				uassert.NoError(t, err, tt.description)
185			}
186
187			totalSupply := tok.TotalSupply()
188			uassert.Equal(t, totalSupply, tt.expectedSupply, "totalSupply should match expected value")
189		})
190	}
191}