79 lines
2.9 KiB
Go
79 lines
2.9 KiB
Go
package logic
|
||
|
||
import (
|
||
"testing"
|
||
"time"
|
||
|
||
"github.com/gogf/gf/v2/os/gtime"
|
||
|
||
"tool-api/internal/consts"
|
||
"tool-api/internal/model/entity"
|
||
)
|
||
|
||
// TestCountActiveMembers_PermanentCounted 看板「有效会员」必须计入永久会员
|
||
// (level_expire_at = NULL,管理员手动分配)。这是本次修复(#24)的核心回归点:
|
||
// 旧 SQL 用 `level_expire_at IS NOT NULL` 把永久会员全部漏掉了。
|
||
func TestCountActiveMembers_PermanentCounted(t *testing.T) {
|
||
future := gtime.New(time.Now().Add(24 * time.Hour))
|
||
past := gtime.New(time.Now().Add(-24 * time.Hour))
|
||
users := []*entity.Users{
|
||
{LevelKey: "v2", LevelExpireAt: nil}, // ① 永久(NULL)→ 应计入
|
||
{LevelKey: "v2", LevelExpireAt: future}, // ② 未过期 → 应计入
|
||
{LevelKey: "v2", LevelExpireAt: past}, // ③ 已过期 → 回落默认等级,不计入
|
||
}
|
||
if got := countActiveMembers(users); got != 2 {
|
||
t.Fatalf("countActiveMembers=%d want 2", got)
|
||
}
|
||
}
|
||
|
||
// TestLevelDistribution_EffectiveKey 等级分布按「生效等级」分组:
|
||
// 已过期用户必须落入默认等级桶,而不是其原始 level_key。
|
||
func TestLevelDistribution_EffectiveKey(t *testing.T) {
|
||
future := gtime.New(time.Now().Add(24 * time.Hour))
|
||
past := gtime.New(time.Now().Add(-24 * time.Hour))
|
||
users := []*entity.Users{
|
||
{LevelKey: "v2", LevelExpireAt: nil},
|
||
{LevelKey: "v2", LevelExpireAt: future},
|
||
{LevelKey: "v2", LevelExpireAt: past},
|
||
}
|
||
dist := levelDistribution(users)
|
||
if dist["v2"] != 2 {
|
||
t.Fatalf("v2 桶=%d want 2 (%v)", dist["v2"], dist)
|
||
}
|
||
if dist[consts.DefaultLevelKey] != 1 {
|
||
t.Fatalf("默认等级桶=%d want 1 (%v)", dist[consts.DefaultLevelKey], dist)
|
||
}
|
||
}
|
||
|
||
// TestCountActiveMembers_DefaultExcluded 默认等级(含空 key)不算有效会员。
|
||
func TestCountActiveMembers_DefaultExcluded(t *testing.T) {
|
||
users := []*entity.Users{
|
||
{LevelKey: consts.DefaultLevelKey, LevelExpireAt: nil},
|
||
{LevelKey: "", LevelExpireAt: nil},
|
||
}
|
||
if got := countActiveMembers(users); got != 0 {
|
||
t.Fatalf("countActiveMembers=%d want 0", got)
|
||
}
|
||
if n := countActiveMembers(nil); n != 0 {
|
||
t.Fatalf("nil 应返回 0,got %d", n)
|
||
}
|
||
}
|
||
|
||
// TestValidateLevelKeyUnchanged 编辑等级时 level_key 是跨端契约字段,不允许变更(T01.6)。
|
||
// 服务端闸门:前端把输入框 disabled 只是体验层,这里固化「变更即报错」的行为,
|
||
// 取消失败回归(例如未来有人误把 level_key 写进编辑 data map)。
|
||
func TestValidateLevelKeyUnchanged(t *testing.T) {
|
||
// 未变更 → 放行
|
||
if err := validateLevelKeyUnchanged("v2", "v2"); err != nil {
|
||
t.Fatalf("相同 level_key 应放行,got err=%v", err)
|
||
}
|
||
// 变更 → 报错
|
||
if err := validateLevelKeyUnchanged("v2", "v3"); err == nil {
|
||
t.Fatalf("变更 level_key 应报错,got nil")
|
||
}
|
||
// 清空(旧展开式回填的典型故障)→ 报错
|
||
if err := validateLevelKeyUnchanged("v2", ""); err == nil {
|
||
t.Fatalf("清空 level_key 应报错,got nil")
|
||
}
|
||
}
|