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)) } }