github.com/Finschia/finschia-sdk@v0.48.1/types/int_test.go (about)

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