diff --git a/examples/gno.land/p/demo/uint256/arithmetic_test.gno b/examples/gno.land/p/demo/uint256/arithmetic_test.gno index 9f45a507754..079d89fa794 100644 --- a/examples/gno.land/p/demo/uint256/arithmetic_test.gno +++ b/examples/gno.land/p/demo/uint256/arithmetic_test.gno @@ -1,6 +1,8 @@ package uint256 -import "testing" +import ( + "testing" +) type binOp2Test struct { x, y, want string @@ -16,30 +18,45 @@ func TestAdd(t *testing.T) { {"18446744073709551615", "18446744073709551615", "36893488147419103230"}, // uint64 overflow } - for _, tc := range tests { - x, err := FromDecimal(tc.x) - if err != nil { - t.Error(err) - continue - } + for _, tt := range tests { + x := MustFromDecimal(tt.x) + y := MustFromDecimal(tt.y) - y, err := FromDecimal(tc.y) - if err != nil { - t.Error(err) - continue - } + want := MustFromDecimal(tt.want) + got := new(Uint).Add(x, y) - want, err := FromDecimal(tc.want) - if err != nil { - t.Error(err) - continue + if got.Neq(want) { + t.Errorf("Add(%s, %s) = %v, want %v", tt.x, tt.y, got.ToString(), want.ToString()) } + } +} - got := &Uint{} - got.Add(x, y) +func TestAddOverflow(t *testing.T) { + tests := []struct { + x, y string + want string + overflow bool + }{ + {"0", "1", "1", false}, + {"1", "0", "1", false}, + {"1", "1", "2", false}, + {"10", "10", "20", false}, + {"18446744073709551615", "18446744073709551615", "36893488147419103230", false}, // uint64 overflow, but not Uint256 overflow + {"115792089237316195423570985008687907853269984665640564039457584007913129639935", "1", "0", true}, // 2^256 - 1 + 1, should overflow + {"57896044618658097711785492504343953926634992332820282019728792003956564819967", "57896044618658097711785492504343953926634992332820282019728792003956564819968", "115792089237316195423570985008687907853269984665640564039457584007913129639935", false}, // (2^255 - 1) + 2^255, no overflow + {"57896044618658097711785492504343953926634992332820282019728792003956564819967", "57896044618658097711785492504343953926634992332820282019728792003956564819969", "0", true}, // (2^255 - 1) + (2^255 + 1), should overflow + } - if got.Neq(want) { - t.Errorf("Add(%s, %s) = %v, want %v", tc.x, tc.y, got.ToString(), want.ToString()) + for _, tt := range tests { + x := MustFromDecimal(tt.x) + y := MustFromDecimal(tt.y) + want, _ := FromDecimal(tt.want) + + got, overflow := new(Uint).AddOverflow(x, y) + + if got.Cmp(want) != 0 || overflow != tt.overflow { + t.Errorf("AddOverflow(%s, %s) = (%s, %v), want (%s, %v)", + tt.x, tt.y, got.ToString(), overflow, tt.want, tt.overflow) } } } @@ -50,33 +67,53 @@ func TestSub(t *testing.T) { {"1", "1", "0"}, {"10", "10", "0"}, {"31337", "1337", "30000"}, - {"2", "3", "115792089237316195423570985008687907853269984665640564039457584007913129639935"}, // underflow + {"2", "3", twoPow256Sub1}, // underflow } for _, tc := range tests { - x, err := FromDecimal(tc.x) - if err != nil { - t.Error(err) - continue - } + x := MustFromDecimal(tc.x) + y := MustFromDecimal(tc.y) - y, err := FromDecimal(tc.y) - if err != nil { - t.Error(err) - continue - } + want := MustFromDecimal(tc.want) - want, err := FromDecimal(tc.want) - if err != nil { - t.Error(err) - continue + got := new(Uint).Sub(x, y) + + if got.Neq(want) { + t.Errorf( + "Sub(%s, %s) = %v, want %v", + tc.x, tc.y, got.ToString(), want.ToString(), + ) } + } +} - got := &Uint{} - got.Sub(x, y) +func TestSubOverflow(t *testing.T) { + tests := []struct { + x, y string + want string + overflow bool + }{ + {"1", "0", "1", false}, + {"1", "1", "0", false}, + {"10", "10", "0", false}, + {"31337", "1337", "30000", false}, + {"0", "1", "115792089237316195423570985008687907853269984665640564039457584007913129639935", true}, // 0 - 1, should underflow + {"57896044618658097711785492504343953926634992332820282019728792003956564819968", "1", "57896044618658097711785492504343953926634992332820282019728792003956564819967", false}, // 2^255 - 1, no underflow + {"57896044618658097711785492504343953926634992332820282019728792003956564819968", "57896044618658097711785492504343953926634992332820282019728792003956564819969", "115792089237316195423570985008687907853269984665640564039457584007913129639935", true}, // 2^255 - (2^255 + 1), should underflow + } - if got.Neq(want) { - t.Errorf("Sub(%s, %s) = %v, want %v", tc.x, tc.y, got.ToString(), want.ToString()) + for _, tc := range tests { + x := MustFromDecimal(tc.x) + y := MustFromDecimal(tc.y) + want := MustFromDecimal(tc.want) + + got, overflow := new(Uint).SubOverflow(x, y) + + if got.Cmp(want) != 0 || overflow != tc.overflow { + t.Errorf( + "SubOverflow(%s, %s) = (%s, %v), want (%s, %v)", + tc.x, tc.y, got.ToString(), overflow, tc.want, tc.overflow, + ) } } } @@ -89,30 +126,50 @@ func TestMul(t *testing.T) { {"18446744073709551615", "2", "36893488147419103230"}, // uint64 overflow } - for _, tc := range tests { - x, err := FromDecimal(tc.x) - if err != nil { - t.Error(err) - continue - } + for _, tt := range tests { + x := MustFromDecimal(tt.x) + y := MustFromDecimal(tt.y) + want := MustFromDecimal(tt.want) + got := new(Uint).Mul(x, y) - y, err := FromDecimal(tc.y) - if err != nil { - t.Error(err) - continue + if got.Neq(want) { + t.Errorf("Mul(%s, %s) = %v, want %v", tt.x, tt.y, got.ToString(), want.ToString()) } + } +} - want, err := FromDecimal(tc.want) - if err != nil { - t.Error(err) - continue - } +func TestMulOverflow(t *testing.T) { + tests := []struct { + x string + y string + wantZ string + wantOver bool + }{ + {"0x1", "0x1", "0x1", false}, + {"0x0", "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0x0", false}, + {"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0x2", "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe", true}, + {"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0x1", true}, + {"0x8000000000000000000000000000000000000000000000000000000000000000", "0x2", "0x0", true}, + {"0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0x2", "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe", false}, + {"0x100000000000000000", "0x100000000000000000", "0x10000000000000000000000000000000000", false}, + {"0x10000000000000000000000000000000", "0x10000000000000000000000000000000", "0x100000000000000000000000000000000000000000000000000000000000000", false}, + } - got := &Uint{} - got.Mul(x, y) + for _, tt := range tests { + x := MustFromHex(tt.x) + y := MustFromHex(tt.y) + wantZ := MustFromHex(tt.wantZ) - if got.Neq(want) { - t.Errorf("Mul(%s, %s) = %v, want %v", tc.x, tc.y, got.ToString(), want.ToString()) + gotZ, gotOver := new(Uint).MulOverflow(x, y) + + if gotZ.Neq(wantZ) { + t.Errorf( + "MulOverflow(%s, %s) = %s, want %s", + tt.x, tt.y, gotZ.ToString(), wantZ.ToString(), + ) + } + if gotOver != tt.wantOver { + t.Errorf("MulOverflow(%s, %s) = %v, want %v", tt.x, tt.y, gotOver, tt.wantOver) } } } @@ -123,32 +180,19 @@ func TestDiv(t *testing.T) { {"31337", "0", "0"}, {"0", "31337", "0"}, {"1", "1", "1"}, + {"1000000000000000000", "3", "333333333333333333"}, + {twoPow256Sub1, "2", "57896044618658097711785492504343953926634992332820282019728792003956564819967"}, } - for _, tc := range tests { - x, err := FromDecimal(tc.x) - if err != nil { - t.Error(err) - continue - } - - y, err := FromDecimal(tc.y) - if err != nil { - t.Error(err) - continue - } - - want, err := FromDecimal(tc.want) - if err != nil { - t.Error(err) - continue - } + for _, tt := range tests { + x := MustFromDecimal(tt.x) + y := MustFromDecimal(tt.y) + want := MustFromDecimal(tt.want) - got := &Uint{} - got.Div(x, y) + got := new(Uint).Div(x, y) if got.Neq(want) { - t.Errorf("Div(%s, %s) = %v, want %v", tc.x, tc.y, got.ToString(), want.ToString()) + t.Errorf("Div(%s, %s) = %v, want %v", tt.x, tt.y, got.ToString(), want.ToString()) } } } @@ -160,32 +204,56 @@ func TestMod(t *testing.T) { {"0", "31337", "0"}, {"2", "31337", "2"}, {"1", "1", "0"}, + {"115792089237316195423570985008687907853269984665640564039457584007913129639935", "2", "1"}, // 2^256 - 1 mod 2 + {"115792089237316195423570985008687907853269984665640564039457584007913129639935", "3", "0"}, // 2^256 - 1 mod 3 + {"115792089237316195423570985008687907853269984665640564039457584007913129639935", "57896044618658097711785492504343953926634992332820282019728792003956564819968", "57896044618658097711785492504343953926634992332820282019728792003956564819967"}, // 2^256 - 1 mod 2^255 } - for _, tc := range tests { - x, err := FromDecimal(tc.x) - if err != nil { - t.Error(err) - continue - } + for _, tt := range tests { + x := MustFromDecimal(tt.x) + y := MustFromDecimal(tt.y) + want := MustFromDecimal(tt.want) - y, err := FromDecimal(tc.y) - if err != nil { - t.Error(err) - continue - } + got := new(Uint).Mod(x, y) - want, err := FromDecimal(tc.want) - if err != nil { - t.Error(err) - continue + if got.Neq(want) { + t.Errorf("Mod(%s, %s) = %v, want %v", tt.x, tt.y, got.ToString(), want.ToString()) } + } +} - got := &Uint{} - got.Mod(x, y) +func TestMulMod(t *testing.T) { + tests := []struct { + x string + y string + m string + want string + }{ + {"0x1", "0x1", "0x2", "0x1"}, + {"0x10", "0x10", "0x7", "0x4"}, + {"0x100", "0x100", "0x17", "0x9"}, + {"0x31337", "0x31337", "0x31338", "0x1"}, + {"0x0", "0x31337", "0x31338", "0x0"}, + {"0x31337", "0x0", "0x31338", "0x0"}, + {"0x2", "0x3", "0x5", "0x1"}, + {"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0x0"}, + {"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe", "0x1"}, + {"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0xffffffffffffffffffffffffffffffff", "0x0"}, + } + + for _, tt := range tests { + x := MustFromHex(tt.x) + y := MustFromHex(tt.y) + m := MustFromHex(tt.m) + want := MustFromHex(tt.want) + + got := new(Uint).MulMod(x, y, m) if got.Neq(want) { - t.Errorf("Mod(%s, %s) = %v, want %v", tc.x, tc.y, got.ToString(), want.ToString()) + t.Errorf( + "MulMod(%s, %s, %s) = %s, want %s", + tt.x, tt.y, tt.m, got.ToString(), want.ToString(), + ) } } } @@ -206,30 +274,11 @@ func TestDivMod(t *testing.T) { {"2", "31337", "0", "2"}, } - for _, tc := range tests { - x, err := FromDecimal(tc.x) - if err != nil { - t.Error(err) - continue - } - - y, err := FromDecimal(tc.y) - if err != nil { - t.Error(err) - continue - } - - wantDiv, err := FromDecimal(tc.wantDiv) - if err != nil { - t.Error(err) - continue - } - - wantMod, err := FromDecimal(tc.wantMod) - if err != nil { - t.Error(err) - continue - } + for _, tt := range tests { + x := MustFromDecimal(tt.x) + y := MustFromDecimal(tt.y) + wantDiv := MustFromDecimal(tt.wantDiv) + wantMod := MustFromDecimal(tt.wantMod) gotDiv := new(Uint) gotMod := new(Uint) @@ -237,13 +286,13 @@ func TestDivMod(t *testing.T) { for i := range gotDiv.arr { if gotDiv.arr[i] != wantDiv.arr[i] { - t.Errorf("DivMod(%s, %s) got Div %v, want Div %v", tc.x, tc.y, gotDiv, wantDiv) + t.Errorf("DivMod(%s, %s) got Div %v, want Div %v", tt.x, tt.y, gotDiv, wantDiv) break } } for i := range gotMod.arr { if gotMod.arr[i] != wantMod.arr[i] { - t.Errorf("DivMod(%s, %s) got Mod %v, want Mod %v", tc.x, tc.y, gotMod, wantMod) + t.Errorf("DivMod(%s, %s) got Mod %v, want Mod %v", tt.x, tt.y, gotMod, wantMod) break } } @@ -259,27 +308,17 @@ func TestNeg(t *testing.T) { {"115792089237316195423570985008687907853269984665640564039457584007913129608599", "31337"}, {"0", "0"}, {"2", "115792089237316195423570985008687907853269984665640564039457584007913129639934"}, - {"1", "115792089237316195423570985008687907853269984665640564039457584007913129639935"}, + {"1", twoPow256Sub1}, } - for _, tc := range tests { - x, err := FromDecimal(tc.x) - if err != nil { - t.Error(err) - continue - } - - want, err := FromDecimal(tc.want) - if err != nil { - t.Error(err) - continue - } + for _, tt := range tests { + x := MustFromDecimal(tt.x) + want := MustFromDecimal(tt.want) - got := &Uint{} - got.Neg(x) + got := new(Uint).Neg(x) if got.Neq(want) { - t.Errorf("Neg(%s) = %v, want %v", tc.x, got.ToString(), want.ToString()) + t.Errorf("Neg(%s) = %v, want %v", tt.x, got.ToString(), want.ToString()) } } } @@ -297,30 +336,57 @@ func TestExp(t *testing.T) { {"2", "256", "0"}, // overflow } - for _, tc := range tests { - x, err := FromDecimal(tc.x) - if err != nil { - t.Error(err) - continue - } + for _, tt := range tests { + x := MustFromDecimal(tt.x) + y := MustFromDecimal(tt.y) + want := MustFromDecimal(tt.want) - y, err := FromDecimal(tc.y) - if err != nil { - t.Error(err) - continue - } + got := new(Uint).Exp(x, y) - want, err := FromDecimal(tc.want) - if err != nil { - t.Error(err) - continue + if got.Neq(want) { + t.Errorf( + "Exp(%s, %s) = %v, want %v", + tt.x, tt.y, got.ToString(), want.ToString(), + ) } + } +} + +func TestExp_LargeExponent(t *testing.T) { + tests := []struct { + name string + base string + exponent string + expected string + }{ + { + name: "2^129", + base: "2", + exponent: "680564733841876926926749214863536422912", + expected: "0", + }, + { + name: "2^193", + base: "2", + exponent: "12379400392853802746563808384000000000000000000", + expected: "0", + }, + } - got := &Uint{} - got.Exp(x, y) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + base := MustFromDecimal(tt.base) + exponent := MustFromDecimal(tt.exponent) + expected := MustFromDecimal(tt.expected) - if got.Neq(want) { - t.Errorf("Exp(%s, %s) = %v, want %v", tc.x, tc.y, got.ToString(), want.ToString()) - } + result := new(Uint).Exp(base, exponent) + + if result.Neq(expected) { + t.Errorf( + "Test %s failed. Expected %s, got %s", + tt.name, expected.ToString(), result.ToString(), + ) + } + }) } } diff --git a/examples/gno.land/p/demo/uint256/bitwise_test.gno b/examples/gno.land/p/demo/uint256/bitwise_test.gno index aba89edfabf..3561629fd94 100644 --- a/examples/gno.land/p/demo/uint256/bitwise_test.gno +++ b/examples/gno.land/p/demo/uint256/bitwise_test.gno @@ -37,11 +37,14 @@ func TestOr(t *testing.T) { }, } - for _, tc := range tests { - t.Run(tc.name, func(t *testing.T) { - res := new(Uint).Or(&tc.x, &tc.y) - if *res != tc.want { - t.Errorf("Or(%s, %s) = %s, want %s", tc.x.ToString(), tc.y.ToString(), res.ToString(), (tc.want).ToString()) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + res := new(Uint).Or(&tt.x, &tt.y) + if *res != tt.want { + t.Errorf( + "Or(%s, %s) = %s, want %s", + tt.x.ToString(), tt.y.ToString(), res.ToString(), (tt.want).ToString(), + ) } }) } @@ -93,11 +96,14 @@ func TestAnd(t *testing.T) { }, } - for _, tc := range tests { - t.Run(tc.name, func(t *testing.T) { - res := new(Uint).And(&tc.x, &tc.y) - if *res != tc.want { - t.Errorf("And(%s, %s) = %s, want %s", tc.x.ToString(), tc.y.ToString(), res.ToString(), (tc.want).ToString()) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + res := new(Uint).And(&tt.x, &tt.y) + if *res != tt.want { + t.Errorf( + "And(%s, %s) = %s, want %s", + tt.x.ToString(), tt.y.ToString(), res.ToString(), (tt.want).ToString(), + ) } }) } @@ -126,11 +132,14 @@ func TestNot(t *testing.T) { }, } - for _, tc := range tests { - t.Run(tc.name, func(t *testing.T) { - res := new(Uint).Not(&tc.x) - if *res != tc.want { - t.Errorf("Not(%s) = %s, want %s", tc.x.ToString(), res.ToString(), (tc.want).ToString()) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + res := new(Uint).Not(&tt.x) + if *res != tt.want { + t.Errorf( + "Not(%s) = %s, want %s", + tt.x.ToString(), res.ToString(), (tt.want).ToString(), + ) } }) } @@ -182,11 +191,14 @@ func TestAndNot(t *testing.T) { }, } - for _, tc := range tests { - t.Run(tc.name, func(t *testing.T) { - res := new(Uint).AndNot(&tc.x, &tc.y) - if *res != tc.want { - t.Errorf("AndNot(%s, %s) = %s, want %s", tc.x.ToString(), tc.y.ToString(), res.ToString(), (tc.want).ToString()) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + res := new(Uint).AndNot(&tt.x, &tt.y) + if *res != tt.want { + t.Errorf( + "AndNot(%s, %s) = %s, want %s", + tt.x.ToString(), tt.y.ToString(), res.ToString(), (tt.want).ToString(), + ) } }) } @@ -238,11 +250,14 @@ func TestXor(t *testing.T) { }, } - for _, tc := range tests { - t.Run(tc.name, func(t *testing.T) { - res := new(Uint).Xor(&tc.x, &tc.y) - if *res != tc.want { - t.Errorf("Xor(%s, %s) = %s, want %s", tc.x.ToString(), tc.y.ToString(), res.ToString(), (tc.want).ToString()) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + res := new(Uint).Xor(&tt.x, &tt.y) + if *res != tt.want { + t.Errorf( + "Xor(%s, %s) = %s, want %s", + tt.x.ToString(), tt.y.ToString(), res.ToString(), (tt.want).ToString(), + ) } }) } @@ -272,26 +287,31 @@ func TestLsh(t *testing.T) { {"31337", 193, "393411074163624830192644266310117284962799025126338899061243904"}, {"31337", 255, "57896044618658097711785492504343953926634992332820282019728792003956564819968"}, {"31337", 256, "0"}, - } + // 64 < n < 128 + {"1", 65, "36893488147419103232"}, + {"31337", 100, "39724366859352024754702188346867712"}, - for _, tc := range tests { - x, err := FromDecimal(tc.x) - if err != nil { - t.Error(err) - continue - } + // 128 < n < 192 + {"1", 129, "680564733841876926926749214863536422912"}, + {"31337", 150, "44725660946326664792723507424638829088826130956288"}, - want, err := FromDecimal(tc.want) - if err != nil { - t.Error(err) - continue - } + // 192 < n < 256 + {"1", 193, "12554203470773361527671578846415332832204710888928069025792"}, + {"31337", 200, "50356617492943978264658466087695012475238275216171379079839219712"}, - got := &Uint{} - got.Lsh(x, tc.y) + // n > 256 + {"1", 257, "0"}, + {"31337", 300, "0"}, + } + + for _, tt := range tests { + x := MustFromDecimal(tt.x) + want := MustFromDecimal(tt.want) + + got := new(Uint).Lsh(x, tt.y) if got.Neq(want) { - t.Errorf("Lsh(%s, %d) = %s, want %s", tc.x, tc.y, got.ToString(), want.ToString()) + t.Errorf("Lsh(%s, %d) = %s, want %s", tt.x, tt.y, got.ToString(), want.ToString()) } } } @@ -319,26 +339,85 @@ func TestRsh(t *testing.T) { {"196705537081812415096322133155058642481399512563169449530621952", 192, "31337"}, {"10663428532201448629551770073089320442396672", 128, "31337"}, {"578065619037836218990592", 64, "31337"}, + {twoPow256Sub1, 256, "0"}, + // outliers + {"340282366920938463463374607431768211455", 129, "0"}, + {"18446744073709551615", 65, "0"}, + {twoPow256Sub1, 1, "57896044618658097711785492504343953926634992332820282019728792003956564819967"}, + + // n > 256 + {"1", 257, "0"}, + {"31337", 300, "0"}, } - for _, tc := range tests { - x, err := FromDecimal(tc.x) - if err != nil { - t.Error(err) - continue - } + for _, tt := range tests { + x := MustFromDecimal(tt.x) + + want := MustFromDecimal(tt.want) + got := new(Uint).Rsh(x, tt.y) - want, err := FromDecimal(tc.want) - if err != nil { - t.Error(err) - continue + if got.Neq(want) { + t.Errorf("Rsh(%s, %d) = %s, want %s", tt.x, tt.y, got.ToString(), want.ToString()) } + } +} + +func TestSRsh(t *testing.T) { + tests := []struct { + x string + y uint + want string + }{ + // Positive numbers (behaves like Rsh) + {"0x0", 0, "0x0"}, + {"0x0", 1, "0x0"}, + {"0x1", 0, "0x1"}, + {"0x1", 1, "0x0"}, + {"0x31337", 0, "0x31337"}, + {"0x31337", 4, "0x3133"}, + {"0x31337", 8, "0x313"}, + {"0x31337", 16, "0x3"}, + {"0x10000000000000000", 64, "0x1"}, // 2^64 >> 64 - got := &Uint{} - got.Rsh(x, tc.y) + // // Numbers with MSB set (negative numbers in two's complement) + {"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 0, "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"}, + {"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 1, "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"}, + {"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 4, "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"}, + {"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 64, "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"}, + {"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 128, "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"}, + {"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 192, "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"}, + {"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 255, "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"}, - if got.Neq(want) { - t.Errorf("Rsh(%s, %d) = %s, want %s", tc.x, tc.y, got.ToString(), want.ToString()) + // Large positive number close to max value + {"0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 1, "0x3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"}, + {"0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 2, "0x1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"}, + {"0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 64, "0x7fffffffffffffffffffffffffffffffffffffffffffffff"}, + {"0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 128, "0x7fffffffffffffffffffffffffffffff"}, + {"0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 192, "0x7fffffffffffffff"}, + {"0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 255, "0x0"}, + + // Specific cases + {"0x8000000000000000000000000000000000000000000000000000000000000000", 1, "0xc000000000000000000000000000000000000000000000000000000000000000"}, + {"0x8000000000000000000000000000000000000000000000000000000000000001", 1, "0xc000000000000000000000000000000000000000000000000000000000000000"}, + + {"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 65, "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"}, + {"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 127, "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"}, + {"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 129, "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"}, + {"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 193, "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"}, + + // n > 256 + {"0x1", 257, "0x0"}, + {"0x31337", 300, "0x0"}, + } + + for _, tt := range tests { + x := MustFromHex(tt.x) + want := MustFromHex(tt.want) + + got := new(Uint).SRsh(x, tt.y) + + if !got.Eq(want) { + t.Errorf("SRsh(%s, %d) = %s, want %s", tt.x, tt.y, got.ToString(), want.ToString()) } } } diff --git a/examples/gno.land/p/demo/uint256/cmp_test.gno b/examples/gno.land/p/demo/uint256/cmp_test.gno index 930079f70f0..51c9e70d9a7 100644 --- a/examples/gno.land/p/demo/uint256/cmp_test.gno +++ b/examples/gno.land/p/demo/uint256/cmp_test.gno @@ -5,6 +5,39 @@ import ( "testing" ) +func TestSign(t *testing.T) { + tests := []struct { + input *Uint + expected int + }{ + { + input: NewUint(0), + expected: 0, + }, + { + input: NewUint(1), + expected: 1, + }, + { + input: NewUint(0x7fffffffffffffff), + expected: 1, + }, + { + input: NewUint(0x8000000000000000), + expected: 1, + }, + } + + for _, tt := range tests { + t.Run(tt.input.ToString(), func(t *testing.T) { + result := tt.input.Sign() + if result != tt.expected { + t.Errorf("Sign() = %d; want %d", result, tt.expected) + } + }) + } +} + func TestCmp(t *testing.T) { tests := []struct { x, y string @@ -20,17 +53,8 @@ func TestCmp(t *testing.T) { } for _, tc := range tests { - x, err := FromDecimal(tc.x) - if err != nil { - t.Error(err) - continue - } - - y, err := FromDecimal(tc.y) - if err != nil { - t.Error(err) - continue - } + x := MustFromDecimal(tc.x) + y := MustFromDecimal(tc.y) got := x.Cmp(y) if got != tc.want { @@ -49,16 +73,12 @@ func TestIsZero(t *testing.T) { {"10", false}, } - for _, tc := range tests { - x, err := FromDecimal(tc.x) - if err != nil { - t.Error(err) - continue - } + for _, tt := range tests { + x := MustFromDecimal(tt.x) got := x.IsZero() - if got != tc.want { - t.Errorf("IsZero(%s) = %v, want %v", tc.x, got, tc.want) + if got != tt.want { + t.Errorf("IsZero(%s) = %v, want %v", tt.x, got, tt.want) } } } @@ -77,31 +97,53 @@ func TestLtUint64(t *testing.T) { } for _, tc := range tests { - var x *Uint - var err error - - if strings.HasPrefix(tc.x, "0x") { - x, err = FromHex(tc.x) - if err != nil { - t.Error(err) - continue - } - } else { - x, err = FromDecimal(tc.x) - if err != nil { - t.Error(err) - continue - } - } + x := parseTestString(t, tc.x) got := x.LtUint64(tc.y) - if got != tc.want { t.Errorf("LtUint64(%s, %d) = %v, want %v", tc.x, tc.y, got, tc.want) } } } +func TestUint_GtUint64(t *testing.T) { + tests := []struct { + name string + z string + n uint64 + want bool + }{ + { + name: "z > n", + z: "1", + n: 0, + want: true, + }, + { + name: "z < n", + z: "18446744073709551615", + n: 0xFFFFFFFFFFFFFFFF, + want: false, + }, + { + name: "z == n", + z: "18446744073709551615", + n: 0xFFFFFFFFFFFFFFFF, + want: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + z := MustFromDecimal(tt.z) + + if got := z.GtUint64(tt.n); got != tt.want { + t.Errorf("Uint.GtUint64() = %v, want %v", got, tt.want) + } + }) + } +} + func TestSGT(t *testing.T) { x := MustFromHex("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe") y := MustFromHex("0x0") @@ -127,37 +169,83 @@ func TestEq(t *testing.T) { {"0xffffffffffffffff", "18446744073709551615", true}, {"0x10000000000000000", "18446744073709551616", true}, {"0", "0", true}, - {"115792089237316195423570985008687907853269984665640564039457584007913129639935", "115792089237316195423570985008687907853269984665640564039457584007913129639935", true}, + {twoPow256Sub1, twoPow256Sub1, true}, } - for i, tc := range tests { - var x *Uint - var err error + for _, tt := range tests { + x := parseTestString(t, tt.x) - if strings.HasPrefix(tc.x, "0x") { - x, err = FromHex(tc.x) - if err != nil { - t.Error(err) - continue - } - } else { - x, err = FromDecimal(tc.x) - if err != nil { - t.Error(err) - continue - } + y, err := FromDecimal(tt.y) + if err != nil { + t.Error(err) + continue } - y, err := FromDecimal(tc.y) + got := x.Eq(y) + + if got != tt.want { + t.Errorf("Eq(%s, %s) = %v, want %v", tt.x, tt.y, got, tt.want) + } + } +} + +func TestUint_Lte(t *testing.T) { + tests := []struct { + z, x string + want bool + }{ + {"10", "20", true}, + {"20", "10", false}, + {"10", "10", true}, + {"0", "0", true}, + } + + for _, tt := range tests { + z, err := FromDecimal(tt.z) if err != nil { t.Error(err) continue } + x, err := FromDecimal(tt.x) + if err != nil { + t.Error(err) + continue + } + if got := z.Lte(x); got != tt.want { + t.Errorf("Uint.Lte(%v, %v) = %v, want %v", tt.z, tt.x, got, tt.want) + } + } +} - got := x.Eq(y) +func TestUint_Gte(t *testing.T) { + tests := []struct { + z, x string + want bool + }{ + {"20", "10", true}, + {"10", "20", false}, + {"10", "10", true}, + {"0", "0", true}, + } - if got != tc.want { - t.Errorf("Eq(%s, %s) = %v, want %v", tc.x, tc.y, got, tc.want) + for _, tt := range tests { + z := parseTestString(t, tt.z) + x := parseTestString(t, tt.x) + + if got := z.Gte(x); got != tt.want { + t.Errorf("Uint.Gte(%v, %v) = %v, want %v", tt.z, tt.x, got, tt.want) } } } + +func parseTestString(_ *testing.T, s string) *Uint { + var x *Uint + + if strings.HasPrefix(s, "0x") { + x = MustFromHex(s) + } else { + x = MustFromDecimal(s) + } + + return x +} diff --git a/examples/gno.land/p/demo/uint256/conversion_test.gno b/examples/gno.land/p/demo/uint256/conversion_test.gno index ee3aad0f819..0ea20158be4 100644 --- a/examples/gno.land/p/demo/uint256/conversion_test.gno +++ b/examples/gno.land/p/demo/uint256/conversion_test.gno @@ -14,18 +14,18 @@ func TestIsUint64(t *testing.T) { {"0x10000000000000000", false}, } - for _, tc := range tests { - x := MustFromHex(tc.x) + for _, tt := range tests { + x := MustFromHex(tt.x) got := x.IsUint64() - if got != tc.want { - t.Errorf("IsUint64(%s) = %v, want %v", tc.x, got, tc.want) + if got != tt.want { + t.Errorf("IsUint64(%s) = %v, want %v", tt.x, got, tt.want) } } } func TestDec(t *testing.T) { - testCases := []struct { + tests := []struct { name string z Uint want string @@ -43,16 +43,133 @@ func TestDec(t *testing.T) { { name: "max possible value", z: Uint{arr: [4]uint64{^uint64(0), ^uint64(0), ^uint64(0), ^uint64(0)}}, - want: "115792089237316195423570985008687907853269984665640564039457584007913129639935", + want: twoPow256Sub1, }, } - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - result := tc.z.Dec() - if result != tc.want { - t.Errorf("Dec(%v) = %s, want %s", tc.z, result, tc.want) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := tt.z.Dec() + if result != tt.want { + t.Errorf("Dec(%v) = %s, want %s", tt.z, result, tt.want) } }) } } + +func TestUint_Scan(t *testing.T) { + tests := []struct { + name string + input interface{} + want *Uint + wantErr bool + }{ + { + name: "nil", + input: nil, + want: NewUint(0), + }, + { + name: "valid scientific notation", + input: "1e4", + want: NewUint(10000), + }, + { + name: "valid decimal string", + input: "12345", + want: NewUint(12345), + }, + { + name: "valid byte slice", + input: []byte("12345"), + want: NewUint(12345), + }, + { + name: "invalid string", + input: "invalid", + wantErr: true, + }, + { + name: "out of range", + input: "115792089237316195423570985008687907853269984665640564039457584007913129639936", // 2^256 + wantErr: true, + }, + { + name: "unsupported type", + input: 123, + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + z := new(Uint) + err := z.Scan(tt.input) + + if tt.wantErr { + if err == nil { + t.Errorf("Scan() error = %v, wantErr %v", err, tt.wantErr) + } + } else { + if err != nil { + t.Errorf("Scan() error = %v, wantErr %v", err, tt.wantErr) + } + if !z.Eq(tt.want) { + t.Errorf("Scan() = %v, want %v", z, tt.want) + } + } + }) + } +} + +func TestSetBytes(t *testing.T) { + tests := []struct { + input []byte + expected string + }{ + {[]byte{}, "0"}, + {[]byte{0x01}, "1"}, + {[]byte{0x12, 0x34}, "4660"}, + {[]byte{0x12, 0x34, 0x56}, "1193046"}, + {[]byte{0x12, 0x34, 0x56, 0x78}, "305419896"}, + {[]byte{0x12, 0x34, 0x56, 0x78, 0x9a}, "78187493530"}, + {[]byte{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc}, "20015998343868"}, + {[]byte{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde}, "5124095576030430"}, + {[]byte{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0}, "1311768467463790320"}, + {[]byte{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12}, "335812727670730321938"}, + {[]byte{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34}, "85968058283706962416180"}, + {[]byte{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56}, "22007822920628982378542166"}, + {[]byte{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78}, "5634002667681019488906794616"}, + {[]byte{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a}, "1442304682926340989160139421850"}, + {[]byte{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc}, "369229998829143293224995691993788"}, + {[]byte{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde}, "94522879700260683065598897150409950"}, + {[]byte{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0}, "24197857203266734864793317670504947440"}, + {[]byte{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12}, "6194651444036284125387089323649266544658"}, + {[]byte{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34}, "1585830769673288736099094866854212235432500"}, + {[]byte{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56}, "405972677036361916441368285914678332270720086"}, + {[]byte{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78}, "103929005321308650608990281194157653061304342136"}, + {[]byte{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a}, "26605825362255014555901511985704359183693911586970"}, + {[]byte{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc}, "6811091292737283726310787068340315951025641366264508"}, + {[]byte{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde}, "1743639370940744633935561489495120883462564189763714270"}, + {[]byte{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0}, "446371678960830626287503741310750946166416432579510853360"}, + {[]byte{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12}, "114271149813972640329600957775552242218602606740354778460178"}, + {[]byte{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34}, "29253414352376995924377845190541374007962267325530823285805620"}, + {[]byte{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56}, "7488874074208510956640728368778591746038340435335890761166238806"}, + {[]byte{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78}, "1917151762997378804900026462407319486985815151445988034858557134456"}, + {[]byte{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a}, "490790851327328974054406774376273788668368678770172936923790626420890"}, + {[]byte{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc}, "125642457939796217357928134240326089899102381765164271852490400363748028"}, + {[]byte{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde}, "32164469232587831643629602365523479014170209731882053594237542493119495390"}, + {[]byte{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0}, "8234104123542484900769178205574010627627573691361805720124810878238590820080"}, + // over 32 bytes (last 32 bytes are used) + {append([]byte{0xff}, []byte{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0}...), "8234104123542484900769178205574010627627573691361805720124810878238590820080"}, + } + + for _, test := range tests { + z := new(Uint) + z.SetBytes(test.input) + expected := MustFromDecimal(test.expected) + if z.Cmp(expected) != 0 { + t.Errorf("SetBytes(%x) = %s, expected %s", test.input, z.ToString(), test.expected) + } + } +} diff --git a/examples/gno.land/p/demo/uint256/uint256.gno b/examples/gno.land/p/demo/uint256/uint256.gno index 80da0ba882b..3d183362992 100644 --- a/examples/gno.land/p/demo/uint256/uint256.gno +++ b/examples/gno.land/p/demo/uint256/uint256.gno @@ -5,6 +5,7 @@ package uint256 import ( "errors" "math/bits" + "strconv" ) const ( @@ -143,10 +144,10 @@ func (z *Uint) fromDecimal(bs string) error { if remaining <= 0 { return nil // Done } else if remaining > 19 { - num, err = parseUint(bs[remaining-19:remaining], 10, 64) + num, err = strconv.ParseUint(bs[remaining-19:remaining], 10, 64) } else { // Final round - num, err = parseUint(bs, 10, 64) + num, err = strconv.ParseUint(bs, 10, 64) } if err != nil { return err diff --git a/examples/gno.land/p/demo/uint256/uint256_test.gno b/examples/gno.land/p/demo/uint256/uint256_test.gno new file mode 100644 index 00000000000..0089af15c66 --- /dev/null +++ b/examples/gno.land/p/demo/uint256/uint256_test.gno @@ -0,0 +1,127 @@ +package uint256 + +import ( + "testing" +) + +func TestSetAllOne(t *testing.T) { + z := Zero() + z.SetAllOne() + if z.ToString() != twoPow256Sub1 { + t.Errorf("Expected all ones, got %s", z.ToString()) + } +} + +func TestByte(t *testing.T) { + tests := []struct { + input string + position uint64 + expected byte + }{ + {"0x1000000000000000000000000000000000000000000000000000000000000000", 0, 16}, + {"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 0, 255}, + {"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 31, 255}, + } + + for i, tt := range tests { + z, _ := FromHex(tt.input) + n := NewUint(tt.position) + result := z.Byte(n) + + if result.arr[0] != uint64(tt.expected) { + t.Errorf("Test case %d failed. Input: %s, Position: %d, Expected: %d, Got: %d", + i, tt.input, tt.position, tt.expected, result.arr[0]) + } + + // check other array elements are 0 + if result.arr[1] != 0 || result.arr[2] != 0 || result.arr[3] != 0 { + t.Errorf("Test case %d failed. Non-zero values in upper bytes", i) + } + } + + // overflow + z, _ := FromHex("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff") + n := NewUint(32) + result := z.Byte(n) + + if !result.IsZero() { + t.Errorf("Expected zero for position >= 32, got %v", result) + } +} + +func TestBitLen(t *testing.T) { + tests := []struct { + input string + expected int + }{ + {"0x0", 0}, + {"0x1", 1}, + {"0xff", 8}, + {"0x100", 9}, + {"0xffff", 16}, + {"0x10000", 17}, + {"0xffffffffffffffff", 64}, + {"0x10000000000000000", 65}, + {"0xffffffffffffffffffffffffffffffff", 128}, + {"0x100000000000000000000000000000000", 129}, + {"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 256}, + } + + for i, tt := range tests { + z, _ := FromHex(tt.input) + result := z.BitLen() + + if result != tt.expected { + t.Errorf("Test case %d failed. Input: %s, Expected: %d, Got: %d", + i, tt.input, tt.expected, result) + } + } +} + +func TestByteLen(t *testing.T) { + tests := []struct { + input string + expected int + }{ + {"0x0", 0}, + {"0x1", 1}, + {"0xff", 1}, + {"0x100", 2}, + {"0xffff", 2}, + {"0x10000", 3}, + {"0xffffffffffffffff", 8}, + {"0x10000000000000000", 9}, + {"0xffffffffffffffffffffffffffffffff", 16}, + {"0x100000000000000000000000000000000", 17}, + {"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 32}, + } + + for i, tt := range tests { + z, _ := FromHex(tt.input) + result := z.ByteLen() + + if result != tt.expected { + t.Errorf("Test case %d failed. Input: %s, Expected: %d, Got: %d", + i, tt.input, tt.expected, result) + } + } +} + +func TestClone(t *testing.T) { + tests := []struct { + input string + expected string + }{ + {"0x1", "1"}, + {"0x100", "256"}, + {"0x10000000000000000", "18446744073709551616"}, + } + + for _, tt := range tests { + z, _ := FromHex(tt.input) + result := z.Clone() + if result.ToString() != tt.expected { + t.Errorf("Test %s failed. Expected %s, got %s", tt.input, tt.expected, result.ToString()) + } + } +} diff --git a/examples/gno.land/p/demo/uint256/utils.gno b/examples/gno.land/p/demo/uint256/utils.gno index 969728f3369..bcc7bb283e0 100644 --- a/examples/gno.land/p/demo/uint256/utils.gno +++ b/examples/gno.land/p/demo/uint256/utils.gno @@ -1,63 +1,5 @@ package uint256 -// lower(c) is a lower-case letter if and only if -// c is either that lower-case letter or the equivalent upper-case letter. -// Instead of writing c == 'x' || c == 'X' one can write lower(c) == 'x'. -// Note that lower of non-letters can produce other non-letters. -func lower(c byte) byte { - return c | ('x' - 'X') -} - -// underscoreOK reports whether the underscores in s are allowed. -// Checking them in this one function lets all the parsers skip over them simply. -// Underscore must appear only between digits or between a base prefix and a digit. -func underscoreOK(s string) bool { - // saw tracks the last character (class) we saw: - // ^ for beginning of number, - // 0 for a digit or base prefix, - // _ for an underscore, - // ! for none of the above. - saw := '^' - i := 0 - - // Optional sign. - if len(s) >= 1 && (s[0] == '-' || s[0] == '+') { - s = s[1:] - } - - // Optional base prefix. - hex := false - if len(s) >= 2 && s[0] == '0' && (lower(s[1]) == 'b' || lower(s[1]) == 'o' || lower(s[1]) == 'x') { - i = 2 - saw = '0' // base prefix counts as a digit for "underscore as digit separator" - hex = lower(s[1]) == 'x' - } - - // Number proper. - for ; i < len(s); i++ { - // Digits are always okay. - if '0' <= s[i] && s[i] <= '9' || hex && 'a' <= lower(s[i]) && lower(s[i]) <= 'f' { - saw = '0' - continue - } - // Underscore must follow digit. - if s[i] == '_' { - if saw != '0' { - return false - } - saw = '_' - continue - } - // Underscore must also be followed by digit. - if saw == '_' { - return false - } - // Saw non-digit, non-underscore. - saw = '!' - } - return saw != '_' -} - func checkNumberS(input string) error { const fn = "UnmarshalText" l := len(input) @@ -76,105 +18,3 @@ func checkNumberS(input string) error { } return nil } - -// ParseUint is like ParseUint but for unsigned numbers. -// -// A sign prefix is not permitted. -func parseUint(s string, base int, bitSize int) (uint64, error) { - const fnParseUint = "ParseUint" - - if s == "" { - return 0, errSyntax(fnParseUint, s) - } - - base0 := base == 0 - - s0 := s - switch { - case 2 <= base && base <= 36: - // valid base; nothing to do - - case base == 0: - // Look for octal, hex prefix. - base = 10 - if s[0] == '0' { - switch { - case len(s) >= 3 && lower(s[1]) == 'b': - base = 2 - s = s[2:] - case len(s) >= 3 && lower(s[1]) == 'o': - base = 8 - s = s[2:] - case len(s) >= 3 && lower(s[1]) == 'x': - base = 16 - s = s[2:] - default: - base = 8 - s = s[1:] - } - } - - default: - return 0, errInvalidBase(fnParseUint, base) - } - - if bitSize == 0 { - bitSize = uintSize - } else if bitSize < 0 || bitSize > 64 { - return 0, errInvalidBitSize(fnParseUint, bitSize) - } - - // Cutoff is the smallest number such that cutoff*base > maxUint64. - // Use compile-time constants for common cases. - var cutoff uint64 - switch base { - case 10: - cutoff = MaxUint64/10 + 1 - case 16: - cutoff = MaxUint64/16 + 1 - default: - cutoff = MaxUint64/uint64(base) + 1 - } - - maxVal := uint64(1)<= byte(base) { - return 0, errSyntax(fnParseUint, s0) - } - - if n >= cutoff { - // n*base overflows - return maxVal, errRange(fnParseUint, s0) - } - n *= uint64(base) - - n1 := n + uint64(d) - if n1 < n || n1 > maxVal { - // n+d overflows - return maxVal, errRange(fnParseUint, s0) - } - n = n1 - } - - if underscores && !underscoreOK(s0) { - return 0, errSyntax(fnParseUint, s0) - } - - return n, nil -}