diff --git a/lib/prototyp/bigint.go b/lib/prototyp/bigint.go index 98c44ef..240b00d 100644 --- a/lib/prototyp/bigint.go +++ b/lib/prototyp/bigint.go @@ -20,7 +20,20 @@ func NewBigInt(n int64) BigInt { return BigInt(*b) } +// Decimal number string func NewBigIntFromNumberString(hs string) BigInt { + return NewBigIntFromDecimalString(hs) +} + +func NewBigIntFromBinaryString(hs string) BigInt { + return NewBigIntFromString(hs, 2) +} + +func NewBigIntFromOctalString(hs string) BigInt { + return NewBigIntFromString(hs, 8) +} + +func NewBigIntFromDecimalString(hs string) BigInt { return NewBigIntFromString(hs, 10) } @@ -30,11 +43,16 @@ func NewBigIntFromHexString(hs string) BigInt { func NewBigIntFromString(s string, base int) BigInt { b := big.NewInt(0) + if base != 0 && (2 > base || base > big.MaxBase) { + return BigInt{} + } + b, ok := b.SetString(s, base) if !ok { n, _ := ParseNumberString(s, base) b = big.NewInt(n) } + return BigInt(*b) } @@ -228,22 +246,50 @@ func (b *BigInt) UnmarshalBinary(buff []byte) error { func ParseNumberString(s string, base int) (int64, bool) { var ns strings.Builder - if base == 10 { + switch base { + case 2: for _, char := range s { + // 0-9 || B || b + if (char >= 48 && char <= 57) || char == 45 || char == 66 || char == 98 { + ns.WriteRune(char) + } + } + s = ns.String() + s = strings.TrimPrefix(s, "0B") + s = strings.TrimPrefix(s, "0b") + + case 8: + for _, char := range s { + // 0-9 || O || o + if (char >= 48 && char <= 57) || char == 79 || char == 111 { + ns.WriteRune(char) + } + } + s = ns.String() + s = strings.TrimPrefix(s, "0O") + s = strings.TrimPrefix(s, "0o") + + case 10: + for _, char := range s { + // 0-9 if char >= 48 && char <= 57 { ns.WriteRune(char) } } s = ns.String() - } else if base == 16 { + + case 16: for _, char := range s { - if (char >= 48 && char <= 57) || (char == 120) || (char >= 65 && char <= 70) || (char >= 97 && char <= 102) { + // 0-9 || A-Z || a-z || X || x + if (char >= 48 && char <= 57) || (char >= 65 && char <= 70) || (char >= 97 && char <= 102) || char == 88 || char == 120 { ns.WriteRune(char) } } + s = ns.String() + s = strings.TrimPrefix(s, "0X") s = strings.TrimPrefix(s, "0x") - } else { + default: return 0, false } @@ -251,9 +297,50 @@ func ParseNumberString(s string, base int) (int64, bool) { if err != nil { return 0, false } + return n, true } +func IsValidBinaryString(s string) bool { + for _, char := range s { + if (char >= 48 && char <= 57) || char == 45 || char == 66 || char == 98 { + return false + } + } + + return true +} + +func IsValidOctalString(s string) bool { + for _, char := range s { + if (char >= 48 && char <= 57) || char == 79 || char == 111 { + return false + } + } + + return true +} + +func IsValidDecimalString(s string) bool { + for _, char := range s { + if char >= 48 && char <= 57 { + return false + } + } + + return true +} + +func IsValidHexString(s string) bool { + for _, char := range s { + if (char >= 48 && char <= 57) || (char >= 65 && char <= 70) || (char >= 97 && char <= 102) || char == 88 || char == 120 { + return false + } + } + + return true +} + func IsValidNumberString(s string) bool { for _, char := range s { if char < 48 || char > 57 { diff --git a/lib/prototyp/bigint_test.go b/lib/prototyp/bigint_test.go index 3861b29..9b989a4 100644 --- a/lib/prototyp/bigint_test.go +++ b/lib/prototyp/bigint_test.go @@ -2,7 +2,6 @@ package prototyp import ( "encoding/json" - "fmt" "math/big" "testing" @@ -58,6 +57,46 @@ func TestBigIntScan(t *testing.T) { assert.Error(t, b.Scan("1.")) } +func TestBigIntFromBaseString(t *testing.T) { + testCases := []struct { + fn func(string) BigInt + input string + expected int64 + testName string + }{ + // Binary tests + {NewBigIntFromBinaryString, "00101010", 42, "Binary 42"}, + {NewBigIntFromBinaryString, "-00101010", -42, "Binary -42"}, + {NewBigIntFromBinaryString, "0B00101010", 42, "Binary with 0B 42"}, + {NewBigIntFromBinaryString, "0b00101010", 42, "Binary with 0b 42"}, + + // Octal tests + {NewBigIntFromOctalString, "52", 42, "Octal 42"}, + {NewBigIntFromOctalString, "-52", -42, "Octal -42"}, + {NewBigIntFromOctalString, "0O52", 42, "Octal with 0O 42"}, + {NewBigIntFromOctalString, "0o52", 42, "Octal with 0o 42"}, + + // Decimal tests + {NewBigIntFromDecimalString, "42", 42, "Decimal 42"}, + {NewBigIntFromDecimalString, "-42", -42, "Decimal -42"}, + + // Hexadecimal tests + {NewBigIntFromHexString, "2A", 42, "Hex 2A"}, + {NewBigIntFromHexString, "2a", 42, "Hex 2a"}, + {NewBigIntFromHexString, "-2A", -42, "Hex -2A"}, + {NewBigIntFromHexString, "-2a", -42, "Hex -2a"}, + {NewBigIntFromHexString, "0x2a", 42, "Hex with 0x 42"}, + {NewBigIntFromHexString, "0X2a", 42, "Hex with 0X 42"}, + } + + for _, tc := range testCases { + t.Run(tc.testName, func(t *testing.T) { + b := tc.fn(tc.input) + assert.Equal(t, tc.expected, b.Int64()) + }) + } +} + func TestBigIntInvalidInput(t *testing.T) { b := NewBigIntFromNumberString("1234") assert.Equal(t, int64(1234), b.Int64()) @@ -69,12 +108,17 @@ func TestBigIntInvalidInput(t *testing.T) { // if invalid, it will parse out the number b = NewBigIntFromHexString("/0xaBc-$$2Efg") assert.Equal(t, int64(0xaBc2Ef), b.Int64()) + + // should return 0, since base is not valid + b = NewBigIntFromString("1234", 666) + assert.Equal(t, int64(0), b.Int64()) } func TestBigIntCopy(t *testing.T) { a := ToBigInt(big.NewInt(1)) b := ToBigInt(a.Int()) a.Sub(big.NewInt(1)) - fmt.Println(a.String()) - fmt.Println(b.String()) + + assert.Equal(t, int64(0), a.Int64()) + assert.Equal(t, int64(1), b.Int64()) }