Files
jiu/backend/internal/util/redeem_code_test.go
T
wangjia 9b6dba4c2b test(backend): 补 redeem_code 单测 + gitignore todo/ 与 gencode 产物
覆盖 NormalizeCode 边界/幂等、GenerateRedeemCode 格式/无歧义字母表
(剔除 0/O/1/I/L)/无碰撞。.gitignore 忽略全局 todo skill 本地数据
与 backend/gencode 构建产物。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y2Wdwo7SmgBJU37cBrkhPK
2026-06-19 14:04:22 +08:00

95 lines
2.6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package util
import (
"strings"
"testing"
)
func TestNormalizeCode(t *testing.T) {
cases := []struct {
name string
in string
want string
}{
{"展示格式带连字符", "JIUKU-YD9S-7CAP", "JIUKUYD9S7CAP"},
{"小写转大写", "jiuku-yd9s-7cap", "JIUKUYD9S7CAP"},
{"去除空格", "JIUKU YD9S 7CAP", "JIUKUYD9S7CAP"},
{"去除制表/换行/回车", "JIUKU\tYD9S\n7CAP\r", "JIUKUYD9S7CAP"},
{"已归一化幂等", "JIUKUYD9S7CAP", "JIUKUYD9S7CAP"},
{"空串", "", ""},
{"混合大小写与分隔", " jiUKu--yd9s 7caP\n", "JIUKUYD9S7CAP"},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
if got := NormalizeCode(c.in); got != c.want {
t.Fatalf("NormalizeCode(%q) = %q, want %q", c.in, got, c.want)
}
})
}
}
func TestNormalizeCodeIdempotent(t *testing.T) {
// 二次归一化结果不变
once := NormalizeCode("jiuku-yd9s-7cap")
if twice := NormalizeCode(once); twice != once {
t.Fatalf("NormalizeCode 非幂等: %q -> %q", once, twice)
}
}
func TestGenerateRedeemCodeFormat(t *testing.T) {
for i := 0; i < 200; i++ {
code := GenerateRedeemCode()
// 展示格式:JIUKU-XXXX-XXXX
parts := strings.Split(code, "-")
if len(parts) != 3 {
t.Fatalf("码段数应为 3,得到 %d%q", len(parts), code)
}
if parts[0] != "JIUKU" {
t.Fatalf("前缀应为 JIUKU,得到 %q%q", parts[0], code)
}
if len(parts[1]) != 4 || len(parts[2]) != 4 {
t.Fatalf("随机段长度应各为 4,得到 %d/%d%q", len(parts[1]), len(parts[2]), code)
}
// 归一化后 = 前缀 + 8 位随机
norm := NormalizeCode(code)
if len(norm) != len("JIUKU")+8 {
t.Fatalf("归一化长度应为 %d,得到 %d%q", len("JIUKU")+8, len(norm), norm)
}
// 随机段只含无歧义字母表字符(不含 0/O/1/I/L)
random := parts[1] + parts[2]
for _, r := range random {
if !strings.ContainsRune(codeAlphabet, r) {
t.Fatalf("出现字母表外字符 %q%q", r, code)
}
}
}
}
func TestCodeAlphabetExcludesAmbiguous(t *testing.T) {
for _, bad := range []rune{'0', 'O', '1', 'I', 'L'} {
if strings.ContainsRune(codeAlphabet, bad) {
t.Fatalf("字母表不应包含易混字符 %q", bad)
}
}
}
func TestGenerateRedeemCodeUnique(t *testing.T) {
// 不要求绝对唯一,但大量生成应几乎无碰撞(31^8 空间)
const n = 1000
seen := make(map[string]struct{}, n)
dup := 0
for i := 0; i < n; i++ {
c := NormalizeCode(GenerateRedeemCode())
if _, ok := seen[c]; ok {
dup++
}
seen[c] = struct{}{}
}
if dup > 0 {
t.Fatalf("%d 次生成出现 %d 次重复,随机性可疑", n, dup)
}
}