Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(tm2): Add additional unit tests for tm2/pkg/std #2739

Closed
wants to merge 11 commits into from
122 changes: 122 additions & 0 deletions tm2/pkg/std/gasprice_test.go
thehowl marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
package std

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestParseGasPrice(t *testing.T) {
t.Parallel()

testCases := []struct {
name string
input string
expected GasPrice
hasError bool
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

better errorIs / errorContains

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

}{
{
name: "Valid case 10foo/1gas",
input: "10foo/1gas",
expected: GasPrice{Gas: 1, Price: Coin{Denom: "foo", Amount: 10}},
hasError: false,
},
{
name: "Valid case 100bar/2gas",
input: "100bar/2gas",
expected: GasPrice{Gas: 2, Price: Coin{Denom: "bar", Amount: 100}},
hasError: false,
},
{
name: "Valid case 5coin/0gas",
input: "5coin/0gas",
expected: GasPrice{Gas: 0, Price: Coin{Denom: "coin", Amount: 5}},
hasError: false,
},
{
name: "Invalid case",
input: "invalid",
expected: GasPrice{},
hasError: true,
},
{
name: "Invalid denom case",
input: "10foo/1coin",
expected: GasPrice{},
hasError: true,
},
}

for _, tc := range testCases {
tc := tc

t.Run(tc.name, func(t *testing.T) {
t.Parallel()

result, err := ParseGasPrice(tc.input)
if tc.hasError {
assert.True(t, err != nil, "expected error but got none")
} else {
assert.Nil(t, err, "unexpected error")
assert.Equal(t, result, tc.expected)
}
})
}
}

func TestParseGasPrices(t *testing.T) {
t.Parallel()

testCases := []struct {
name string
input string
expected []GasPrice
hasError bool
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

}{
{
name: "Valid case 10foo/1gas and 5bar/2gas",
input: "10foo/1gas;5bar/2gas",
expected: []GasPrice{
{Gas: 1, Price: Coin{Denom: "foo", Amount: 10}},
{Gas: 2, Price: Coin{Denom: "bar", Amount: 5}},
},
hasError: false,
},
{
name: "Valid case 5coin/0gas",
input: "5coin/0gas",
expected: []GasPrice{
{Gas: 0, Price: Coin{Denom: "coin", Amount: 5}},
},
hasError: false,
},
{
name: "Invalid case",
input: "invalid",
expected: nil,
hasError: true,
},
{
name: "Invalid denom case 10foo/1coin and 5bar/2gas",
input: "10foo/1coin;5bar/2gas",
expected: nil,
hasError: true,
},
}

for _, tc := range testCases {
tc := tc

t.Run(tc.name, func(t *testing.T) {
t.Parallel()

result, err := ParseGasPrices(tc.input)
if tc.hasError {
assert.True(t, err != nil, "expected error but got none")
} else {
assert.Nil(t, err, "unexpected error")
assert.Equal(t, result, tc.expected)
}
})
}
}
216 changes: 216 additions & 0 deletions tm2/pkg/std/tx_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
package std

import (
"testing"

"github.com/gnolang/gno/tm2/pkg/crypto"
"github.com/gnolang/gno/tm2/pkg/crypto/ed25519"
"github.com/gnolang/gno/tm2/pkg/crypto/multisig"
"github.com/stretchr/testify/require"
)

// Mock implementations of Msg interfaces
type mockMsg struct {
caller crypto.Address
msgType string
}

func (m mockMsg) ValidateBasic() error {
return nil
}

func (m mockMsg) GetSignBytes() []byte {
return nil
}

func (m mockMsg) GetSigners() []crypto.Address {
return []crypto.Address{m.caller}
}

func (m mockMsg) Route() string {
return ""
}

func (m mockMsg) Type() string {
return m.msgType
}

func TestNewTx(t *testing.T) {
t.Parallel()

addr, _ := crypto.AddressFromBech32("g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5")
msgs := []Msg{
mockMsg{
caller: addr,
},
}

fee := NewFee(1000, Coin{Denom: "atom", Amount: 10})

sigs := []Signature{
{
Signature: []byte{0x00},
},
}

memo := "test memo"

tx := NewTx(msgs, fee, sigs, memo)
require.Equal(t, msgs, tx.GetMsgs())
require.Equal(t, fee, tx.Fee)
require.Equal(t, sigs, tx.GetSignatures())
require.Equal(t, memo, tx.GetMemo())
}

