Files
encryptx/hexx/hexx_test.go
T

280 lines
7.5 KiB
Go
Raw Normal View History

2026-09-30 15:49:12 +08:00
package hexx_test
import (
"bytes"
"encoding/hex"
"strings"
"testing"
"code.yun.ink/pkg/encryptx/hexx"
)
// payloads 覆盖空、单字节、ASCII、UTF-8 与全字节值等输入。
var payloads = [][]byte{
nil,
{},
{0x00},
{0x0f, 0xf0},
[]byte("Hello, World!"),
[]byte("中文与 emoji 🚀"),
bytes.Repeat([]byte{0xde, 0xad, 0xbe, 0xef}, 64),
func() []byte {
b := make([]byte, 256)
for i := range b {
b[i] = byte(i)
}
return b
}(),
}
// TestRoundTrip 校验大小写两种编码都能往返还原。
func TestRoundTrip(t *testing.T) {
for i, payload := range payloads {
lower := hexx.Encode(payload)
upper := hexx.EncodeUpper(payload)
if len(lower) != len(payload)*2 {
t.Errorf("用例 %d: Encode 长度 = %d, 期望 %d", i, len(lower), len(payload)*2)
}
if lower != strings.ToLower(lower) {
t.Errorf("用例 %d: Encode 应输出小写: %q", i, lower)
}
if upper != strings.ToUpper(upper) {
t.Errorf("用例 %d: EncodeUpper 应输出大写: %q", i, upper)
}
if !strings.EqualFold(lower, upper) {
t.Errorf("用例 %d: 大小写编码内容不一致: %q vs %q", i, lower, upper)
}
decodedLower, err := hexx.Decode(lower)
if err != nil {
t.Fatalf("用例 %d: Decode(小写) 失败: %v", i, err)
}
if !bytes.Equal(decodedLower, payload) {
t.Errorf("用例 %d: Decode(小写) 往返不一致", i)
}
decodedUpper, err := hexx.DecodeUpper(upper)
if err != nil {
t.Fatalf("用例 %d: DecodeUpper(大写) 失败: %v", i, err)
}
if !bytes.Equal(decodedUpper, payload) {
t.Errorf("用例 %d: DecodeUpper 往返不一致", i)
}
// 大写编码也必须能被宽松的 Decode 正确解码。
decodedLoose, err := hexx.Decode(upper)
if err != nil {
t.Fatalf("用例 %d: Decode(大写) 失败: %v", i, err)
}
if !bytes.Equal(decodedLoose, payload) {
t.Errorf("用例 %d: Decode(大写) 往返不一致", i)
}
}
}
// TestDecodeMixedCase 校验 Decode 在语义上接受大小写混合输入。
func TestDecodeMixedCase(t *testing.T) {
cases := []struct {
in string
want []byte
}{
{"deadbeef", []byte{0xde, 0xad, 0xbe, 0xef}},
{"DEADBEEF", []byte{0xde, 0xad, 0xbe, 0xef}},
{"DeAdBeEf", []byte{0xde, 0xad, 0xbe, 0xef}},
{"dEaDbEeF", []byte{0xde, 0xad, 0xbe, 0xef}},
{"0a1B2c3D", []byte{0x0a, 0x1b, 0x2c, 0x3d}},
}
for _, c := range cases {
got, err := hexx.Decode(c.in)
if err != nil {
t.Errorf("Decode(%q) 返回错误: %v", c.in, err)
continue
}
if !bytes.Equal(got, c.want) {
t.Errorf("Decode(%q) = %x, 期望 %x", c.in, got, c.want)
}
}
}
// TestEncodeMatchesStdlib 与标准库交叉验证,确保封装未引入行为差异。
func TestEncodeMatchesStdlib(t *testing.T) {
for i, payload := range payloads {
if got, want := hexx.Encode(payload), hex.EncodeToString(payload); got != want {
t.Errorf("用例 %d: Encode = %q, 标准库 = %q", i, got, want)
}
if got, want := hexx.EncodeUpper(payload), strings.ToUpper(hex.EncodeToString(payload)); got != want {
t.Errorf("用例 %d: EncodeUpper = %q, 标准库 = %q", i, got, want)
}
}
}
// TestIsValid 校验 IsValid 对合法与非法输入的判定。
func TestIsValid(t *testing.T) {
valid := []string{
"00", "ff", "FF", "deadbeef", "DEADBEEF", "DeAdBeEf",
"0123456789abcdefABCDEF",
}
for _, s := range valid {
if !hexx.IsValid(s) {
t.Errorf("IsValid(%q) = false, 期望 true", s)
}
}
invalid := []struct {
name string
in string
}{
{"空串", ""},
{"奇数长度", "a"},
{"奇数长度三字符", "abc"},
{"奇数长度长串", strings.Repeat("ab", 20) + "c"},
{"非十六进制字母", "zz"},
{"含 g", "0g"},
{"含 0x 前缀", "0x1f"},
{"含空格", "de ad"},
{"含换行", "dead\n"},
{"含连字符", "de-ad"},
{"非 ASCII 字符", "中文"},
{"emoji", "🚀"},
{"含 tab", "aa\tbb"},
}
for _, c := range invalid {
if hexx.IsValid(c.in) {
t.Errorf("IsValid(%q)(%s)= true, 期望 false", c.in, c.name)
}
}
}
// TestDecodeRejectsInvalid 校验 Decode 对非法输入返回 nil 与 error。
func TestDecodeRejectsInvalid(t *testing.T) {
invalid := []struct {
name string
in string
}{
{"奇数长度", "abc"},
{"奇数长度单字符", "a"},
{"非十六进制字符", "zz"},
{"包含 g", "0g"},
{"0x 前缀", "0x1f"},
{"含空格", "de ad"},
{"含换行", "beef\n"},
{"含连字符", "de-ad"},
{"非 ASCII", "中文"},
{"emoji", "🚀"},
{"长度与内容都非法", "xyz"},
}
for _, c := range invalid {
got, err := hexx.Decode(c.in)
if err == nil {
t.Errorf("Decode(%q)(%s)应当失败,却成功得到 %x", c.in, c.name, got)
}
if got != nil {
t.Errorf("Decode(%q)(%s)失败时应返回 nil,实际 %x", c.in, c.name, got)
}
if err != nil && err.Error() == "" {
t.Errorf("Decode(%q) 返回了空错误信息", c.in)
}
}
}
// TestDecodeUpperStrict 校验 DecodeUpper 在语义上要求输入是大写形式。
func TestDecodeUpperStrict(t *testing.T) {
// 纯大写(含数字)必须成功。
uppers := []struct {
in string
want []byte
}{
{"DEADBEEF", []byte{0xde, 0xad, 0xbe, 0xef}},
{"00FF", []byte{0x00, 0xff}},
{"0A1B2C3D", []byte{0x0a, 0x1b, 0x2c, 0x3d}},
}
for _, c := range uppers {
got, err := hexx.DecodeUpper(c.in)
if err != nil {
t.Errorf("DecodeUpper(%q) 返回错误: %v", c.in, err)
continue
}
if !bytes.Equal(got, c.want) {
t.Errorf("DecodeUpper(%q) = %x, 期望 %x", c.in, got, c.want)
}
}
// 含小写字母的输入必须被拒绝,并返回 nil。
rejected := []string{"deadbeef", "DeadBeef", "DEADbeef", "de"}
for _, in := range rejected {
got, err := hexx.DecodeUpper(in)
if err == nil {
t.Errorf("DecodeUpper(%q) 应当失败(含小写字母),却成功得到 %x", in, got)
}
if got != nil {
t.Errorf("DecodeUpper(%q) 失败时应返回 nil,实际 %x", in, got)
}
}
// 大写但仍非法的输入同样必须失败。
for _, in := range []string{"0X1F", "GG", "ABC", "DE AD"} {
got, err := hexx.DecodeUpper(in)
if err == nil {
t.Errorf("DecodeUpper(%q) 应当失败,却成功得到 %x", in, got)
}
if got != nil {
t.Errorf("DecodeUpper(%q) 失败时应返回 nil,实际 %x", in, got)
}
}
}
// TestDecodeEmpty 校验空串的边界语义。
func TestDecodeEmpty(t *testing.T) {
got, err := hexx.Decode("")
if err != nil {
t.Errorf("Decode(\"\") 应成功: %v", err)
}
if len(got) != 0 {
t.Errorf("Decode(\"\") 得到 %d 字节,期望 0", len(got))
}
// IsValid 明确把空串视为非法。
if hexx.IsValid("") {
t.Error("IsValid(\"\") 应为 false")
}
}
// TestNoPanicOnAnyInput 用一批畸形输入整体验证不 panic。
func TestNoPanicOnAnyInput(t *testing.T) {
defer func() {
if r := recover(); r != nil {
t.Fatalf("畸形输入导致 panic: %v", r)
}
}()
inputs := []string{
"", "0", "00", "000", strings.Repeat("f", 511), strings.Repeat("F", 512),
"\x00\x01\x02", "%$#@!", "ff", "🇨🇳", "AB",
}
for _, in := range inputs {
_ = hexx.IsValid(in)
_, _ = hexx.Decode(in)
_, _ = hexx.DecodeUpper(in)
_ = hexx.Encode([]byte(in))
_ = hexx.EncodeUpper([]byte(in))
}
}
// TestEncodeDecodeNil 校验 nil 输入的处理。
func TestEncodeDecodeNil(t *testing.T) {
if got := hexx.Encode(nil); got != "" {
t.Errorf("Encode(nil) = %q, 期望空串", got)
}
if got := hexx.EncodeUpper(nil); got != "" {
t.Errorf("EncodeUpper(nil) = %q, 期望空串", got)
}
got, err := hexx.Decode(hexx.Encode(nil))
if err != nil {
t.Errorf("Decode(Encode(nil)) 失败: %v", err)
}
if len(got) != 0 {
t.Errorf("Decode(Encode(nil)) 得到 %d 字节,期望 0", len(got))
}
}