Merge PR #1626: Increase coverage of types/

This commit is contained in:
Joon 2018-08-06 12:00:49 -07:00 committed by Christopher Goes
parent 12c2c236c2
commit 93457aac33
14 changed files with 1018 additions and 28 deletions

132
types/account_test.go Normal file
View File

@ -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)
}
}

View File

@ -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) { func TestCoins(t *testing.T) {
//Define the coins to be used in tests //Define the coins to be used in tests
@ -160,6 +200,7 @@ func TestCoins(t *testing.T) {
empty := Coins{ empty := Coins{
{"GOLD", NewInt(0)}, {"GOLD", NewInt(0)},
} }
null := Coins{}
badSort1 := Coins{ badSort1 := Coins{
{"TREE", NewInt(1)}, {"TREE", NewInt(1)},
{"GAS", 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.IsValid(), "Coins are valid")
assert.True(t, good.IsPositive(), "Expected coins to be positive: %v", good) 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.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.False(t, neg.IsPositive(), "Expected neg coins to not be positive: %v", neg)
assert.Zero(t, len(sum), "Expected 0 coins") assert.Zero(t, len(sum), "Expected 0 coins")

View File

@ -98,3 +98,84 @@ func TestLogContext(t *testing.T) {
ctx.Logger().Error("error") ctx.Logger().Error("error")
require.Equal(t, *logger.logs, []string{"debug", "info", "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())
}

View File

@ -65,6 +65,10 @@ const (
MaximumCodespace CodespaceType = 65535 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. // NOTE: Don't stringer this, we'll put better messages in later.
// nolint: gocyclo // nolint: gocyclo
func CodeToDefaultMsg(code CodeType) string { func CodeToDefaultMsg(code CodeType) string {
@ -96,7 +100,7 @@ func CodeToDefaultMsg(code CodeType) string {
case CodeMemoTooLarge: case CodeMemoTooLarge:
return "memo too large" return "memo too large"
default: default:
return fmt.Sprintf("unknown code %d", code) return unknownCodeMsg(code)
} }
} }

View File

@ -1,7 +1,6 @@
package types package types
import ( import (
"strings"
"testing" "testing"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@ -14,8 +13,13 @@ var codeTypes = []CodeType{
CodeUnauthorized, CodeUnauthorized,
CodeInsufficientFunds, CodeInsufficientFunds,
CodeUnknownRequest, CodeUnknownRequest,
CodeUnknownAddress, CodeInvalidAddress,
CodeInvalidPubKey, CodeInvalidPubKey,
CodeUnknownAddress,
CodeInsufficientCoins,
CodeInvalidCoins,
CodeOutOfGas,
CodeMemoTooLarge,
} }
type errFn func(msg string) Error type errFn func(msg string) Error
@ -27,24 +31,34 @@ var errFns = []errFn{
ErrUnauthorized, ErrUnauthorized,
ErrInsufficientFunds, ErrInsufficientFunds,
ErrUnknownRequest, ErrUnknownRequest,
ErrUnknownAddress, ErrInvalidAddress,
ErrInvalidPubKey, ErrInvalidPubKey,
ErrUnknownAddress,
ErrInsufficientCoins,
ErrInvalidCoins,
ErrOutOfGas,
ErrMemoTooLarge,
} }
func TestCodeType(t *testing.T) { func TestCodeType(t *testing.T) {
require.True(t, ABCICodeOK.IsOK()) require.True(t, ABCICodeOK.IsOK())
for _, c := range codeTypes { for tcnum, c := range codeTypes {
msg := CodeToDefaultMsg(c) 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) { func TestErrFn(t *testing.T) {
for i, errFn := range errFns { for i, errFn := range errFns {
err := errFn("") err := errFn("")
codeType := codeTypes[i] codeType := codeTypes[i]
require.Equal(t, err.Code(), 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)) 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))
} }

36
types/gas_test.go Normal file
View File

@ -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
}
}

View File

@ -4,21 +4,13 @@ import (
"encoding/json" "encoding/json"
"math/big" "math/big"
"math/rand"
) )
func newIntegerFromString(s string) (*big.Int, bool) { func newIntegerFromString(s string) (*big.Int, bool) {
return new(big.Int).SetString(s, 0) 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 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 } 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 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 { func min(i *big.Int, i2 *big.Int) *big.Int {
if i.Cmp(i2) == 1 { if i.Cmp(i2) == 1 {
return new(big.Int).Set(i2) return new(big.Int).Set(i2)
@ -118,7 +112,13 @@ func NewIntFromString(s string) (res Int, ok bool) {
// NewIntWithDecimal constructs Int with decimal // NewIntWithDecimal constructs Int with decimal
// Result value is n*10^dec // Result value is n*10^dec
func NewIntWithDecimal(n int64, dec int) Int { 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 // Check overflow
if i.BitLen() > 255 { if i.BitLen() > 255 {
panic("NewIntWithDecimal() out of bound") panic("NewIntWithDecimal() out of bound")
@ -141,6 +141,11 @@ func (i Int) Int64() int64 {
return i.i.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 // IsZero returns true if Int is zero
func (i Int) IsZero() bool { func (i Int) IsZero() bool {
return i.i.Sign() == 0 return i.i.Sign() == 0
@ -229,6 +234,19 @@ func (i Int) DivRaw(i2 int64) Int {
return i.Div(NewInt(i2)) 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 // Neg negates Int
func (i Int) Neg() (res Int) { func (i Int) Neg() (res Int) {
return Int{neg(i.i)} return Int{neg(i.i)}
@ -239,10 +257,16 @@ func MinInt(i1, i2 Int) Int {
return Int{min(i1.BigInt(), i2.BigInt())} return Int{min(i1.BigInt(), i2.BigInt())}
} }
// Human readable string
func (i Int) String() string { func (i Int) String() string {
return i.i.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 // MarshalAmino defines custom encoding scheme
func (i Int) MarshalAmino() (string, error) { func (i Int) MarshalAmino() (string, error) {
if i.i == nil { // Necessary since default Uint initialization has i.i as nil 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 // NewUintWithDecimal constructs Uint with decimal
// Result value is n*10^dec // Result value is n*10^dec
func NewUintWithDecimal(n int64, dec int) Uint { func NewUintWithDecimal(n uint64, dec int) Uint {
i := newIntegerWithDecimal(n, dec) 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 // Check overflow
if i.Sign() == -1 || i.Sign() == 1 && i.BitLen() > 256 { if i.Sign() == -1 || i.Sign() == 1 && i.BitLen() > 256 {
panic("NewUintWithDecimal() out of bound") panic("NewUintWithDecimal() out of bound")
@ -343,6 +373,11 @@ func (i Uint) Uint64() uint64 {
return i.i.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 // IsZero returns true if Uint is zero
func (i Uint) IsZero() bool { func (i Uint) IsZero() bool {
return i.i.Sign() == 0 return i.i.Sign() == 0
@ -378,7 +413,7 @@ func (i Uint) Add(i2 Uint) (res Uint) {
return return
} }
// AddRaw adds int64 to Uint // AddRaw adds uint64 to Uint
func (i Uint) AddRaw(i2 uint64) Uint { func (i Uint) AddRaw(i2 uint64) Uint {
return i.Add(NewUint(i2)) return i.Add(NewUint(i2))
} }
@ -393,7 +428,7 @@ func (i Uint) Sub(i2 Uint) (res Uint) {
return return
} }
// SubRaw subtracts int64 from Uint // SubRaw subtracts uint64 from Uint
func (i Uint) SubRaw(i2 uint64) Uint { func (i Uint) SubRaw(i2 uint64) Uint {
return i.Sub(NewUint(i2)) return i.Sub(NewUint(i2))
} }
@ -412,7 +447,7 @@ func (i Uint) Mul(i2 Uint) (res Uint) {
return return
} }
// MulRaw multipies Uint and int64 // MulRaw multipies Uint and uint64
func (i Uint) MulRaw(i2 uint64) Uint { func (i Uint) MulRaw(i2 uint64) Uint {
return i.Mul(NewUint(i2)) return i.Mul(NewUint(i2))
} }
@ -426,16 +461,39 @@ func (i Uint) Div(i2 Uint) (res Uint) {
return Uint{div(i.i, i2.i)} return Uint{div(i.i, i2.i)}
} }
// Div divides Uint with int64 // Div divides Uint with uint64
func (i Uint) DivRaw(i2 uint64) Uint { func (i Uint) DivRaw(i2 uint64) Uint {
return i.Div(NewUint(i2)) 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 // Return the minimum of the Uints
func MinUint(i1, i2 Uint) Uint { func MinUint(i1, i2 Uint) Uint {
return Uint{min(i1.BigInt(), i2.BigInt())} 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 // MarshalAmino defines custom encoding scheme
func (i Uint) MarshalAmino() (string, error) { func (i Uint) MarshalAmino() (string, error) {
if i.i == nil { // Necessary since default Uint initialization has i.i as nil if i.i == nil { // Necessary since default Uint initialization has i.i as nil

View File

@ -1,8 +1,10 @@
package types package types
import ( import (
"math"
"math/big" "math/big"
"math/rand" "math/rand"
"strconv"
"testing" "testing"
"github.com/stretchr/testify/require" "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 // Max Int = 2^255-1 = 5.789e+76
// Min Int = -(2^255-1) = -5.789e+76 // Min Int = -(2^255-1) = -5.789e+76
require.NotPanics(t, func() { NewIntWithDecimal(1, 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)) }) require.Panics(t, func() { i1.Div(NewInt(0)) })
} }
func TestUint(t *testing.T) { func TestUintPanic(t *testing.T) {
// Max Uint = 1.15e+77 // Max Uint = 1.15e+77
// Min Uint = 0 // Min Uint = 0
require.NotPanics(t, func() { NewUintWithDecimal(5, 76) }) require.NotPanics(t, func() { NewUintWithDecimal(5, 76) })
@ -109,3 +111,482 @@ func TestUint(t *testing.T) {
// Division-by-zero check // Division-by-zero check
require.Panics(t, func() { i1.Div(uintmin) }) 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)
}
}

View File

@ -31,6 +31,18 @@ func defaultComponents(key sdk.StoreKey) (sdk.Context, *wire.Codec) {
return ctx, cdc 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) { func TestList(t *testing.T) {
key := sdk.NewKVStoreKey("test") key := sdk.NewKVStoreKey("test")
ctx, cdc := defaultComponents(key) ctx, cdc := defaultComponents(key)

View File

@ -2,6 +2,7 @@ package types
import ( import (
"math/big" "math/big"
"math/rand"
"testing" "testing"
wire "github.com/cosmos/cosmos-sdk/wire" wire "github.com/cosmos/cosmos-sdk/wire"
@ -317,3 +318,85 @@ func TestStringOverflow(t *testing.T) {
rat3.String(), 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))
}
}

18
types/result_test.go Normal file
View File

@ -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())
}

View File

@ -25,3 +25,15 @@ func TestPrefixEndBytes(t *testing.T) {
require.Equal(t, test.expected, end) 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())
}

View File

@ -11,6 +11,7 @@ func TestAppendTags(t *testing.T) {
b := NewTags("b", []byte("2")) b := NewTags("b", []byte("2"))
c := a.AppendTags(b) 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")), MakeTag("b", []byte("2"))})
require.Equal(t, c, Tags{MakeTag("a", []byte("1"))}.AppendTag("b", []byte("2")))
} }
func TestEmptyTags(t *testing.T) { func TestEmptyTags(t *testing.T) {
@ -21,4 +22,14 @@ func TestEmptyTags(t *testing.T) {
func TestNewTags(t *testing.T) { func TestNewTags(t *testing.T) {
b := NewTags("a", []byte("1")) b := NewTags("a", []byte("1"))
require.Equal(t, b, Tags{MakeTag("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()))
} }

View File

@ -31,9 +31,15 @@ func TestSortJSON(t *testing.T) {
for tcIndex, tc := range cases { for tcIndex, tc := range cases {
got, err := SortJSON([]byte(tc.unsortedJSON)) got, err := SortJSON([]byte(tc.unsortedJSON))
if tc.wantErr != (err != nil) { if tc.wantErr {
t.Fatalf("got %t, want: %t, tc #%d, err=%s", err != nil, tc.wantErr, tcIndex, err) 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) require.Equal(t, string(got), tc.want)
} }
} }