- 活动切换并发安全:App/Scheduler 增加 client/cfg 读写锁与快照访问, 支持运行中热替换客户端,切换活动不再静默覆盖用户自定义 timeApiUrl - 启动失败时写入崩溃日志文件便于事后排查 - 前端类型声明从 Wails 自动生成的绑定派生,避免手写契约漂移 - 提取 parseAccountFile 消除 ExportAccounts/OrganizeAccounts 重复解析逻辑 - 删除 utils 中未使用的 ReadJSON/WriteJSON/WriteError 及空目录 internal/app - gofmt 统一格式化(activity/types/scheduler 字段对齐) - 新增 logger/seckill/utils 单元测试 - 清理 git 中遗留产物(frontend/app.js、yml.txt、其他日志/)并补全 .gitignore
118 lines
3.1 KiB
Go
118 lines
3.1 KiB
Go
package utils
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestMaskValue(t *testing.T) {
|
|
cases := []struct {
|
|
in string
|
|
want string
|
|
}{
|
|
{"", "****"},
|
|
{"abc", "****"},
|
|
{"12345678", "****"},
|
|
{"abcdefghij", "abcd****ghij"}, // 10 runes => 前4+****+后4
|
|
}
|
|
for _, c := range cases {
|
|
got := MaskValue(c.in)
|
|
if got != c.want {
|
|
t.Errorf("MaskValue(%q) = %q, want %q", c.in, got, c.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestMaskCookie(t *testing.T) {
|
|
// 空
|
|
if got := MaskCookie(""); got != "" {
|
|
t.Errorf("MaskCookie(empty) = %q, want empty", got)
|
|
}
|
|
// 单条
|
|
got := MaskCookie("acf_ccn=abcdefghij")
|
|
if !strings.Contains(got, "acf_ccn=abcd****ghij") {
|
|
t.Errorf("MaskCookie single = %q, want masked acf_ccn", got)
|
|
}
|
|
// 多条只显示前 3 条并标注总数
|
|
got = MaskCookie("a=abcdefghij; b=abcdefghij; c=abcdefghij; d=abcdefghij")
|
|
if !strings.Contains(got, "共4项") {
|
|
t.Errorf("MaskCookie multi = %q, want '共4项'", got)
|
|
}
|
|
if strings.Count(got, "; ") > 3 {
|
|
t.Errorf("MaskCookie multi shows too many pairs: %q", got)
|
|
}
|
|
// 缺失 = 号的段被跳过
|
|
got = MaskCookie("broken; valid=12345678")
|
|
if strings.Contains(got, "broken") {
|
|
t.Errorf("MaskCookie should skip pair without '=': %q", got)
|
|
}
|
|
}
|
|
|
|
func TestMergeCookie(t *testing.T) {
|
|
// 覆盖已有
|
|
got := MergeCookie("a=1; b=2; c=3", "b", "20")
|
|
if got != "a=1; b=20; c=3" {
|
|
t.Errorf("MergeCookie overwrite = %q, want 'a=1; b=20; c=3'", got)
|
|
}
|
|
// 追加新字段
|
|
got = MergeCookie("a=1", "b", "2")
|
|
if got != "a=1; b=2" {
|
|
t.Errorf("MergeCookie append = %q, want 'a=1; b=2'", got)
|
|
}
|
|
// 空值不追加
|
|
got = MergeCookie("a=1", "b", "")
|
|
if got != "a=1" {
|
|
t.Errorf("MergeCookie empty value = %q, want 'a=1'", got)
|
|
}
|
|
// 空值覆盖已有:当前实现对空值仍保留 name= 形式(生产调用均传非空值)
|
|
got = MergeCookie("a=1; b=2", "a", "")
|
|
if got != "a=; b=2" {
|
|
t.Errorf("MergeCookie empty overwrite = %q, want 'a=; b=2'", got)
|
|
}
|
|
}
|
|
|
|
func TestSafeFilename(t *testing.T) {
|
|
got := SafeFilename("a/b:c*d?e\"f<g>h|i")
|
|
want := "a_b_c_d_e_f_g_h_i"
|
|
if got != want {
|
|
t.Errorf("SafeFilename = %q, want %q", got, want)
|
|
}
|
|
}
|
|
|
|
func TestCloneStringMap(t *testing.T) {
|
|
in := map[string]string{"a": "1", "b": "2"}
|
|
out := CloneStringMap(in)
|
|
out["a"] = "changed"
|
|
if in["a"] != "1" {
|
|
t.Errorf("CloneStringMap should be independent, original mutated")
|
|
}
|
|
if len(out) != 2 {
|
|
t.Errorf("CloneStringMap length = %d, want 2", len(out))
|
|
}
|
|
}
|
|
|
|
func TestTrimForLog(t *testing.T) {
|
|
if got := TrimForLog("hello", 10); got != "hello" {
|
|
t.Errorf("TrimForLog short = %q, want 'hello'", got)
|
|
}
|
|
got := TrimForLog("abcdefghij", 5)
|
|
if got != "abcde..." {
|
|
t.Errorf("TrimForLog long = %q, want 'abcde...'", got)
|
|
}
|
|
if got := TrimForLog(" spaced ", 10); got != "spaced" {
|
|
t.Errorf("TrimForLog trim = %q, want 'spaced'", got)
|
|
}
|
|
}
|
|
|
|
func TestEmptyDefault(t *testing.T) {
|
|
if got := EmptyDefault("", "fb"); got != "fb" {
|
|
t.Errorf("EmptyDefault empty = %q, want 'fb'", got)
|
|
}
|
|
if got := EmptyDefault("x", "fb"); got != "x" {
|
|
t.Errorf("EmptyDefault non-empty = %q, want 'x'", got)
|
|
}
|
|
if got := EmptyDefault(" ", "fb"); got != "fb" {
|
|
t.Errorf("EmptyDefault whitespace = %q, want 'fb'", got)
|
|
}
|
|
}
|