Files
qitongxue-api/internal/logic/note_test.go
2026-09-29 10:57:01 +08:00

108 lines
4.0 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 logic
import (
"testing"
"time"
"github.com/gogf/gf/v2/os/gctx"
"github.com/gogf/gf/v2/os/gtime"
"tool-api/internal/consts"
"tool-api/internal/model/entity"
)
// TestEvaluateNoteQuota 覆盖额度边界:
// - 免费未满(49) → 允许新建
// - 免费刚好满(50) → 禁止新建(对应「第 51 条返回 4003」的前置条件)
// - 会员过期回落且活跃数超限(51) → 仅禁止新建,不删数据
// - 会员(不限量) → 允许新建
//
// 该函数是 SaveNote/RestoreNote 真实调用的额度判定,非复述逻辑。
func TestEvaluateNoteQuota(t *testing.T) {
cases := []struct {
name string
activeCount int
isMember bool
wantLimit int
wantUnlimit bool
wantCreate bool
}{
{"免费_未满", 49, false, consts.NoteFreeLimit, false, true},
{"免费_刚好满", 50, false, consts.NoteFreeLimit, false, false},
{"会员过期回落_超限仅禁新建", 51, false, consts.NoteFreeLimit, false, false},
{"会员_超限仍不限", 51, true, 0, true, true},
{"会员_零条", 0, true, 0, true, true},
}
for _, c := range cases {
limit, unlimited, canCreate := evaluateNoteQuota(c.activeCount, c.isMember)
if limit != c.wantLimit || unlimited != c.wantUnlimit || canCreate != c.wantCreate {
t.Fatalf("%s: got(limit=%d, unlimited=%v, canCreate=%v) want(%d, %v, %v)",
c.name, limit, unlimited, canCreate, c.wantLimit, c.wantUnlimit, c.wantCreate)
}
}
}
// TestEffectiveLevelKeyMemberFallback 证明会员判定确实走 EffectiveLevelKey,
// 且会员到期后回落默认等级(保证「会员过期即回落免费额度」)。
func TestEffectiveLevelKeyMemberFallback(t *testing.T) {
if got := EffectiveLevelKey(nil); got != consts.DefaultLevelKey {
t.Fatalf("nil user: got %s want %s", got, consts.DefaultLevelKey)
}
// 永久会员(level_expire_at 为空)
if got := EffectiveLevelKey(&entity.Users{LevelKey: "v2"}); got != "v2" {
t.Fatalf("永久会员: got %s want v2", got)
}
// 未过期会员
if got := EffectiveLevelKey(&entity.Users{LevelKey: "v2", LevelExpireAt: gtime.Now().Add(time.Hour)}); got != "v2" {
t.Fatalf("未过期会员: got %s want v2", got)
}
// 已过期会员 → 回落默认(免费)等级
if got := EffectiveLevelKey(&entity.Users{LevelKey: "v2", LevelExpireAt: gtime.Now().Add(-time.Hour)}); got != consts.DefaultLevelKey {
t.Fatalf("已过期会员: got %s want %s", got, consts.DefaultLevelKey)
}
}
// TestSendNoteRemindWithEmptyTemplateDegrades 覆盖「模板未配置时接口正常、无 panic」:
// 直接调用真实发送函数并传入空模板 ID,断言不 panic 且返回 nil(降级)。
func TestSendNoteRemindWithEmptyTemplateDegrades(t *testing.T) {
defer func() {
if r := recover(); r != nil {
t.Fatalf("模板未配置时不应 panic,但发生了 panic: %v", r)
}
}()
ctx := gctx.New()
err := sendNoteRemindWithTemplate(ctx, NoteRemindSendReq{
NoteId: 1,
Openid: "o_test_openid",
Title: "会议要点",
Content: "待办清单:a、b、c",
Time: "2026-09-20 09:00:00",
}, "")
if err != nil {
t.Fatalf("模板未配置时应降级返回 nil,但返回 err=%v", err)
}
}
// TestShouldClaimRemind 证明「同一提醒只发一次」的条件更新语义:
// 只有当抢占了 remind_status=1→2 的那一次(rowsAffected==1)才继续发送。
func TestShouldClaimRemind(t *testing.T) {
if !shouldClaimRemind(1) {
t.Fatalf("rowsAffected=1 时应继续发送")
}
if shouldClaimRemind(0) {
t.Fatalf("rowsAffected=0 时应跳过(已被其它实例/轮次抢占)")
}
}
// TestJoinAndSplitTags 覆盖标签规整(去空白/去空项/去重)与回拆分。
func TestJoinAndSplitTags(t *testing.T) {
csv := joinNoteTags([]string{" 工作 ", "", "待办", "工作"})
if csv != "工作,待办" {
t.Fatalf("joinNoteTags got %q want %q", csv, "工作,待办")
}
tags := splitNoteTags(csv)
if len(tags) != 2 || tags[0] != "工作" || tags[1] != "待办" {
t.Fatalf("splitNoteTags got %v want [工作 待办]", tags)
}
}