func Test_ValidateBasic(t *testing.T) {
t.Parallel()

addr, _ := crypto.AddressFromBech32("g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5")
msgs := []Msg{
mockMsg{
caller: addr,
},
}

testCases := []struct {
name string
tx Tx
expectedError string
}{
{
name: "Valid case",
tx: NewTx(msgs, NewFee(maxGasWanted, Coin{Denom: "atom", Amount: 10}), []Signature{{Signature: []byte{0x00}}}, "test memo"),
expectedError: "",
},
{
name: "Invalid gas case",
tx: NewTx(msgs, NewFee(maxGasWanted+1, Coin{Denom: "atom", Amount: 10}), []Signature{{Signature: []byte{0x00}}}, "test memo"),
expectedError: "expected gas overflow error",
},
{
name: "Invalid fee case",
tx: NewTx(msgs, NewFee(1000, Coin{Denom: "atom", Amount: -10}), []Signature{{Signature: []byte{0x00}}}, "test memo"),
expectedError: "expected insufficient fee error",
},
{
name: "No signatures case",
tx: NewTx(msgs, NewFee(maxGasWanted, Coin{Denom: "atom", Amount: 10}), []Signature{}, "test memo"),
expectedError: "expected no signatures error",
},
{
name: "Wrong number of signers case",
tx: NewTx(msgs, NewFee(maxGasWanted, Coin{Denom: "atom", Amount: 10}), []Signature{{Signature: []byte{0x00}}, {Signature: []byte{0x01}}}, "test memo"),
expectedError: "expected wrong number of signers error",
},
}

for _, tc := range testCases {
tc := tc

t.Run(tc.name, func(t *testing.T) {
t.Parallel()

err := tc.tx.ValidateBasic()
if tc.expectedError == "" {
require.NoError(t, err)
} else {
require.Error(t, err, tc.expectedError)
}
})
}
}

func Test_CountSubKeys(t *testing.T) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why underscore?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

t.Parallel()

// Single key case
pubKey := ed25519.GenPrivKey().PubKey()
require.Equal(t, 1, CountSubKeys(pubKey))

// Multi-sig case
pubKeys := []crypto.PubKey{ed25519.GenPrivKey().PubKey(), ed25519.GenPrivKey().PubKey()}
multisigPubKey := multisig.NewPubKeyMultisigThreshold(2, pubKeys)
require.Equal(t, len(pubKeys), CountSubKeys(multisigPubKey))
}

func Test_GetSigners(t *testing.T) {
t.Parallel()

addr, _ := crypto.AddressFromBech32("g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5")
addr2, _ := crypto.AddressFromBech32("g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj")

testCases := []struct {
name string
msgs []Msg
expected []crypto.Address
}{
{
name: "Single signer case",
msgs: []Msg{
mockMsg{
caller: addr,
msgType: "call",
},
},
expected: []crypto.Address{addr},
},
{
name: "Duplicate signers case",
msgs: []Msg{
mockMsg{
caller: addr,
msgType: "send",
},
mockMsg{
caller: addr,
msgType: "send",
},
},
expected: []crypto.Address{addr},
},
{
name: "Multiple unique signers case",
msgs: []Msg{
mockMsg{
caller: addr,
msgType: "call",
},
mockMsg{
caller: addr2,
msgType: "run",
},
},
expected: []crypto.Address{
addr,
addr2,
},
},
}

for _, tc := range testCases {
tc := tc

t.Run(tc.name, func(t *testing.T) {
t.Parallel()

tx := NewTx(tc.msgs, Fee{}, []Signature{}, "")
require.Equal(t, tc.expected, tx.GetSigners())
})
}
}

func Test_GetSignBytes(t *testing.T) {
t.Parallel()

msgs := []Msg{}
fee := NewFee(1000, Coin{Denom: "atom", Amount: 10})
sigs := []Signature{}
tx := NewTx(msgs, fee, sigs, "test memo")
chainID := "test-chain"
accountNumber := uint64(1)
sequence := uint64(1)

signBytes, err := tx.GetSignBytes(chainID, accountNumber, sequence)
require.NoError(t, err)
require.NotEmpty(t, signBytes)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be a golden test (match signBytes against a known example output)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

}
Loading