Compare commits

...

2 Commits

Author SHA1 Message Date
徐涛
fbc419f92e test(base36): 添加 Encode 和 EncodeInt64 的模糊测试
为 base36 包添加了两个 fuzz 测试函数,分别用于测试
Encode/Decode 和 EncodeInt64/DecodeToInt64 的正确性。
测试覆盖了字符串和 int64 类型的编码与解码过程,
确保在各种输入下功能的稳定性和正确性。
2025-10-05 09:36:43 +08:00
徐涛
0d486f5d01 (feat):增加Base36编解码功能,待测。 2025-10-03 16:46:45 +08:00
2 changed files with 150 additions and 0 deletions

108
serialize/base36/base36.go Normal file
View File

@@ -0,0 +1,108 @@
package base36
import (
"fmt"
"math/big"
"strings"
)
// Encode 将字节数据编码为Base36字符串(大写),使用=作为padding字符
func Encode(src []byte) string {
if len(src) == 0 {
return ""
}
// 将字节转换为big.Int
num := new(big.Int).SetBytes(src)
// 如果输入为全零字节,则直接返回"0"
if num.Cmp(big.NewInt(0)) == 0 {
return "0"
}
// 进行Base36编码
var result strings.Builder
base := big.NewInt(36)
zero := big.NewInt(0)
remainder := new(big.Int)
// 重复除以36获取余数作为字符
for num.Cmp(zero) > 0 {
num.DivMod(num, base, remainder)
digit := remainder.Int64()
if digit < 10 {
result.WriteString(fmt.Sprintf("%d", digit))
} else {
result.WriteString(fmt.Sprintf("%c", 'A'+digit-10))
}
}
// 反转字符串,因为我们是从低位开始计算的
encoded := result.String()
runes := []rune(encoded)
for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 {
runes[i], runes[j] = runes[j], runes[i]
}
return string(runes)
}
// Decode 将Base36字符串(可为任意大小写)解码为字节数组
func Decode(src string) ([]byte, error) {
if src == "" {
return []byte{}, nil
}
// 移除padding字符
src = strings.ReplaceAll(src, "=", "")
src = strings.ToUpper(src)
// 使用big.Int进行解码
num := big.NewInt(0)
base := big.NewInt(36)
for _, char := range src {
var digit int64
switch {
case char >= '0' && char <= '9':
digit = int64(char - '0')
case char >= 'A' && char <= 'Z':
digit = int64(char - 'A' + 10)
default:
return nil, fmt.Errorf("invalid character %c in base36 string", char)
}
num.Mul(num, base)
num.Add(num, big.NewInt(digit))
}
// 转换为字节数组
return num.Bytes(), nil
}
// EncodeToString 是Encode的别名用于保持与标准库一致的命名
func EncodeToString(src []byte) string {
return Encode(src)
}
// DecodeString 是Decode的别名用于保持与标准库一致的命名
func DecodeString(src string) ([]byte, error) {
return Decode(src)
}
// EncodeInt64 将int64转换为Base36字符串
func EncodeInt64(num int64) string {
return EncodeToString(big.NewInt(num).Bytes())
}
// DecodeToInt64 将Base36字符串解码为int64
func DecodeToInt64(src string) (int64, error) {
bytes, err := DecodeString(src)
if err != nil {
return 0, err
}
return new(big.Int).SetBytes(bytes).Int64(), nil
}

View File

@@ -0,0 +1,42 @@
package base36
import (
"fmt"
"testing"
)
func FuzzEncode(f *testing.F) {
testCases := []string{"a", "abc", "uuid"}
for _, tc := range testCases {
f.Add(tc)
}
f.Fuzz(func(t *testing.T, a string) {
encoded := Encode([]byte(a))
redecoded, err := Decode(encoded)
fmt.Printf("Origin: %s, Encoded: %s\n", a, encoded)
if err != nil {
t.Errorf("Decode(%q) failed: %v", encoded, err)
}
if string(redecoded) != a {
t.Errorf("Decode(%q) = %q, want %q", encoded, redecoded, a)
}
})
}
func FuzzEncodeInt64(f *testing.F) {
testCases := []int64{1, 6, 34598347534, 234532543, 2342546456, 34587639284756293}
for _, tc := range testCases {
f.Add(tc)
}
f.Fuzz(func(t *testing.T, a int64) {
encoded := EncodeInt64(a)
redecoded, err := DecodeToInt64(encoded)
fmt.Printf("Origin: %d, Encoded: %s\n", a, encoded)
if err != nil {
t.Errorf("Decode(%q) failed: %v", encoded, err)
}
if redecoded != a {
t.Errorf("Decode(%q) = %q, want %q", encoded, redecoded, a)
}
})
}