Files
tamabox/route/vote/vote_dedupe_test.go
T
tamakyi 5fdc3df22d 修复: 评论组件泄露私密 token、cwebp 无超时、选项长度与去重
Waline(安全)
- item.html 的 path 从 window.location.href 改为剔除 ?t= 后的 URL。
  私密题 /_/<domain>/<id>?t=<token> 的钥匙原本会整条发往 Waline 服务端
  并落进其访问日志。只删 t、保留其他参数,公开题的评论线程键不变。

cwebp(可靠性)
- ConvertGifToAnimatedWebP 改用 exec.CommandContext + 30s 上限。
  原来裸 exec.Command 无超时,畸形/超大 GIF 会把子进程和上传 goroutine 一起挂住。
  超时杀进程并记 Warn,调用方按既有逻辑回退为原 GIF,不影响上传成功。

投票选项长度(正确性)
- vote_options.content 由 varchar(200) 放宽到 300,与配置默认值一致。
  此前 201–300 字的选项通过校验后在写库阶段失败。
- 新增 db.MaxVoteOptionLen;voteOptionMaxLen() 取配置与存储上限的较小值,
  校验与前端 maxlength 同源,避免配置调大后再次越界。

多选 checkbox 去重(正确性)
- 抽出 appendUniqueValue,预置值与「其他」文本共用同一 seen 集合。
  此前重复提交同名字段会让同一选项在统计里被计多次。

测试
- vote_dedupe_test.go:去重与顺序。
- vote_option_len_test.go:配置小于/等于/大于存储上限三种情形。
- TestVoteOptionMaxLengthRoundTrip:300 个多字节字符存回不截断。
- TestVoteOptionColumnWidens:把列改回 200 后 AutoMigrate 能扩回 300(老库升级路径)。

验证:WSL2 Debian + PostgreSQL 全量 go test ./... 27 个包全绿;
隔离实例渲染单题页确认新的 path 逻辑。
2026-11-05 17:04:47 +08:00

49 lines
1.4 KiB
Go

package vote
import (
"testing"
)
// TestAppendUniqueValue 钉住多选字段的去重语义:
// 客户端重复提交同一选项时,落库与统计都只能算一次。
func TestAppendUniqueValue(t *testing.T) {
t.Run("重复值只保留第一次", func(t *testing.T) {
seen := map[string]bool{}
var got []string
for _, v := range []string{"A", "A", "B", "A", "B", "C"} {
got = appendUniqueValue(got, seen, v)
}
want := []string{"A", "B", "C"}
if len(got) != len(want) {
t.Fatalf("got %v, want %v", got, want)
}
for i := range want {
if got[i] != want[i] {
t.Fatalf("got %v, want %v(顺序应按首次出现)", got, want)
}
}
})
t.Run("空切片与单值", func(t *testing.T) {
seen := map[string]bool{}
var got []string
got = appendUniqueValue(got, seen, "只有一项")
if len(got) != 1 || got[0] != "只有一项" {
t.Fatalf("got %v", got)
}
})
t.Run("seen 复用时跨批次仍然去重", func(t *testing.T) {
// checkbox 的「其他」文本与预置值走同一条追加路径,
// seen 必须在整个字段解析期间共享,而不是每轮新建。
seen := map[string]bool{}
var got []string
got = appendUniqueValue(got, seen, "预置")
got = appendUniqueValue(got, seen, "其他文本")
got = appendUniqueValue(got, seen, "预置")
if len(got) != 2 {
t.Fatalf("got %v, want 2 项", got)
}
})
}