diff --git a/types/account_test.go b/types/account_test.go new file mode 100644 index 000000000..aa222ee7e --- /dev/null +++ b/types/account_test.go @@ -0,0 +1,132 @@ +package types_test + +import ( + "encoding/hex" + "math/rand" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/tendermint/tendermint/crypto/ed25519" + + "github.com/cosmos/cosmos-sdk/types" +) + +var invalidstrs = []string{ + "", + "hello, world!", + "0xAA", + "AAA", + types.Bech32PrefixAccAddr + "AB0C", + types.Bech32PrefixAccPub + "1234", + types.Bech32PrefixValAddr + "5678", + types.Bech32PrefixValPub + "BBAB", +} + +func testMarshal(t *testing.T, original interface{}, res interface{}, marshal func() ([]byte, error), unmarshal func([]byte) error) { + bz, err := marshal() + require.Nil(t, err) + err = unmarshal(bz) + require.Nil(t, err) + require.Equal(t, original, res) +} + +func TestRandBech32PubkeyConsistency(t *testing.T) { + var pub ed25519.PubKeyEd25519 + + for i := 0; i < 1000; i++ { + rand.Read(pub[:]) + + mustbech32accpub := types.MustBech32ifyAccPub(pub) + bech32accpub, err := types.Bech32ifyAccPub(pub) + require.Nil(t, err) + require.Equal(t, bech32accpub, mustbech32accpub) + + mustbech32valpub := types.MustBech32ifyValPub(pub) + bech32valpub, err := types.Bech32ifyValPub(pub) + require.Nil(t, err) + require.Equal(t, bech32valpub, mustbech32valpub) + + mustaccpub := types.MustGetAccPubKeyBech32(bech32accpub) + accpub, err := types.GetAccPubKeyBech32(bech32accpub) + require.Nil(t, err) + require.Equal(t, accpub, mustaccpub) + + mustvalpub := types.MustGetValPubKeyBech32(bech32valpub) + valpub, err := types.GetValPubKeyBech32(bech32valpub) + require.Nil(t, err) + require.Equal(t, valpub, mustvalpub) + + require.Equal(t, valpub, accpub) + } +} + +func TestRandBech32AccAddrConsistency(t *testing.T) { + var pub ed25519.PubKeyEd25519 + + for i := 0; i < 1000; i++ { + rand.Read(pub[:]) + + acc := types.AccAddress(pub.Address()) + res := types.AccAddress{} + + testMarshal(t, &acc, &res, acc.MarshalJSON, (&res).UnmarshalJSON) + testMarshal(t, &acc, &res, acc.Marshal, (&res).Unmarshal) + + str := acc.String() + res, err := types.AccAddressFromBech32(str) + require.Nil(t, err) + require.Equal(t, acc, res) + + str = hex.EncodeToString(acc) + res, err = types.AccAddressFromHex(str) + require.Nil(t, err) + require.Equal(t, acc, res) + } + + for _, str := range invalidstrs { + _, err := types.AccAddressFromHex(str) + require.NotNil(t, err) + + _, err = types.AccAddressFromBech32(str) + require.NotNil(t, err) + + err = (*types.AccAddress)(nil).UnmarshalJSON([]byte("\"" + str + "\"")) + require.NotNil(t, err) + } +} + +func TestValAddr(t *testing.T) { + var pub ed25519.PubKeyEd25519 + + for i := 0; i < 20; i++ { + rand.Read(pub[:]) + + acc := types.ValAddress(pub.Address()) + res := types.ValAddress{} + + testMarshal(t, &acc, &res, acc.MarshalJSON, (&res).UnmarshalJSON) + testMarshal(t, &acc, &res, acc.Marshal, (&res).Unmarshal) + + str := acc.String() + res, err := types.ValAddressFromBech32(str) + require.Nil(t, err) + require.Equal(t, acc, res) + + str = hex.EncodeToString(acc) + res, err = types.ValAddressFromHex(str) + require.Nil(t, err) + require.Equal(t, acc, res) + } + + for _, str := range invalidstrs { + _, err := types.ValAddressFromHex(str) + require.NotNil(t, err) + + _, err = types.ValAddressFromBech32(str) + require.NotNil(t, err) + + err = (*types.ValAddress)(nil).UnmarshalJSON([]byte("\"" + str + "\"")) + require.NotNil(t, err) + } +} diff --git a/types/coin_test.go b/types/coin_test.go index 246339e97..0d47630f4 100644 --- a/types/coin_test.go +++ b/types/coin_test.go @@ -147,6 +147,46 @@ func TestMinusCoin(t *testing.T) { } +func TestIsZeroCoins(t *testing.T) { + cases := []struct { + inputOne Coins + expected bool + }{ + {Coins{}, true}, + {Coins{NewCoin("A", 0)}, true}, + {Coins{NewCoin("A", 0), NewCoin("B", 0)}, true}, + {Coins{NewCoin("A", 1)}, false}, + {Coins{NewCoin("A", 0), NewCoin("B", 1)}, false}, + } + + for _, tc := range cases { + res := tc.inputOne.IsZero() + require.Equal(t, tc.expected, res) + } +} + +func TestEqualCoins(t *testing.T) { + cases := []struct { + inputOne Coins + inputTwo Coins + expected bool + }{ + {Coins{}, Coins{}, true}, + {Coins{NewCoin("A", 0)}, Coins{NewCoin("A", 0)}, true}, + {Coins{NewCoin("A", 0), NewCoin("B", 1)}, Coins{NewCoin("A", 0), NewCoin("B", 1)}, true}, + {Coins{NewCoin("A", 0)}, Coins{NewCoin("B", 0)}, false}, + {Coins{NewCoin("A", 0)}, Coins{NewCoin("A", 1)}, false}, + {Coins{NewCoin("A", 0)}, Coins{NewCoin("A", 0), NewCoin("B", 1)}, false}, + // TODO: is it expected behaviour? shouldn't we sort the coins before comparing them? + {Coins{NewCoin("A", 0), NewCoin("B", 1)}, Coins{NewCoin("B", 1), NewCoin("A", 0)}, false}, + } + + for tcnum, tc := range cases { + res := tc.inputOne.IsEqual(tc.inputTwo) + require.Equal(t, tc.expected, res, "Equality is differed from expected. tc #%d, expected %b, actual %b.", tcnum, tc.expected, res) + } +} + func TestCoins(t *testing.T) { //Define the coins to be used in tests @@ -160,6 +200,7 @@ func TestCoins(t *testing.T) { empty := Coins{ {"GOLD", NewInt(0)}, } + null := Coins{} badSort1 := Coins{ {"TREE", NewInt(1)}, {"GAS", NewInt(1)}, @@ -184,6 +225,7 @@ func TestCoins(t *testing.T) { assert.True(t, good.IsValid(), "Coins are valid") assert.True(t, good.IsPositive(), "Expected coins to be positive: %v", good) + assert.False(t, null.IsPositive(), "Expected coins to not be positive: %v", null) assert.True(t, good.IsGTE(empty), "Expected %v to be >= %v", good, empty) assert.False(t, neg.IsPositive(), "Expected neg coins to not be positive: %v", neg) assert.Zero(t, len(sum), "Expected 0 coins") diff --git a/types/context_test.go b/types/context_test.go index fb2786cff..900192285 100644 --- a/types/context_test.go +++ b/types/context_test.go @@ -98,3 +98,84 @@ func TestLogContext(t *testing.T) { ctx.Logger().Error("error") require.Equal(t, *logger.logs, []string{"debug", "info", "error"}) } + +type dummy int64 + +func (d dummy) Clone() interface{} { + return d +} + +// Testing saving/loading primitive values to/from the context +func TestContextWithPrimitive(t *testing.T) { + ctx := types.NewContext(nil, abci.Header{}, false, log.NewNopLogger()) + + clonerkey := "cloner" + stringkey := "string" + int32key := "int32" + uint32key := "uint32" + uint64key := "uint64" + + keys := []string{clonerkey, stringkey, int32key, uint32key, uint64key} + + for _, key := range keys { + require.Nil(t, ctx.Value(key)) + } + + clonerval := dummy(1) + stringval := "string" + int32val := int32(1) + uint32val := uint32(2) + uint64val := uint64(3) + + ctx = ctx. + WithCloner(clonerkey, clonerval). + WithString(stringkey, stringval). + WithInt32(int32key, int32val). + WithUint32(uint32key, uint32val). + WithUint64(uint64key, uint64val) + + require.Equal(t, clonerval, ctx.Value(clonerkey)) + require.Equal(t, stringval, ctx.Value(stringkey)) + require.Equal(t, int32val, ctx.Value(int32key)) + require.Equal(t, uint32val, ctx.Value(uint32key)) + require.Equal(t, uint64val, ctx.Value(uint64key)) +} + +// Testing saving/loading sdk type values to/from the context +func TestContextWithCustom(t *testing.T) { + var ctx types.Context + require.True(t, ctx.IsZero()) + + require.Panics(t, func() { ctx.BlockHeader() }) + require.Panics(t, func() { ctx.BlockHeight() }) + require.Panics(t, func() { ctx.ChainID() }) + require.Panics(t, func() { ctx.TxBytes() }) + require.Panics(t, func() { ctx.Logger() }) + require.Panics(t, func() { ctx.SigningValidators() }) + require.Panics(t, func() { ctx.GasMeter() }) + + header := abci.Header{} + height := int64(1) + chainid := "chainid" + ischeck := true + txbytes := []byte("txbytes") + logger := NewMockLogger() + signvals := []abci.SigningValidator{abci.SigningValidator{}} + meter := types.NewGasMeter(10000) + + ctx = types.NewContext(nil, header, ischeck, logger). + WithBlockHeight(height). + WithChainID(chainid). + WithTxBytes(txbytes). + WithSigningValidators(signvals). + WithGasMeter(meter) + + require.Equal(t, header, ctx.BlockHeader()) + require.Equal(t, height, ctx.BlockHeight()) + require.Equal(t, chainid, ctx.ChainID()) + require.Equal(t, txbytes, ctx.TxBytes()) + require.Equal(t, logger, ctx.Logger()) + require.Equal(t, signvals, ctx.SigningValidators()) + require.Equal(t, meter, ctx.GasMeter()) + +} diff --git a/types/errors.go b/types/errors.go index a106ee9bb..58541dfea 100644 --- a/types/errors.go +++ b/types/errors.go @@ -65,6 +65,10 @@ const ( MaximumCodespace CodespaceType = 65535 ) +func unknownCodeMsg(code CodeType) string { + return fmt.Sprintf("unknown code %d", code) +} + // NOTE: Don't stringer this, we'll put better messages in later. // nolint: gocyclo func CodeToDefaultMsg(code CodeType) string { @@ -96,7 +100,7 @@ func CodeToDefaultMsg(code CodeType) string { case CodeMemoTooLarge: return "memo too large" default: - return fmt.Sprintf("unknown code %d", code) + return unknownCodeMsg(code) } } diff --git a/types/errors_test.go b/types/errors_test.go index 959f059d0..e7625e96f 100644 --- a/types/errors_test.go +++ b/types/errors_test.go @@ -1,7 +1,6 @@ package types import ( - "strings" "testing" "github.com/stretchr/testify/require" @@ -14,8 +13,13 @@ var codeTypes = []CodeType{ CodeUnauthorized, CodeInsufficientFunds, CodeUnknownRequest, - CodeUnknownAddress, + CodeInvalidAddress, CodeInvalidPubKey, + CodeUnknownAddress, + CodeInsufficientCoins, + CodeInvalidCoins, + CodeOutOfGas, + CodeMemoTooLarge, } type errFn func(msg string) Error @@ -27,24 +31,34 @@ var errFns = []errFn{ ErrUnauthorized, ErrInsufficientFunds, ErrUnknownRequest, - ErrUnknownAddress, + ErrInvalidAddress, ErrInvalidPubKey, + ErrUnknownAddress, + ErrInsufficientCoins, + ErrInvalidCoins, + ErrOutOfGas, + ErrMemoTooLarge, } func TestCodeType(t *testing.T) { require.True(t, ABCICodeOK.IsOK()) - for _, c := range codeTypes { + for tcnum, c := range codeTypes { msg := CodeToDefaultMsg(c) - require.False(t, strings.HasPrefix(msg, "Unknown code")) + require.NotEqual(t, unknownCodeMsg(c), msg, "Code expected to be known. tc #%d, code %d, msg %s", tcnum, c, msg) } + + msg := CodeToDefaultMsg(CodeOK) + require.Equal(t, unknownCodeMsg(CodeOK), msg) } func TestErrFn(t *testing.T) { for i, errFn := range errFns { err := errFn("") codeType := codeTypes[i] - require.Equal(t, err.Code(), codeType) - require.Equal(t, err.Result().Code, ToABCICode(CodespaceRoot, codeType)) + require.Equal(t, err.Code(), codeType, "Err function expected to return proper code. tc #%d", i) + require.Equal(t, err.Result().Code, ToABCICode(CodespaceRoot, codeType), "Err function expected to return proper ABCICode. tc #%d") } + + require.Equal(t, ABCICodeOK, ToABCICode(CodespaceRoot, CodeOK)) } diff --git a/types/gas_test.go b/types/gas_test.go new file mode 100644 index 000000000..cd2384d12 --- /dev/null +++ b/types/gas_test.go @@ -0,0 +1,36 @@ +package types + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestGasMeter(t *testing.T) { + cases := []struct { + limit Gas + usage []Gas + }{ + {10, []Gas{1, 2, 3, 4}}, + {1000, []Gas{40, 30, 20, 10, 900}}, + {100000, []Gas{99999, 1}}, + {100000000, []Gas{50000000, 40000000, 10000000}}, + {65535, []Gas{32768, 32767}}, + {65536, []Gas{32768, 32767, 1}}, + } + + for tcnum, tc := range cases { + meter := NewGasMeter(tc.limit) + used := int64(0) + + for unum, usage := range tc.usage { + used += usage + require.NotPanics(t, func() { meter.ConsumeGas(usage, "") }, "Not exceeded limit but panicked. tc #%d, usage #%d", tcnum, unum) + require.Equal(t, used, meter.GasConsumed(), "Gas consumption not match. tc #%d, usage #%d", tcnum, unum) + } + + require.Panics(t, func() { meter.ConsumeGas(1, "") }, "Exceeded but not panicked. tc #%d", tcnum) + break + + } +} diff --git a/types/int.go b/types/int.go index 0227203cd..1421a934d 100644 --- a/types/int.go +++ b/types/int.go @@ -4,21 +4,13 @@ import ( "encoding/json" "math/big" + "math/rand" ) func newIntegerFromString(s string) (*big.Int, bool) { return new(big.Int).SetString(s, 0) } -func newIntegerWithDecimal(n int64, dec int) (res *big.Int) { - if dec < 0 { - return - } - exp := new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(dec)), nil) - i := new(big.Int) - return i.Mul(big.NewInt(n), exp) -} - func equal(i *big.Int, i2 *big.Int) bool { return i.Cmp(i2) == 0 } func gt(i *big.Int, i2 *big.Int) bool { return i.Cmp(i2) == 1 } @@ -37,6 +29,8 @@ func mod(i *big.Int, i2 *big.Int) *big.Int { return new(big.Int).Mod(i, i2) } func neg(i *big.Int) *big.Int { return new(big.Int).Neg(i) } +func random(i *big.Int) *big.Int { return new(big.Int).Rand(rand.New(rand.NewSource(rand.Int63())), i) } + func min(i *big.Int, i2 *big.Int) *big.Int { if i.Cmp(i2) == 1 { return new(big.Int).Set(i2) @@ -118,7 +112,13 @@ func NewIntFromString(s string) (res Int, ok bool) { // NewIntWithDecimal constructs Int with decimal // Result value is n*10^dec func NewIntWithDecimal(n int64, dec int) Int { - i := newIntegerWithDecimal(n, dec) + if dec < 0 { + panic("NewIntWithDecimal() decimal is negative") + } + exp := new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(dec)), nil) + i := new(big.Int) + i.Mul(big.NewInt(n), exp) + // Check overflow if i.BitLen() > 255 { panic("NewIntWithDecimal() out of bound") @@ -141,6 +141,11 @@ func (i Int) Int64() int64 { return i.i.Int64() } +// IsInt64 returns true if Int64() not panics +func (i Int) IsInt64() bool { + return i.i.IsInt64() +} + // IsZero returns true if Int is zero func (i Int) IsZero() bool { return i.i.Sign() == 0 @@ -229,6 +234,19 @@ func (i Int) DivRaw(i2 int64) Int { return i.Div(NewInt(i2)) } +// Mod returns remainder after dividing with Int +func (i Int) Mod(i2 Int) Int { + if i2.Sign() == 0 { + panic("division-by-zero") + } + return Int{mod(i.i, i2.i)} +} + +// ModRaw returns remainder after dividing with int64 +func (i Int) ModRaw(i2 int64) Int { + return i.Mod(NewInt(i2)) +} + // Neg negates Int func (i Int) Neg() (res Int) { return Int{neg(i.i)} @@ -239,10 +257,16 @@ func MinInt(i1, i2 Int) Int { return Int{min(i1.BigInt(), i2.BigInt())} } +// Human readable string func (i Int) String() string { return i.i.String() } +// Testing purpose random Int generator +func randomInt(i Int) Int { + return NewIntFromBigInt(random(i.BigInt())) +} + // MarshalAmino defines custom encoding scheme func (i Int) MarshalAmino() (string, error) { if i.i == nil { // Necessary since default Uint initialization has i.i as nil @@ -319,8 +343,14 @@ func NewUintFromString(s string) (res Uint, ok bool) { // NewUintWithDecimal constructs Uint with decimal // Result value is n*10^dec -func NewUintWithDecimal(n int64, dec int) Uint { - i := newIntegerWithDecimal(n, dec) +func NewUintWithDecimal(n uint64, dec int) Uint { + if dec < 0 { + panic("NewUintWithDecimal() decimal is negative") + } + exp := new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(dec)), nil) + i := new(big.Int) + i.Mul(new(big.Int).SetUint64(n), exp) + // Check overflow if i.Sign() == -1 || i.Sign() == 1 && i.BitLen() > 256 { panic("NewUintWithDecimal() out of bound") @@ -343,6 +373,11 @@ func (i Uint) Uint64() uint64 { return i.i.Uint64() } +// IsUint64 returns true if Uint64() not panics +func (i Uint) IsUint64() bool { + return i.i.IsUint64() +} + // IsZero returns true if Uint is zero func (i Uint) IsZero() bool { return i.i.Sign() == 0 @@ -378,7 +413,7 @@ func (i Uint) Add(i2 Uint) (res Uint) { return } -// AddRaw adds int64 to Uint +// AddRaw adds uint64 to Uint func (i Uint) AddRaw(i2 uint64) Uint { return i.Add(NewUint(i2)) } @@ -393,7 +428,7 @@ func (i Uint) Sub(i2 Uint) (res Uint) { return } -// SubRaw subtracts int64 from Uint +// SubRaw subtracts uint64 from Uint func (i Uint) SubRaw(i2 uint64) Uint { return i.Sub(NewUint(i2)) } @@ -412,7 +447,7 @@ func (i Uint) Mul(i2 Uint) (res Uint) { return } -// MulRaw multipies Uint and int64 +// MulRaw multipies Uint and uint64 func (i Uint) MulRaw(i2 uint64) Uint { return i.Mul(NewUint(i2)) } @@ -426,16 +461,39 @@ func (i Uint) Div(i2 Uint) (res Uint) { return Uint{div(i.i, i2.i)} } -// Div divides Uint with int64 +// Div divides Uint with uint64 func (i Uint) DivRaw(i2 uint64) Uint { return i.Div(NewUint(i2)) } +// Mod returns remainder after dividing with Uint +func (i Uint) Mod(i2 Uint) Uint { + if i2.Sign() == 0 { + panic("division-by-zero") + } + return Uint{mod(i.i, i2.i)} +} + +// ModRaw returns remainder after dividing with uint64 +func (i Uint) ModRaw(i2 uint64) Uint { + return i.Mod(NewUint(i2)) +} + // Return the minimum of the Uints func MinUint(i1, i2 Uint) Uint { return Uint{min(i1.BigInt(), i2.BigInt())} } +// Human readable string +func (i Uint) String() string { + return i.i.String() +} + +// Testing purpose random Uint generator +func randomUint(i Uint) Uint { + return NewUintFromBigInt(random(i.BigInt())) +} + // MarshalAmino defines custom encoding scheme func (i Uint) MarshalAmino() (string, error) { if i.i == nil { // Necessary since default Uint initialization has i.i as nil diff --git a/types/int_test.go b/types/int_test.go index e81bd6d7e..a105bb379 100644 --- a/types/int_test.go +++ b/types/int_test.go @@ -1,8 +1,10 @@ package types import ( + "math" "math/big" "math/rand" + "strconv" "testing" "github.com/stretchr/testify/require" @@ -15,7 +17,7 @@ func TestFromInt64(t *testing.T) { } } -func TestInt(t *testing.T) { +func TestIntPanic(t *testing.T) { // Max Int = 2^255-1 = 5.789e+76 // Min Int = -(2^255-1) = -5.789e+76 require.NotPanics(t, func() { NewIntWithDecimal(1, 76) }) @@ -71,7 +73,7 @@ func TestInt(t *testing.T) { require.Panics(t, func() { i1.Div(NewInt(0)) }) } -func TestUint(t *testing.T) { +func TestUintPanic(t *testing.T) { // Max Uint = 1.15e+77 // Min Uint = 0 require.NotPanics(t, func() { NewUintWithDecimal(5, 76) }) @@ -109,3 +111,482 @@ func TestUint(t *testing.T) { // Division-by-zero check require.Panics(t, func() { i1.Div(uintmin) }) } + +// Tests below uses randomness +// Since we are using *big.Int as underlying value +// and (U/)Int is immutable value(see TestImmutability(U/)Int) +// it is safe to use randomness in the tests +func TestIdentInt(t *testing.T) { + for d := 0; d < 1000; d++ { + n := rand.Int63() + i := NewInt(n) + + ifromstr, ok := NewIntFromString(strconv.FormatInt(n, 10)) + require.True(t, ok) + + cases := []int64{ + i.Int64(), + i.BigInt().Int64(), + ifromstr.Int64(), + NewIntFromBigInt(big.NewInt(n)).Int64(), + NewIntWithDecimal(n, 0).Int64(), + } + + for tcnum, tc := range cases { + require.Equal(t, n, tc, "Int is modified during conversion. tc #%d", tcnum) + } + } +} + +func minint(i1, i2 int64) int64 { + if i1 < i2 { + return i1 + } + return i2 +} + +func TestArithInt(t *testing.T) { + for d := 0; d < 1000; d++ { + n1 := int64(rand.Int31()) + i1 := NewInt(n1) + n2 := int64(rand.Int31()) + i2 := NewInt(n2) + + cases := []struct { + ires Int + nres int64 + }{ + {i1.Add(i2), n1 + n2}, + {i1.Sub(i2), n1 - n2}, + {i1.Mul(i2), n1 * n2}, + {i1.Div(i2), n1 / n2}, + {i1.AddRaw(n2), n1 + n2}, + {i1.SubRaw(n2), n1 - n2}, + {i1.MulRaw(n2), n1 * n2}, + {i1.DivRaw(n2), n1 / n2}, + {MinInt(i1, i2), minint(n1, n2)}, + {i1.Neg(), -n1}, + } + + for tcnum, tc := range cases { + require.Equal(t, tc.nres, tc.ires.Int64(), "Int arithmetic operation does not match with int64 operation. tc #%d", tcnum) + } + } + +} + +func TestCompInt(t *testing.T) { + for d := 0; d < 1000; d++ { + n1 := int64(rand.Int31()) + i1 := NewInt(n1) + n2 := int64(rand.Int31()) + i2 := NewInt(n2) + + cases := []struct { + ires bool + nres bool + }{ + {i1.Equal(i2), n1 == n2}, + {i1.GT(i2), n1 > n2}, + {i1.LT(i2), n1 < n2}, + } + + for tcnum, tc := range cases { + require.Equal(t, tc.nres, tc.ires, "Int comparison operation does not match with int64 operation. tc #%d", tcnum) + } + } +} + +func TestIdentUint(t *testing.T) { + for d := 0; d < 1000; d++ { + n := rand.Uint64() + i := NewUint(n) + + ifromstr, ok := NewUintFromString(strconv.FormatUint(n, 10)) + require.True(t, ok) + + cases := []uint64{ + i.Uint64(), + i.BigInt().Uint64(), + ifromstr.Uint64(), + NewUintFromBigInt(new(big.Int).SetUint64(n)).Uint64(), + NewUintWithDecimal(n, 0).Uint64(), + } + + for tcnum, tc := range cases { + require.Equal(t, n, tc, "Uint is modified during conversion. tc #%d", tcnum) + } + } +} + +func minuint(i1, i2 uint64) uint64 { + if i1 < i2 { + return i1 + } + return i2 +} + +func TestArithUint(t *testing.T) { + for d := 0; d < 1000; d++ { + n1 := uint64(rand.Uint32()) + i1 := NewUint(n1) + n2 := uint64(rand.Uint32()) + i2 := NewUint(n2) + + cases := []struct { + ires Uint + nres uint64 + }{ + {i1.Add(i2), n1 + n2}, + {i1.Mul(i2), n1 * n2}, + {i1.Div(i2), n1 / n2}, + {i1.AddRaw(n2), n1 + n2}, + {i1.MulRaw(n2), n1 * n2}, + {i1.DivRaw(n2), n1 / n2}, + {MinUint(i1, i2), minuint(n1, n2)}, + } + + for tcnum, tc := range cases { + require.Equal(t, tc.nres, tc.ires.Uint64(), "Uint arithmetic operation does not match with uint64 operation. tc #%d", tcnum) + } + + if n2 > n1 { + continue + } + + subs := []struct { + ires Uint + nres uint64 + }{ + {i1.Sub(i2), n1 - n2}, + {i1.SubRaw(n2), n1 - n2}, + } + + for tcnum, tc := range subs { + require.Equal(t, tc.nres, tc.ires.Uint64(), "Uint subtraction does not match with uint64 operation. tc #%d", tcnum) + } + } +} + +func TestCompUint(t *testing.T) { + for d := 0; d < 1000; d++ { + n1 := rand.Uint64() + i1 := NewUint(n1) + n2 := rand.Uint64() + i2 := NewUint(n2) + + cases := []struct { + ires bool + nres bool + }{ + {i1.Equal(i2), n1 == n2}, + {i1.GT(i2), n1 > n2}, + {i1.LT(i2), n1 < n2}, + } + + for tcnum, tc := range cases { + require.Equal(t, tc.nres, tc.ires, "Uint comparison operation does not match with uint64 operation. tc #%d", tcnum) + } + } +} + +func randint() Int { + return NewInt(rand.Int63()) +} + +func TestImmutabilityAllInt(t *testing.T) { + ops := []func(*Int){ + func(i *Int) { _ = i.Add(randint()) }, + func(i *Int) { _ = i.Sub(randint()) }, + func(i *Int) { _ = i.Mul(randint()) }, + func(i *Int) { _ = i.Div(randint()) }, + func(i *Int) { _ = i.AddRaw(rand.Int63()) }, + func(i *Int) { _ = i.SubRaw(rand.Int63()) }, + func(i *Int) { _ = i.MulRaw(rand.Int63()) }, + func(i *Int) { _ = i.DivRaw(rand.Int63()) }, + func(i *Int) { _ = i.Neg() }, + func(i *Int) { _ = i.IsZero() }, + func(i *Int) { _ = i.Sign() }, + func(i *Int) { _ = i.Equal(randint()) }, + func(i *Int) { _ = i.GT(randint()) }, + func(i *Int) { _ = i.LT(randint()) }, + func(i *Int) { _ = i.String() }, + } + + for i := 0; i < 1000; i++ { + n := rand.Int63() + ni := NewInt(n) + + for opnum, op := range ops { + op(&ni) + + require.Equal(t, n, ni.Int64(), "Int is modified by operation. tc #%d", opnum) + require.Equal(t, NewInt(n), ni, "Int is modified by operation. tc #%d", opnum) + } + } +} + +type intop func(Int, *big.Int) (Int, *big.Int) + +func intarith(uifn func(Int, Int) Int, bifn func(*big.Int, *big.Int, *big.Int) *big.Int) intop { + return func(ui Int, bi *big.Int) (Int, *big.Int) { + r := rand.Int63() + br := new(big.Int).SetInt64(r) + return uifn(ui, NewInt(r)), bifn(new(big.Int), bi, br) + } +} + +func intarithraw(uifn func(Int, int64) Int, bifn func(*big.Int, *big.Int, *big.Int) *big.Int) intop { + return func(ui Int, bi *big.Int) (Int, *big.Int) { + r := rand.Int63() + br := new(big.Int).SetInt64(r) + return uifn(ui, r), bifn(new(big.Int), bi, br) + } +} + +func TestImmutabilityArithInt(t *testing.T) { + size := 1000 + + ops := []intop{ + intarith(Int.Add, (*big.Int).Add), + intarith(Int.Sub, (*big.Int).Sub), + intarith(Int.Mul, (*big.Int).Mul), + intarith(Int.Div, (*big.Int).Div), + intarithraw(Int.AddRaw, (*big.Int).Add), + intarithraw(Int.SubRaw, (*big.Int).Sub), + intarithraw(Int.MulRaw, (*big.Int).Mul), + intarithraw(Int.DivRaw, (*big.Int).Div), + } + + for i := 0; i < 1000; i++ { + uis := make([]Int, size) + bis := make([]*big.Int, size) + + n := rand.Int63() + ui := NewInt(n) + bi := new(big.Int).SetInt64(n) + + for j := 0; j < size; j++ { + op := ops[rand.Intn(len(ops))] + uis[j], bis[j] = op(ui, bi) + } + + for j := 0; j < size; j++ { + require.Equal(t, 0, bis[j].Cmp(uis[j].BigInt()), "Int is different from *big.Int. tc #%d, Int %s, *big.Int %s", j, uis[j].String(), bis[j].String()) + require.Equal(t, NewIntFromBigInt(bis[j]), uis[j], "Int is different from *big.Int. tc #%d, Int %s, *big.Int %s", j, uis[j].String(), bis[j].String()) + require.True(t, uis[j].i != bis[j], "Pointer addresses are equal. tc #%d, Int %s, *big.Int %s", j, uis[j].String(), bis[j].String()) + } + } +} +func TestImmutabilityAllUint(t *testing.T) { + ops := []func(*Uint){ + func(i *Uint) { _ = i.Add(NewUint(rand.Uint64())) }, + func(i *Uint) { _ = i.Sub(NewUint(rand.Uint64() % i.Uint64())) }, + func(i *Uint) { _ = i.Mul(randuint()) }, + func(i *Uint) { _ = i.Div(randuint()) }, + func(i *Uint) { _ = i.AddRaw(rand.Uint64()) }, + func(i *Uint) { _ = i.SubRaw(rand.Uint64() % i.Uint64()) }, + func(i *Uint) { _ = i.MulRaw(rand.Uint64()) }, + func(i *Uint) { _ = i.DivRaw(rand.Uint64()) }, + func(i *Uint) { _ = i.IsZero() }, + func(i *Uint) { _ = i.Sign() }, + func(i *Uint) { _ = i.Equal(randuint()) }, + func(i *Uint) { _ = i.GT(randuint()) }, + func(i *Uint) { _ = i.LT(randuint()) }, + func(i *Uint) { _ = i.String() }, + } + + for i := 0; i < 1000; i++ { + n := rand.Uint64() + ni := NewUint(n) + + for opnum, op := range ops { + op(&ni) + + require.Equal(t, n, ni.Uint64(), "Uint is modified by operation. #%d", opnum) + require.Equal(t, NewUint(n), ni, "Uint is modified by operation. #%d", opnum) + } + } +} + +type uintop func(Uint, *big.Int) (Uint, *big.Int) + +func uintarith(uifn func(Uint, Uint) Uint, bifn func(*big.Int, *big.Int, *big.Int) *big.Int, sub bool) uintop { + return func(ui Uint, bi *big.Int) (Uint, *big.Int) { + r := rand.Uint64() + if sub && ui.IsUint64() { + if ui.IsZero() { + return ui, bi + } + r = r % ui.Uint64() + } + ur := NewUint(r) + br := new(big.Int).SetUint64(r) + return uifn(ui, ur), bifn(new(big.Int), bi, br) + } +} + +func uintarithraw(uifn func(Uint, uint64) Uint, bifn func(*big.Int, *big.Int, *big.Int) *big.Int, sub bool) uintop { + return func(ui Uint, bi *big.Int) (Uint, *big.Int) { + r := rand.Uint64() + if sub && ui.IsUint64() { + if ui.IsZero() { + return ui, bi + } + r = r % ui.Uint64() + } + br := new(big.Int).SetUint64(r) + mui := ui.ModRaw(math.MaxUint64) + mbi := new(big.Int).Mod(bi, new(big.Int).SetUint64(math.MaxUint64)) + return uifn(mui, r), bifn(new(big.Int), mbi, br) + } +} + +func TestImmutabilityArithUint(t *testing.T) { + size := 1000 + + ops := []uintop{ + uintarith(Uint.Add, (*big.Int).Add, false), + uintarith(Uint.Sub, (*big.Int).Sub, true), + uintarith(Uint.Mul, (*big.Int).Mul, false), + uintarith(Uint.Div, (*big.Int).Div, false), + uintarithraw(Uint.AddRaw, (*big.Int).Add, false), + uintarithraw(Uint.SubRaw, (*big.Int).Sub, true), + uintarithraw(Uint.MulRaw, (*big.Int).Mul, false), + uintarithraw(Uint.DivRaw, (*big.Int).Div, false), + } + + for i := 0; i < 1000; i++ { + uis := make([]Uint, size) + bis := make([]*big.Int, size) + + n := rand.Uint64() + ui := NewUint(n) + bi := new(big.Int).SetUint64(n) + + for j := 0; j < size; j++ { + op := ops[rand.Intn(len(ops))] + uis[j], bis[j] = op(ui, bi) + } + + for j := 0; j < size; j++ { + require.Equal(t, 0, bis[j].Cmp(uis[j].BigInt()), "Int is different from *big.Int. tc #%d, Int %s, *big.Int %s", j, uis[j].String(), bis[j].String()) + require.Equal(t, NewUintFromBigInt(bis[j]), uis[j], "Int is different from *big.Int. tc #%d, Int %s, *big.Int %s", j, uis[j].String(), bis[j].String()) + require.True(t, uis[j].i != bis[j], "Pointer addresses are equal. tc #%d, Int %s, *big.Int %s", j, uis[j].String(), bis[j].String()) + } + } +} + +func randuint() Uint { + return NewUint(rand.Uint64()) +} + +func TestEncodingRandom(t *testing.T) { + for i := 0; i < 1000; i++ { + n := rand.Int63() + ni := NewInt(n) + var ri Int + + str, err := ni.MarshalAmino() + require.Nil(t, err) + err = (&ri).UnmarshalAmino(str) + require.Nil(t, err) + + require.Equal(t, ni, ri, "MarshalAmino * UnmarshalAmino is not identity. tc #%d, Expected %s, Actual %s", i, ni.String(), ri.String()) + require.True(t, ni.i != ri.i, "Pointer addresses are equal. tc #%d", i) + + bz, err := ni.MarshalJSON() + require.Nil(t, err) + err = (&ri).UnmarshalJSON(bz) + require.Nil(t, err) + + require.Equal(t, ni, ri, "MarshalJSON * UnmarshalJSON is not identity. tc #%d, Expected %s, Actual %s", i, ni.String(), ri.String()) + require.True(t, ni.i != ri.i, "Pointer addresses are equal. tc #%d", i) + } + + for i := 0; i < 1000; i++ { + n := rand.Uint64() + ni := NewUint(n) + var ri Uint + + str, err := ni.MarshalAmino() + require.Nil(t, err) + err = (&ri).UnmarshalAmino(str) + require.Nil(t, err) + + require.Equal(t, ni, ri, "MarshalAmino * UnmarshalAmino is not identity. tc #%d, Expected %s, Actual %s", i, ni.String(), ri.String()) + require.True(t, ni.i != ri.i, "Pointer addresses are equal. tc #%d", i) + + bz, err := ni.MarshalJSON() + require.Nil(t, err) + err = (&ri).UnmarshalJSON(bz) + require.Nil(t, err) + + require.Equal(t, ni, ri, "MarshalJSON * UnmarshalJSON is not identity. tc #%d, Expected %s, Actual %s", i, ni.String(), ri.String()) + require.True(t, ni.i != ri.i, "Pointer addresses are equal. tc #%d", i) + } +} + +func TestEncodingTableInt(t *testing.T) { + var i Int + + cases := []struct { + i Int + bz []byte + str string + }{ + {NewInt(0), []byte("\"0\""), "0"}, + {NewInt(100), []byte("\"100\""), "100"}, + {NewInt(51842), []byte("\"51842\""), "51842"}, + {NewInt(19513368), []byte("\"19513368\""), "19513368"}, + {NewInt(999999999999), []byte("\"999999999999\""), "999999999999"}, + } + + for tcnum, tc := range cases { + bz, err := tc.i.MarshalJSON() + require.Nil(t, err, "Error marshaling Int. tc #%d, err %s", tcnum, err) + require.Equal(t, tc.bz, bz, "Marshaled value is different from expected. tc #%d", tcnum) + err = (&i).UnmarshalJSON(bz) + require.Nil(t, err, "Error unmarshaling Int. tc #%d, err %s", tcnum, err) + require.Equal(t, tc.i, i, "Unmarshaled value is different from expected. tc #%d", tcnum) + + str, err := tc.i.MarshalAmino() + require.Nil(t, err, "Error marshaling Int. tc #%d, err %s", tcnum, err) + require.Equal(t, tc.str, str, "Marshaled value is different from expected. tc #%d", tcnum) + err = (&i).UnmarshalAmino(str) + require.Nil(t, err, "Error unmarshaling Int. tc #%d, err %s", tcnum, err) + require.Equal(t, tc.i, i, "Unmarshaled value is different from expected. tc #%d", tcnum) + } +} + +func TestEncodingTableUint(t *testing.T) { + var i Uint + + cases := []struct { + i Uint + bz []byte + str string + }{ + {NewUint(0), []byte("\"0\""), "0"}, + {NewUint(100), []byte("\"100\""), "100"}, + {NewUint(51842), []byte("\"51842\""), "51842"}, + {NewUint(19513368), []byte("\"19513368\""), "19513368"}, + {NewUint(999999999999), []byte("\"999999999999\""), "999999999999"}, + } + + for tcnum, tc := range cases { + bz, err := tc.i.MarshalJSON() + require.Nil(t, err, "Error marshaling Int. tc #%d, err %s", tcnum, err) + require.Equal(t, tc.bz, bz, "Marshaled value is different from expected. tc #%d", tcnum) + err = (&i).UnmarshalJSON(bz) + require.Nil(t, err, "Error unmarshaling Int. tc #%d, err %s", tcnum, err) + require.Equal(t, tc.i, i, "Unmarshaled value is different from expected. tc #%d", tcnum) + + str, err := tc.i.MarshalAmino() + require.Nil(t, err, "Error marshaling Int. tc #%d, err %s", tcnum, err) + require.Equal(t, tc.str, str, "Marshaled value is different from expected. tc #%d", tcnum) + err = (&i).UnmarshalAmino(str) + require.Nil(t, err, "Error unmarshaling Int. tc #%d, err %s", tcnum, err) + require.Equal(t, tc.i, i, "Unmarshaled value is different from expected. tc #%d", tcnum) + } +} diff --git a/types/lib/linear_test.go b/types/lib/linear_test.go index b14300a98..2b5a6c405 100644 --- a/types/lib/linear_test.go +++ b/types/lib/linear_test.go @@ -31,6 +31,18 @@ func defaultComponents(key sdk.StoreKey) (sdk.Context, *wire.Codec) { return ctx, cdc } +func TestNewLinear(t *testing.T) { + cdc := wire.NewCodec() + require.NotPanics(t, func() { NewLinear(cdc, nil, nil) }) + require.NotPanics(t, func() { NewLinear(cdc, nil, DefaultLinearKeys()) }) + require.NotPanics(t, func() { NewLinear(cdc, nil, &LinearKeys{[]byte{0xAA}, []byte{0xBB}, []byte{0xCC}}) }) + + require.Panics(t, func() { NewLinear(cdc, nil, &LinearKeys{nil, nil, nil}) }) + require.Panics(t, func() { NewLinear(cdc, nil, &LinearKeys{[]byte{0xAA}, nil, nil}) }) + require.Panics(t, func() { NewLinear(cdc, nil, &LinearKeys{nil, []byte{0xBB}, nil}) }) + require.Panics(t, func() { NewLinear(cdc, nil, &LinearKeys{nil, nil, []byte{0xCC}}) }) +} + func TestList(t *testing.T) { key := sdk.NewKVStoreKey("test") ctx, cdc := defaultComponents(key) diff --git a/types/rational_test.go b/types/rational_test.go index 5ca1ac9c6..940de23dc 100644 --- a/types/rational_test.go +++ b/types/rational_test.go @@ -2,6 +2,7 @@ package types import ( "math/big" + "math/rand" "testing" wire "github.com/cosmos/cosmos-sdk/wire" @@ -317,3 +318,85 @@ func TestStringOverflow(t *testing.T) { rat3.String(), ) } + +// Tests below uses randomness +// Since we are using *big.Rat as underlying value +// and (U/)Int is immutable value(see TestImmutability(U/)Int) +// it is safe to use randomness in the tests +func TestArithRat(t *testing.T) { + for i := 0; i < 20; i++ { + n1 := NewInt(int64(rand.Int31())) + d1 := NewInt(int64(rand.Int31())) + rat1 := NewRatFromInt(n1, d1) + + n2 := NewInt(int64(rand.Int31())) + d2 := NewInt(int64(rand.Int31())) + rat2 := NewRatFromInt(n2, d2) + + n1d2 := n1.Mul(d2) + n2d1 := n2.Mul(d1) + + cases := []struct { + nres Int + dres Int + rres Rat + }{ + {n1d2.Add(n2d1), d1.Mul(d2), rat1.Add(rat2)}, + {n1d2.Sub(n2d1), d1.Mul(d2), rat1.Sub(rat2)}, + {n1.Mul(n2), d1.Mul(d2), rat1.Mul(rat2)}, + {n1d2, n2d1, rat1.Quo(rat2)}, + } + + for _, tc := range cases { + require.Equal(t, NewRatFromInt(tc.nres, tc.dres), tc.rres) + } + } +} + +func TestCompRat(t *testing.T) { + for i := 0; i < 20; i++ { + n1 := NewInt(int64(rand.Int31())) + d1 := NewInt(int64(rand.Int31())) + rat1 := NewRatFromInt(n1, d1) + + n2 := NewInt(int64(rand.Int31())) + d2 := NewInt(int64(rand.Int31())) + rat2 := NewRatFromInt(n2, d2) + + n1d2 := n1.Mul(d2) + n2d1 := n2.Mul(d1) + + cases := []struct { + ires bool + rres bool + }{ + {n1d2.Equal(n2d1), rat1.Equal(rat2)}, + {n1d2.GT(n2d1), rat1.GT(rat2)}, + {n1d2.LT(n2d1), rat1.LT(rat2)}, + {n1d2.GT(n2d1) || n1d2.Equal(n2d1), rat1.GTE(rat2)}, + {n1d2.LT(n2d1) || n1d2.Equal(n2d1), rat1.LTE(rat2)}, + } + + for _, tc := range cases { + require.Equal(t, tc.ires, tc.rres) + } + } +} + +func TestImmutabilityRat(t *testing.T) { + for i := 0; i < 20; i++ { + n := int64(rand.Int31()) + r := NewRat(n) + z := ZeroRat() + o := OneRat() + + r.Add(z) + r.Sub(z) + r.Mul(o) + r.Quo(o) + + require.Equal(t, n, r.RoundInt64()) + require.True(t, NewRat(n).Equal(r)) + } + +} diff --git a/types/result_test.go b/types/result_test.go new file mode 100644 index 000000000..e0305932c --- /dev/null +++ b/types/result_test.go @@ -0,0 +1,18 @@ +package types + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestResult(t *testing.T) { + var res Result + require.True(t, res.IsOK()) + + res.Data = []byte("data") + require.True(t, res.IsOK()) + + res.Code = ABCICodeType(1) + require.False(t, res.IsOK()) +} diff --git a/types/store_test.go b/types/store_test.go index f376f3be1..b5e36c487 100644 --- a/types/store_test.go +++ b/types/store_test.go @@ -25,3 +25,15 @@ func TestPrefixEndBytes(t *testing.T) { require.Equal(t, test.expected, end) } } + +func TestCommitID(t *testing.T) { + var empty CommitID + require.True(t, empty.IsZero()) + + var nonempty CommitID + nonempty = CommitID{ + Version: 1, + Hash: []byte("testhash"), + } + require.False(t, nonempty.IsZero()) +} diff --git a/types/tags_test.go b/types/tags_test.go index 4ef556124..77bb4041c 100644 --- a/types/tags_test.go +++ b/types/tags_test.go @@ -11,6 +11,7 @@ func TestAppendTags(t *testing.T) { b := NewTags("b", []byte("2")) c := a.AppendTags(b) require.Equal(t, c, Tags{MakeTag("a", []byte("1")), MakeTag("b", []byte("2"))}) + require.Equal(t, c, Tags{MakeTag("a", []byte("1"))}.AppendTag("b", []byte("2"))) } func TestEmptyTags(t *testing.T) { @@ -21,4 +22,14 @@ func TestEmptyTags(t *testing.T) { func TestNewTags(t *testing.T) { b := NewTags("a", []byte("1")) require.Equal(t, b, Tags{MakeTag("a", []byte("1"))}) + + require.Panics(t, func() { NewTags("a", []byte("1"), "b") }) + require.Panics(t, func() { NewTags("a", 1) }) + require.Panics(t, func() { NewTags(1, 1) }) + require.Panics(t, func() { NewTags(true, false) }) +} + +func TestKVPairTags(t *testing.T) { + a := NewTags("a", []byte("1")) + require.Equal(t, a, Tags(a.ToKVPairs())) } diff --git a/types/utils_test.go b/types/utils_test.go index af22f2db6..05bc622e7 100644 --- a/types/utils_test.go +++ b/types/utils_test.go @@ -31,9 +31,15 @@ func TestSortJSON(t *testing.T) { for tcIndex, tc := range cases { got, err := SortJSON([]byte(tc.unsortedJSON)) - if tc.wantErr != (err != nil) { - t.Fatalf("got %t, want: %t, tc #%d, err=%s", err != nil, tc.wantErr, tcIndex, err) + if tc.wantErr { + require.NotNil(t, err, "tc #%d", tcIndex) + require.Panics(t, func() { MustSortJSON([]byte(tc.unsortedJSON)) }) + } else { + require.Nil(t, err, "tc #%d, err=%s", tcIndex, err) + require.NotPanics(t, func() { MustSortJSON([]byte(tc.unsortedJSON)) }) + require.Equal(t, got, MustSortJSON([]byte(tc.unsortedJSON))) } + require.Equal(t, string(got), tc.want) } }