github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/cosmos-sdk/types/int_test.go (about)

     1  package types
     2  
     3  import (
     4  	"math/big"
     5  	"math/rand"
     6  	"strconv"
     7  	"testing"
     8  
     9  	"github.com/stretchr/testify/require"
    10  )
    11  
    12  func TestFromInt64(t *testing.T) {
    13  	for n := 0; n < 20; n++ {
    14  		r := rand.Int63()
    15  		require.Equal(t, r, NewInt(r).Int64())
    16  	}
    17  }
    18  
    19  func TestFromUint64(t *testing.T) {
    20  	for n := 0; n < 20; n++ {
    21  		r := rand.Uint64()
    22  		require.True(t, NewIntFromUint64(r).IsUint64())
    23  		require.Equal(t, r, NewIntFromUint64(r).Uint64())
    24  	}
    25  }
    26  
    27  func TestIntPanic(t *testing.T) {
    28  	// Max Int = 2^255-1 = 5.789e+76
    29  	// Min Int = -(2^255-1) = -5.789e+76
    30  	require.NotPanics(t, func() { NewIntWithDecimal(1, 76) })
    31  	i1 := NewIntWithDecimal(1, 76)
    32  	require.NotPanics(t, func() { NewIntWithDecimal(2, 76) })
    33  	i2 := NewIntWithDecimal(2, 76)
    34  	require.NotPanics(t, func() { NewIntWithDecimal(3, 76) })
    35  	i3 := NewIntWithDecimal(3, 76)
    36  
    37  	require.Panics(t, func() { NewIntWithDecimal(6, 76) })
    38  	require.Panics(t, func() { NewIntWithDecimal(9, 80) })
    39  
    40  	// Overflow check
    41  	require.NotPanics(t, func() { i1.Add(i1) })
    42  	require.NotPanics(t, func() { i2.Add(i2) })
    43  	require.Panics(t, func() { i3.Add(i3) })
    44  
    45  	require.NotPanics(t, func() { i1.Sub(i1.Neg()) })
    46  	require.NotPanics(t, func() { i2.Sub(i2.Neg()) })
    47  	require.Panics(t, func() { i3.Sub(i3.Neg()) })
    48  
    49  	require.Panics(t, func() { i1.Mul(i1) })
    50  	require.Panics(t, func() { i2.Mul(i2) })
    51  	require.Panics(t, func() { i3.Mul(i3) })
    52  
    53  	require.Panics(t, func() { i1.Neg().Mul(i1.Neg()) })
    54  	require.Panics(t, func() { i2.Neg().Mul(i2.Neg()) })
    55  	require.Panics(t, func() { i3.Neg().Mul(i3.Neg()) })
    56  
    57  	// Underflow check
    58  	i3n := i3.Neg()
    59  	require.NotPanics(t, func() { i3n.Sub(i1) })
    60  	require.NotPanics(t, func() { i3n.Sub(i2) })
    61  	require.Panics(t, func() { i3n.Sub(i3) })
    62  
    63  	require.NotPanics(t, func() { i3n.Add(i1.Neg()) })
    64  	require.NotPanics(t, func() { i3n.Add(i2.Neg()) })
    65  	require.Panics(t, func() { i3n.Add(i3.Neg()) })
    66  
    67  	require.Panics(t, func() { i1.Mul(i1.Neg()) })
    68  	require.Panics(t, func() { i2.Mul(i2.Neg()) })
    69  	require.Panics(t, func() { i3.Mul(i3.Neg()) })
    70  
    71  	// Bound check
    72  	intmax := NewIntFromBigInt(new(big.Int).Sub(new(big.Int).Exp(big.NewInt(2), big.NewInt(255), nil), big.NewInt(1)))
    73  	intmin := intmax.Neg()
    74  	require.NotPanics(t, func() { intmax.Add(ZeroInt()) })
    75  	require.NotPanics(t, func() { intmin.Sub(ZeroInt()) })
    76  	require.Panics(t, func() { intmax.Add(OneInt()) })
    77  	require.Panics(t, func() { intmin.Sub(OneInt()) })
    78  
    79  	// Division-by-zero check
    80  	require.Panics(t, func() { i1.Quo(NewInt(0)) })
    81  
    82  	require.NotPanics(t, func() { Int{}.BigInt() })
    83  }
    84  
    85  // Tests below uses randomness
    86  // Since we are using *big.Int as underlying value
    87  // and (U/)Int is immutable value(see TestImmutability(U/)Int)
    88  // it is safe to use randomness in the tests
    89  func TestIdentInt(t *testing.T) {
    90  	for d := 0; d < 1000; d++ {
    91  		n := rand.Int63()
    92  		i := NewInt(n)
    93  
    94  		ifromstr, ok := NewIntFromString(strconv.FormatInt(n, 10))
    95  		require.True(t, ok)
    96  
    97  		cases := []int64{
    98  			i.Int64(),
    99  			i.BigInt().Int64(),
   100  			ifromstr.Int64(),
   101  			NewIntFromBigInt(big.NewInt(n)).Int64(),
   102  			NewIntWithDecimal(n, 0).Int64(),
   103  		}
   104  
   105  		for tcnum, tc := range cases {
   106  			require.Equal(t, n, tc, "Int is modified during conversion. tc #%d", tcnum)
   107  		}
   108  	}
   109  }
   110  
   111  func minint(i1, i2 int64) int64 {
   112  	if i1 < i2 {
   113  		return i1
   114  	}
   115  	return i2
   116  }
   117  
   118  func maxint(i1, i2 int64) int64 {
   119  	if i1 > i2 {
   120  		return i1
   121  	}
   122  	return i2
   123  }
   124  
   125  func TestArithInt(t *testing.T) {
   126  	for d := 0; d < 1000; d++ {
   127  		n1 := int64(rand.Int31())
   128  		i1 := NewInt(n1)
   129  		n2 := int64(rand.Int31())
   130  		i2 := NewInt(n2)
   131  
   132  		cases := []struct {
   133  			ires Int
   134  			nres int64
   135  		}{
   136  			{i1.Add(i2), n1 + n2},
   137  			{i1.Sub(i2), n1 - n2},
   138  			{i1.Mul(i2), n1 * n2},
   139  			{i1.Quo(i2), n1 / n2},
   140  			{i1.AddRaw(n2), n1 + n2},
   141  			{i1.SubRaw(n2), n1 - n2},
   142  			{i1.MulRaw(n2), n1 * n2},
   143  			{i1.QuoRaw(n2), n1 / n2},
   144  			{MinInt(i1, i2), minint(n1, n2)},
   145  			{MaxInt(i1, i2), maxint(n1, n2)},
   146  			{i1.Neg(), -n1},
   147  		}
   148  
   149  		for tcnum, tc := range cases {
   150  			require.Equal(t, tc.nres, tc.ires.Int64(), "Int arithmetic operation does not match with int64 operation. tc #%d", tcnum)
   151  		}
   152  	}
   153  
   154  }
   155  
   156  func TestCompInt(t *testing.T) {
   157  	for d := 0; d < 1000; d++ {
   158  		n1 := int64(rand.Int31())
   159  		i1 := NewInt(n1)
   160  		n2 := int64(rand.Int31())
   161  		i2 := NewInt(n2)
   162  
   163  		cases := []struct {
   164  			ires bool
   165  			nres bool
   166  		}{
   167  			{i1.Equal(i2), n1 == n2},
   168  			{i1.GT(i2), n1 > n2},
   169  			{i1.LT(i2), n1 < n2},
   170  		}
   171  
   172  		for tcnum, tc := range cases {
   173  			require.Equal(t, tc.nres, tc.ires, "Int comparison operation does not match with int64 operation. tc #%d", tcnum)
   174  		}
   175  	}
   176  }
   177  
   178  func minuint(i1, i2 uint64) uint64 {
   179  	if i1 < i2 {
   180  		return i1
   181  	}
   182  	return i2
   183  }
   184  
   185  func maxuint(i1, i2 uint64) uint64 {
   186  	if i1 > i2 {
   187  		return i1
   188  	}
   189  	return i2
   190  }
   191  
   192  func randint() Int {
   193  	return NewInt(rand.Int63())
   194  }
   195  
   196  func TestImmutabilityAllInt(t *testing.T) {
   197  	ops := []func(*Int){
   198  		func(i *Int) { _ = i.Add(randint()) },
   199  		func(i *Int) { _ = i.Sub(randint()) },
   200  		func(i *Int) { _ = i.Mul(randint()) },
   201  		func(i *Int) { _ = i.Quo(randint()) },
   202  		func(i *Int) { _ = i.AddRaw(rand.Int63()) },
   203  		func(i *Int) { _ = i.SubRaw(rand.Int63()) },
   204  		func(i *Int) { _ = i.MulRaw(rand.Int63()) },
   205  		func(i *Int) { _ = i.QuoRaw(rand.Int63()) },
   206  		func(i *Int) { _ = i.Neg() },
   207  		func(i *Int) { _ = i.IsZero() },
   208  		func(i *Int) { _ = i.Sign() },
   209  		func(i *Int) { _ = i.Equal(randint()) },
   210  		func(i *Int) { _ = i.GT(randint()) },
   211  		func(i *Int) { _ = i.LT(randint()) },
   212  		func(i *Int) { _ = i.String() },
   213  	}
   214  
   215  	for i := 0; i < 1000; i++ {
   216  		n := rand.Int63()
   217  		ni := NewInt(n)
   218  
   219  		for opnum, op := range ops {
   220  			op(&ni)
   221  
   222  			require.Equal(t, n, ni.Int64(), "Int is modified by operation. tc #%d", opnum)
   223  			require.Equal(t, NewInt(n), ni, "Int is modified by operation. tc #%d", opnum)
   224  		}
   225  	}
   226  }
   227  
   228  type intop func(Int, *big.Int) (Int, *big.Int)
   229  
   230  func intarith(uifn func(Int, Int) Int, bifn func(*big.Int, *big.Int, *big.Int) *big.Int) intop {
   231  	return func(ui Int, bi *big.Int) (Int, *big.Int) {
   232  		r := rand.Int63()
   233  		br := new(big.Int).SetInt64(r)
   234  		return uifn(ui, NewInt(r)), bifn(new(big.Int), bi, br)
   235  	}
   236  }
   237  
   238  func intarithraw(uifn func(Int, int64) Int, bifn func(*big.Int, *big.Int, *big.Int) *big.Int) intop {
   239  	return func(ui Int, bi *big.Int) (Int, *big.Int) {
   240  		r := rand.Int63()
   241  		br := new(big.Int).SetInt64(r)
   242  		return uifn(ui, r), bifn(new(big.Int), bi, br)
   243  	}
   244  }
   245  
   246  func TestImmutabilityArithInt(t *testing.T) {
   247  	size := 500
   248  
   249  	ops := []intop{
   250  		intarith(Int.Add, (*big.Int).Add),
   251  		intarith(Int.Sub, (*big.Int).Sub),
   252  		intarith(Int.Mul, (*big.Int).Mul),
   253  		intarith(Int.Quo, (*big.Int).Quo),
   254  		intarithraw(Int.AddRaw, (*big.Int).Add),
   255  		intarithraw(Int.SubRaw, (*big.Int).Sub),
   256  		intarithraw(Int.MulRaw, (*big.Int).Mul),
   257  		intarithraw(Int.QuoRaw, (*big.Int).Quo),
   258  	}
   259  
   260  	for i := 0; i < 100; i++ {
   261  		uis := make([]Int, size)
   262  		bis := make([]*big.Int, size)
   263  
   264  		n := rand.Int63()
   265  		ui := NewInt(n)
   266  		bi := new(big.Int).SetInt64(n)
   267  
   268  		for j := 0; j < size; j++ {
   269  			op := ops[rand.Intn(len(ops))]
   270  			uis[j], bis[j] = op(ui, bi)
   271  		}
   272  
   273  		for j := 0; j < size; j++ {
   274  			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())
   275  			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())
   276  			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())
   277  		}
   278  	}
   279  }
   280  
   281  func TestEncodingRandom(t *testing.T) {
   282  	for i := 0; i < 1000; i++ {
   283  		n := rand.Int63()
   284  		ni := NewInt(n)
   285  		var ri Int
   286  
   287  		str, err := ni.MarshalAmino()
   288  		require.Nil(t, err)
   289  		err = (&ri).UnmarshalAmino(str)
   290  		require.Nil(t, err)
   291  
   292  		require.Equal(t, ni, ri, "MarshalAmino * UnmarshalAmino is not identity. tc #%d, Expected %s, Actual %s", i, ni.String(), ri.String())
   293  		require.True(t, ni.i != ri.i, "Pointer addresses are equal. tc #%d", i)
   294  
   295  		bz, err := ni.MarshalJSON()
   296  		require.Nil(t, err)
   297  		err = (&ri).UnmarshalJSON(bz)
   298  		require.Nil(t, err)
   299  
   300  		require.Equal(t, ni, ri, "MarshalJSON * UnmarshalJSON is not identity. tc #%d, Expected %s, Actual %s", i, ni.String(), ri.String())
   301  		require.True(t, ni.i != ri.i, "Pointer addresses are equal. tc #%d", i)
   302  	}
   303  
   304  	for i := 0; i < 1000; i++ {
   305  		n := rand.Uint64()
   306  		ni := NewUint(n)
   307  		var ri Uint
   308  
   309  		str, err := ni.MarshalAmino()
   310  		require.Nil(t, err)
   311  		err = (&ri).UnmarshalAmino(str)
   312  		require.Nil(t, err)
   313  
   314  		require.Equal(t, ni, ri, "MarshalAmino * UnmarshalAmino is not identity. tc #%d, Expected %s, Actual %s", i, ni.String(), ri.String())
   315  		require.True(t, ni.i != ri.i, "Pointer addresses are equal. tc #%d", i)
   316  
   317  		bz, err := ni.MarshalJSON()
   318  		require.Nil(t, err)
   319  		err = (&ri).UnmarshalJSON(bz)
   320  		require.Nil(t, err)
   321  
   322  		require.Equal(t, ni, ri, "MarshalJSON * UnmarshalJSON is not identity. tc #%d, Expected %s, Actual %s", i, ni.String(), ri.String())
   323  		require.True(t, ni.i != ri.i, "Pointer addresses are equal. tc #%d", i)
   324  	}
   325  }
   326  
   327  func TestEncodingTableInt(t *testing.T) {
   328  	var i Int
   329  
   330  	cases := []struct {
   331  		i   Int
   332  		bz  []byte
   333  		str string
   334  	}{
   335  		{NewInt(0), []byte("\"0\""), "0"},
   336  		{NewInt(100), []byte("\"100\""), "100"},
   337  		{NewInt(51842), []byte("\"51842\""), "51842"},
   338  		{NewInt(19513368), []byte("\"19513368\""), "19513368"},
   339  		{NewInt(999999999999), []byte("\"999999999999\""), "999999999999"},
   340  	}
   341  
   342  	for tcnum, tc := range cases {
   343  		bz, err := tc.i.MarshalJSON()
   344  		require.Nil(t, err, "Error marshaling Int. tc #%d, err %s", tcnum, err)
   345  		require.Equal(t, tc.bz, bz, "Marshaled value is different from exported. tc #%d", tcnum)
   346  		err = (&i).UnmarshalJSON(bz)
   347  		require.Nil(t, err, "Error unmarshaling Int. tc #%d, err %s", tcnum, err)
   348  		require.Equal(t, tc.i, i, "Unmarshaled value is different from exported. tc #%d", tcnum)
   349  
   350  		str, err := tc.i.MarshalAmino()
   351  		require.Nil(t, err, "Error marshaling Int. tc #%d, err %s", tcnum, err)
   352  		require.Equal(t, tc.str, str, "Marshaled value is different from exported. tc #%d", tcnum)
   353  		err = (&i).UnmarshalAmino(str)
   354  		require.Nil(t, err, "Error unmarshaling Int. tc #%d, err %s", tcnum, err)
   355  		require.Equal(t, tc.i, i, "Unmarshaled value is different from exported. tc #%d", tcnum)
   356  	}
   357  }
   358  
   359  func TestEncodingTableUint(t *testing.T) {
   360  	var i Uint
   361  
   362  	cases := []struct {
   363  		i   Uint
   364  		bz  []byte
   365  		str string
   366  	}{
   367  		{NewUint(0), []byte("\"0\""), "0"},
   368  		{NewUint(100), []byte("\"100\""), "100"},
   369  		{NewUint(51842), []byte("\"51842\""), "51842"},
   370  		{NewUint(19513368), []byte("\"19513368\""), "19513368"},
   371  		{NewUint(999999999999), []byte("\"999999999999\""), "999999999999"},
   372  	}
   373  
   374  	for tcnum, tc := range cases {
   375  		bz, err := tc.i.MarshalJSON()
   376  		require.Nil(t, err, "Error marshaling Int. tc #%d, err %s", tcnum, err)
   377  		require.Equal(t, tc.bz, bz, "Marshaled value is different from exported. tc #%d", tcnum)
   378  		err = (&i).UnmarshalJSON(bz)
   379  		require.Nil(t, err, "Error unmarshaling Int. tc #%d, err %s", tcnum, err)
   380  		require.Equal(t, tc.i, i, "Unmarshaled value is different from exported. tc #%d", tcnum)
   381  
   382  		str, err := tc.i.MarshalAmino()
   383  		require.Nil(t, err, "Error marshaling Int. tc #%d, err %s", tcnum, err)
   384  		require.Equal(t, tc.str, str, "Marshaled value is different from exported. tc #%d", tcnum)
   385  		err = (&i).UnmarshalAmino(str)
   386  		require.Nil(t, err, "Error unmarshaling Int. tc #%d, err %s", tcnum, err)
   387  		require.Equal(t, tc.i, i, "Unmarshaled value is different from exported. tc #%d", tcnum)
   388  	}
   389  }
   390  
   391  func TestSerializationOverflow(t *testing.T) {
   392  	bx, _ := new(big.Int).SetString("91888242871839275229946405745257275988696311157297823662689937894645226298583", 10)
   393  	x := Int{bx}
   394  	y := new(Int)
   395  
   396  	// require amino deserialization to fail due to overflow
   397  	xStr, err := x.MarshalAmino()
   398  	require.NoError(t, err)
   399  
   400  	err = y.UnmarshalAmino(xStr)
   401  	require.Error(t, err)
   402  
   403  	// require JSON deserialization to fail due to overflow
   404  	bz, err := x.MarshalJSON()
   405  	require.NoError(t, err)
   406  
   407  	err = y.UnmarshalJSON(bz)
   408  	require.Error(t, err)
   409  }