feat: 用户徽章与等级体系,积分经济管理重构
- 新增徽章系统:badge 服务与 handler、管理端配置页、BadgeChip/LevelBadge 展示组件 - 新增等级模型:model/level 及前端 levels 元数据 - 管理端经济模块拆分为 points/badges/levels 独立页面,EconomySettings 迁入设置 - 积分、签到、评论等服务适配等级与徽章逻辑
This commit is contained in:
106
backend/model/level_test.go
Normal file
106
backend/model/level_test.go
Normal file
@@ -0,0 +1,106 @@
|
||||
package model
|
||||
|
||||
import "testing"
|
||||
|
||||
// withLevelDefs 临时切换等级快照并在测试结束后恢复现场(快照为进程级全局态)
|
||||
func withLevelDefs(t *testing.T, defs []LevelDef) {
|
||||
t.Helper()
|
||||
prev := LevelDefs()
|
||||
t.Cleanup(func() { ApplyLevelDefs(prev) })
|
||||
ApplyLevelDefs(defs)
|
||||
}
|
||||
|
||||
func TestLevelOfDefault(t *testing.T) {
|
||||
withLevelDefs(t, DefaultLevelDefs())
|
||||
cases := []struct {
|
||||
total int
|
||||
want int
|
||||
}{
|
||||
{0, 1},
|
||||
{49, 1},
|
||||
{50, 2},
|
||||
{51, 2},
|
||||
{199, 2},
|
||||
{200, 3},
|
||||
{500, 4},
|
||||
{1200, 5},
|
||||
{3000, 6},
|
||||
{7999, 6},
|
||||
{8000, 7},
|
||||
{1 << 30, 7},
|
||||
{-5, 1},
|
||||
}
|
||||
for _, c := range cases {
|
||||
if got := LevelOf(c.total); got != c.want {
|
||||
t.Errorf("LevelOf(%d) = %d, want %d", c.total, got, c.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLevelOfCustomConfig(t *testing.T) {
|
||||
withLevelDefs(t, []LevelDef{
|
||||
{Threshold: 0, Color: "neutral"},
|
||||
{Threshold: 10, Color: "gold"},
|
||||
{Threshold: 100, Color: "info"},
|
||||
})
|
||||
cases := []struct {
|
||||
total int
|
||||
want int
|
||||
}{
|
||||
{0, 1},
|
||||
{9, 1},
|
||||
{10, 2},
|
||||
{99, 2},
|
||||
{100, 3},
|
||||
{1 << 20, 3},
|
||||
}
|
||||
for _, c := range cases {
|
||||
if got := LevelOf(c.total); got != c.want {
|
||||
t.Errorf("LevelOf(%d) = %d, want %d", c.total, got, c.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyLevelDefsFallback(t *testing.T) {
|
||||
withLevelDefs(t, DefaultLevelDefs())
|
||||
// 非法配置(首级阈值非 0、数量不足、非递增)一律回落默认表
|
||||
invalid := [][]LevelDef{
|
||||
{{Threshold: 10, Color: "gold"}, {Threshold: 50, Color: "info"}},
|
||||
{{Threshold: 0, Color: "neutral"}},
|
||||
{{Threshold: 0, Color: "neutral"}, {Threshold: 50, Color: "info"}, {Threshold: 50, Color: "ok"}},
|
||||
{{Threshold: 0, Color: "neutral"}, {Threshold: -1, Color: "info"}},
|
||||
}
|
||||
for _, defs := range invalid {
|
||||
ApplyLevelDefs(defs)
|
||||
got := LevelDefs()
|
||||
if len(got) != len(DefaultLevelDefs()) {
|
||||
t.Fatalf("ApplyLevelDefs(invalid) 未回落默认表: got %d levels", len(got))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidLevelDefs(t *testing.T) {
|
||||
valid := []LevelDef{{Threshold: 0, Color: "neutral"}, {Threshold: 1, Color: "gold"}}
|
||||
if !ValidLevelDefs(valid) {
|
||||
t.Errorf("ValidLevelDefs(合法两极) = false")
|
||||
}
|
||||
tooMany := make([]LevelDef, MaxLevelCount+1)
|
||||
for i := range tooMany {
|
||||
tooMany[i] = LevelDef{Threshold: i, Color: "gold"}
|
||||
}
|
||||
if ValidLevelDefs(tooMany) {
|
||||
t.Errorf("ValidLevelDefs(超上限) = true")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLevelDefsBoundaryCount(t *testing.T) {
|
||||
withLevelDefs(t, DefaultLevelDefs())
|
||||
defs := make([]LevelDef, MaxLevelCount)
|
||||
for i := range defs {
|
||||
defs[i] = LevelDef{Threshold: i * 10, Color: "gold"}
|
||||
}
|
||||
ApplyLevelDefs(defs)
|
||||
if got := LevelOf(1 << 30); got != MaxLevelCount {
|
||||
t.Errorf("LevelOf(极大值) = %d, want %d", got, MaxLevelCount)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user