290 lines
7.6 KiB
Go
290 lines
7.6 KiB
Go
package types
|
|
|
|
import (
|
|
"math"
|
|
"math/big"
|
|
"math/rand"
|
|
"strconv"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestUintPanics(t *testing.T) {
|
|
// Max Uint = 1.15e+77
|
|
// Min Uint = 0
|
|
u1 := NewUint(0)
|
|
u2 := OneUint()
|
|
|
|
require.Equal(t, uint64(0), u1.Uint64())
|
|
require.Equal(t, uint64(1), u2.Uint64())
|
|
|
|
require.Panics(t, func() { NewUintFromBigInt(big.NewInt(-5)) })
|
|
require.Panics(t, func() { NewUintFromString("-1") })
|
|
require.NotPanics(t, func() {
|
|
require.True(t, NewUintFromString("0").Equal(ZeroUint()))
|
|
require.True(t, NewUintFromString("5").Equal(NewUint(5)))
|
|
})
|
|
|
|
// Overflow check
|
|
require.True(t, u1.Add(u1).Equal(ZeroUint()))
|
|
require.True(t, u1.Add(OneUint()).Equal(OneUint()))
|
|
require.Equal(t, uint64(0), u1.Uint64())
|
|
require.Equal(t, uint64(1), OneUint().Uint64())
|
|
require.Panics(t, func() { u1.SubUint64(2) })
|
|
require.True(t, u1.SubUint64(0).Equal(ZeroUint()))
|
|
require.True(t, u2.Add(OneUint()).Sub(OneUint()).Equal(OneUint())) // i2 == 1
|
|
require.True(t, u2.Add(OneUint()).Mul(NewUint(5)).Equal(NewUint(10))) // i2 == 10
|
|
require.True(t, NewUint(7).Quo(NewUint(2)).Equal(NewUint(3)))
|
|
require.True(t, NewUint(0).Quo(NewUint(2)).Equal(ZeroUint()))
|
|
require.True(t, NewUint(5).MulUint64(4).Equal(NewUint(20)))
|
|
require.True(t, NewUint(5).MulUint64(0).Equal(ZeroUint()))
|
|
|
|
uintmax := NewUintFromBigInt(new(big.Int).Sub(new(big.Int).Exp(big.NewInt(2), big.NewInt(256), nil), big.NewInt(1)))
|
|
uintmin := ZeroUint()
|
|
|
|
// divs by zero
|
|
require.Panics(t, func() { OneUint().Mul(ZeroUint().SubUint64(uint64(1))) })
|
|
require.Panics(t, func() { OneUint().QuoUint64(0) })
|
|
require.Panics(t, func() { OneUint().Quo(ZeroUint()) })
|
|
require.Panics(t, func() { ZeroUint().QuoUint64(0) })
|
|
require.Panics(t, func() { OneUint().Quo(ZeroUint().Sub(OneUint())) })
|
|
require.Panics(t, func() { uintmax.Add(OneUint()) })
|
|
require.Panics(t, func() { uintmax.Incr() })
|
|
require.Panics(t, func() { uintmin.Sub(OneUint()) })
|
|
require.Panics(t, func() { uintmin.Decr() })
|
|
|
|
require.Equal(t, uint64(0), MinUint(ZeroUint(), OneUint()).Uint64())
|
|
require.Equal(t, uint64(1), MaxUint(ZeroUint(), OneUint()).Uint64())
|
|
|
|
// comparison ops
|
|
require.True(t,
|
|
OneUint().GT(ZeroUint()),
|
|
)
|
|
require.False(t,
|
|
OneUint().LT(ZeroUint()),
|
|
)
|
|
require.True(t,
|
|
OneUint().GTE(ZeroUint()),
|
|
)
|
|
require.False(t,
|
|
OneUint().LTE(ZeroUint()),
|
|
)
|
|
|
|
require.False(t, ZeroUint().GT(OneUint()))
|
|
require.True(t, ZeroUint().LT(OneUint()))
|
|
require.False(t, ZeroUint().GTE(OneUint()))
|
|
require.True(t, ZeroUint().LTE(OneUint()))
|
|
}
|
|
|
|
func TestIdentUint(t *testing.T) {
|
|
for d := 0; d < 1000; d++ {
|
|
n := rand.Uint64()
|
|
i := NewUint(n)
|
|
|
|
ifromstr := NewUintFromString(strconv.FormatUint(n, 10))
|
|
|
|
cases := []uint64{
|
|
i.Uint64(),
|
|
i.BigInt().Uint64(),
|
|
i.i.Uint64(),
|
|
ifromstr.Uint64(),
|
|
NewUintFromBigInt(new(big.Int).SetUint64(n)).Uint64(),
|
|
}
|
|
|
|
for tcnum, tc := range cases {
|
|
require.Equal(t, n, tc, "Uint is modified during conversion. tc #%d", tcnum)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestArithUint(t *testing.T) {
|
|
for d := 0; d < 1000; d++ {
|
|
n1 := uint64(rand.Uint32())
|
|
u1 := NewUint(n1)
|
|
n2 := uint64(rand.Uint32())
|
|
u2 := NewUint(n2)
|
|
|
|
cases := []struct {
|
|
ures Uint
|
|
nres uint64
|
|
}{
|
|
{u1.Add(u2), n1 + n2},
|
|
{u1.Mul(u2), n1 * n2},
|
|
{u1.Quo(u2), n1 / n2},
|
|
{u1.AddUint64(n2), n1 + n2},
|
|
{u1.MulUint64(n2), n1 * n2},
|
|
{u1.QuoUint64(n2), n1 / n2},
|
|
{MinUint(u1, u2), minuint(n1, n2)},
|
|
{MaxUint(u1, u2), maxuint(n1, n2)},
|
|
{u1.Incr(), n1 + 1},
|
|
}
|
|
|
|
for tcnum, tc := range cases {
|
|
require.Equal(t, tc.nres, tc.ures.Uint64(), "Uint arithmetic operation does not match with uint64 operation. tc #%d", tcnum)
|
|
}
|
|
|
|
if n2 > n1 {
|
|
n1, n2 = n2, n1
|
|
u1, u2 = NewUint(n1), NewUint(n2)
|
|
}
|
|
|
|
subs := []struct {
|
|
ures Uint
|
|
nres uint64
|
|
}{
|
|
{u1.Sub(u2), n1 - n2},
|
|
{u1.SubUint64(n2), n1 - n2},
|
|
{u1.Decr(), n1 - 1},
|
|
}
|
|
|
|
for tcnum, tc := range subs {
|
|
require.Equal(t, tc.nres, tc.ures.Uint64(), "Uint subtraction does not match with uint64 operation. tc #%d", tcnum)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestCompUint(t *testing.T) {
|
|
for d := 0; d < 10000; 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},
|
|
{i1.GTE(i2), !i1.LT(i2)},
|
|
{!i1.GTE(i2), i1.LT(i2)},
|
|
{i1.LTE(i2), n1 <= n2},
|
|
{i2.LTE(i1), n2 <= n1},
|
|
}
|
|
|
|
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 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.Quo(randuint()) },
|
|
func(i *Uint) { _ = i.AddUint64(rand.Uint64()) },
|
|
func(i *Uint) { _ = i.SubUint64(rand.Uint64() % i.Uint64()) },
|
|
func(i *Uint) { _ = i.MulUint64(rand.Uint64()) },
|
|
func(i *Uint) { _ = i.QuoUint64(rand.Uint64()) },
|
|
func(i *Uint) { _ = i.IsZero() },
|
|
func(i *Uint) { _ = i.Equal(randuint()) },
|
|
func(i *Uint) { _ = i.GT(randuint()) },
|
|
func(i *Uint) { _ = i.GTE(randuint()) },
|
|
func(i *Uint) { _ = i.LT(randuint()) },
|
|
func(i *Uint) { _ = i.LTE(randuint()) },
|
|
func(i *Uint) { _ = i.String() },
|
|
func(i *Uint) { _ = i.Incr() },
|
|
func(i *Uint) {
|
|
if i.IsZero() {
|
|
return
|
|
}
|
|
|
|
_ = i.Decr()
|
|
},
|
|
}
|
|
|
|
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)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestSafeSub(t *testing.T) {
|
|
testCases := []struct {
|
|
x, y Uint
|
|
expected uint64
|
|
panic bool
|
|
}{
|
|
{NewUint(0), NewUint(0), 0, false},
|
|
{NewUint(10), NewUint(5), 5, false},
|
|
{NewUint(5), NewUint(10), 5, true},
|
|
{NewUint(math.MaxUint64), NewUint(0), math.MaxUint64, false},
|
|
}
|
|
|
|
for i, tc := range testCases {
|
|
tc := tc
|
|
if tc.panic {
|
|
require.Panics(t, func() { tc.x.Sub(tc.y) })
|
|
continue
|
|
}
|
|
require.Equal(
|
|
t, tc.expected, tc.x.Sub(tc.y).Uint64(),
|
|
"invalid subtraction result; x: %s, y: %s, tc: #%d", tc.x, tc.y, i,
|
|
)
|
|
}
|
|
}
|
|
|
|
func TestParseUint(t *testing.T) {
|
|
type args struct {
|
|
s string
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
want Uint
|
|
wantErr bool
|
|
}{
|
|
{"malformed", args{"malformed"}, Uint{}, true},
|
|
{"empty", args{""}, Uint{}, true},
|
|
{"positive", args{"50"}, NewUint(uint64(50)), false},
|
|
{"negative", args{"-1"}, Uint{}, true},
|
|
{"zero", args{"0"}, ZeroUint(), false},
|
|
}
|
|
for _, tt := range tests {
|
|
tt := tt
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got, err := ParseUint(tt.args.s)
|
|
if tt.wantErr {
|
|
require.Error(t, err)
|
|
return
|
|
}
|
|
require.NoError(t, err)
|
|
require.True(t, got.Equal(tt.want))
|
|
})
|
|
}
|
|
}
|
|
|
|
func randuint() Uint {
|
|
return NewUint(rand.Uint64())
|
|
}
|
|
|
|
func TestRelativePow(t *testing.T) {
|
|
tests := []struct {
|
|
args []Uint
|
|
want Uint
|
|
}{
|
|
{[]Uint{ZeroUint(), ZeroUint(), OneUint()}, OneUint()},
|
|
{[]Uint{ZeroUint(), ZeroUint(), NewUint(10)}, NewUint(10)},
|
|
{[]Uint{ZeroUint(), OneUint(), NewUint(10)}, ZeroUint()},
|
|
{[]Uint{NewUint(10), NewUint(2), OneUint()}, NewUint(100)},
|
|
{[]Uint{NewUint(210), NewUint(2), NewUint(100)}, NewUint(441)},
|
|
{[]Uint{NewUint(2100), NewUint(2), NewUint(1000)}, NewUint(4410)},
|
|
{[]Uint{NewUint(1000000001547125958), NewUint(600), NewUint(1000000000000000000)}, NewUint(1000000928276004850)},
|
|
}
|
|
for i, tc := range tests {
|
|
res := RelativePow(tc.args[0], tc.args[1], tc.args[2])
|
|
require.Equal(t, tc.want, res, "unexpected result for test case %d, input: %v, got: %v", i, tc.args, res)
|
|
}
|
|
}
|