Files
Scoreboard/server/internal/domain/records_test.go
T
AskaEth 7f9701c465 fix: 审查修复波次(P0x4 + P1x30+)
- domain/rules: 计分与排名解耦、破纪录按组别、tieBreak 生效、调整分不丢、移除 aggregate 假能力
- realtime: 新建 internal/dto,快照三项契约对齐,/ws 只认会话身份
- httpapi: 流水幂等、standings 整表载荷、广播接线、强制改密、XFF 防伪造、records 写入、审计、赛事包内容、发布前备份、result.points、实例列表
- web: FormData 上传、YAML 解析、快照归一化、大屏解析层、bootstrap 降级、访客判定、主题切换
- console: 优雅关闭握手、中文化、免验证改管理员账号、选屏与日志轮转修复
- docs: 用户文档三份 + README
- 主代理: 破纪录加分接线(levels 未加载导致恒 0)
2026-09-09 21:06:40 +08:00

234 lines
7.2 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 domain
import "testing"
func bonusConfig(mode RecordBonusMode) RecordBonusConfig {
return RecordBonusConfig{
Enabled: true, Mode: mode,
Levels: []RecordLevel{
{Code: "meet", Name: "赛会纪录", Points: 2},
{Code: "city", Name: "市级纪录", Points: 5},
{Code: "province", Name: "省级纪录", Points: 8},
},
}
}
func TestRecordBonusDisabled(t *testing.T) {
cfg := bonusConfig(RecordBonusMax)
cfg.Enabled = false
got := RecordBonusPoints(cfg, []RecordBreak{{EntryID: 1, Level: "meet", State: RecordBreakApproved}})
if got != nil {
t.Fatalf("未启用时 = %+v,期望 nil", got)
}
}
func TestRecordBonusStateFilter(t *testing.T) {
cases := []struct {
name string
state RecordBreakState
want float64
}{
{"已通过计入", RecordBreakApproved, 2},
{"待审核不计入", RecordBreakPending, 0},
{"已驳回不计入", RecordBreakRejected, 0},
{"状态空值不计入", "", 0},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
got := RecordBonusPoints(bonusConfig(RecordBonusMax), []RecordBreak{{EntryID: 1, Level: "meet", State: tc.state}})
if tc.want == 0 {
if len(got) != 0 {
t.Fatalf("结果 = %+v,期望空", got)
}
return
}
if len(got) != 1 || !nearlyEqual(got[0].Points, tc.want) {
t.Fatalf("结果 = %+v,期望 %v 分", got, tc.want)
}
})
}
}
func TestRecordBonusUnknownLevel(t *testing.T) {
got := RecordBonusPoints(bonusConfig(RecordBonusMax), []RecordBreak{{EntryID: 1, Level: "galaxy", State: RecordBreakApproved}})
if len(got) != 0 {
t.Fatalf("未配置档位 = %+v,期望空(不能凭空加分)", got)
}
}
func TestRecordBonusModes(t *testing.T) {
breaks := []RecordBreak{
{ID: 1, EntryID: 1, Level: "meet", State: RecordBreakApproved},
{ID: 2, EntryID: 1, Level: "city", State: RecordBreakApproved},
{ID: 3, EntryID: 1, Level: "province", State: RecordBreakApproved},
}
cases := []struct {
name string
mode RecordBonusMode
want float64
}{
{"max 取最高档", RecordBonusMax, 8},
{"sum 累加", RecordBonusSum, 15},
{"模式空值按 max", "", 8},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
got := RecordBonusPoints(bonusConfig(tc.mode), breaks)
if len(got) != 1 || !nearlyEqual(got[0].Points, tc.want) {
t.Fatalf("结果 = %+v,期望 %v", got, tc.want)
}
})
}
}
func TestRecordBonusGroupsByEntry(t *testing.T) {
breaks := []RecordBreak{
{ID: 1, EntryID: 2, Level: "meet", State: RecordBreakApproved},
{ID: 2, EntryID: 1, Level: "city", State: RecordBreakApproved},
{ID: 3, EntryID: 1, Level: "meet", State: RecordBreakApproved},
}
got := RecordBonusPoints(bonusConfig(RecordBonusMax), breaks)
if len(got) != 2 {
t.Fatalf("条数 = %d,期望 2(按报名项分组)", len(got))
}
if got[0].EntryID != 1 || got[1].EntryID != 2 {
t.Fatalf("顺序 = %+v,期望按 EntryID 升序", got)
}
if !nearlyEqual(got[0].Points, 5) || !nearlyEqual(got[1].Points, 2) {
t.Fatalf("分值 = %v/%v,期望 5/2", got[0].Points, got[1].Points)
}
}
func TestRecordBonusDedupLevel(t *testing.T) {
breaks := []RecordBreak{
{ID: 1, EntryID: 1, Level: "meet", State: RecordBreakApproved},
{ID: 2, EntryID: 1, Level: "meet", State: RecordBreakApproved},
}
got := RecordBonusPoints(bonusConfig(RecordBonusSum), breaks)
if len(got) != 1 || !nearlyEqual(got[0].Points, 2) {
t.Fatalf("重复档位 = %+v,期望只计一次 2 分", got)
}
if len(got[0].Levels) != 1 {
t.Fatalf("档位列表 = %v,期望去重", got[0].Levels)
}
}
func TestRecordBonusNoBreaks(t *testing.T) {
if got := RecordBonusPoints(bonusConfig(RecordBonusMax), nil); got != nil {
t.Fatalf("无破纪录登记 = %+v,期望 nil", got)
}
}
func TestRecordBonusLedger(t *testing.T) {
entries, results := fixture(lineup(2))
base := EventScoreInput{
Event: individualEvent(1), Category: testCategory(),
Channels: []ScoreChannel{athleteResultChannel(1)},
Profiles: map[int64]ScoringProfile{1: individualTop6()},
Entries: entries, Results: results,
RecordBreaks: []RecordBreak{{
ID: 1, EventID: 1, EntryID: 1, AthleteID: 101, TeamID: 1001,
Level: "meet", State: RecordBreakApproved,
}},
}
t.Run("未启用不产生加分流水", func(t *testing.T) {
cfg := bonusConfig(RecordBonusMax)
cfg.Enabled = false
base.RecordBonus = &cfg
es := mustScore(t, base)
for _, e := range es.Ledger {
if e.SourceType == SourceRecordBonus {
t.Fatalf("不应有加分流水: %+v", e)
}
}
})
t.Run("启用后归属到人", func(t *testing.T) {
cfg := bonusConfig(RecordBonusMax)
base.RecordBonus = &cfg
es := mustScore(t, base)
var found bool
for _, e := range es.Ledger {
if e.SourceType != SourceRecordBonus {
continue
}
found = true
if e.TeamID != 1001 || e.AthleteID != 101 || !nearlyEqual(e.Points, 2) {
t.Fatalf("加分流水 = %+v,期望 1001/101 记 2 分", e)
}
}
if !found {
t.Fatal("未产生加分流水")
}
})
t.Run("联队按份额拆分加分", func(t *testing.T) {
ps := []participant{{
entryID: 1, athleteID: 101, teamID: 1001, value: 1,
shares: []TeamShare{{TeamID: 1001, Weight: 3}, {TeamID: 1002, Weight: 2}},
}}
e2, r2 := fixture(ps)
cfg := bonusConfig(RecordBonusMax)
es := mustScore(t, EventScoreInput{
Event: individualEvent(1), Category: testCategory(),
Channels: []ScoreChannel{athleteResultChannel(1)},
Profiles: map[int64]ScoringProfile{1: individualTop6()},
Entries: e2, Results: r2,
RecordBonus: &cfg,
RecordBreaks: []RecordBreak{{
ID: 1, EventID: 1, EntryID: 1, AthleteID: 101, TeamID: 1001,
Level: "meet", State: RecordBreakApproved,
}},
Options: ScoreOptions{UnionAttribution: UnionSplit},
})
var bonus float64
for _, e := range es.Ledger {
if e.SourceType == SourceRecordBonus && e.TeamID == 1002 {
bonus += e.Points
}
}
if !nearlyEqual(bonus, 0.8) {
t.Fatalf("单位1002 的加分 = %v,期望 2 × 0.4 = 0.8", bonus)
}
})
}
// TestRecordBonusLedgerFiltersByCategory 验证按「小项+组别」过滤:
// 上层逐组别调用 ScoreEvent,别的组别的破纪录登记不能在本组别重复记一次加分。
func TestRecordBonusLedgerFiltersByCategory(t *testing.T) {
entries, results := fixture(lineup(2))
entries[1].CategoryID = 2 // entry2 属于另一个组别
cfg := bonusConfig(RecordBonusMax)
es := mustScore(t, EventScoreInput{
Event: individualEvent(1), Category: testCategory(),
Channels: []ScoreChannel{athleteResultChannel(1)},
Profiles: map[int64]ScoringProfile{1: individualTop6()},
Entries: entries, Results: results,
RecordBonus: &cfg,
RecordBreaks: []RecordBreak{
{ID: 1, EventID: 1, EntryID: 1, AthleteID: 101, TeamID: 1001, Level: "meet", State: RecordBreakApproved},
{ID: 2, EventID: 1, EntryID: 2, AthleteID: 102, TeamID: 1002, Level: "meet", State: RecordBreakApproved},
},
})
var thisCategory, otherCategory int
for _, e := range es.Ledger {
if e.SourceType != SourceRecordBonus {
continue
}
switch e.EntryID {
case 1:
thisCategory++
case 2:
otherCategory++
}
}
if thisCategory != 1 {
t.Fatalf("本组别加分流水 = %d 条,期望 1", thisCategory)
}
if otherCategory != 0 {
t.Fatalf("别的组别的加分不应记入本组别,实际 %d 条", otherCategory)
}
}