token_test.gno

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