You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

144 lines
4.5 KiB

package memory
import (
"testing"
"time"
"yunyan/comm"
"yunyan/pb"
)
func TestTaskToMemoryItem_Basic(t *testing.T) {
task := &pb.DBTask{
Id: 42, Uid: "u1",
TaskName: "跟进A客户", TaskDesc: "电话联系",
TaskType: pb.TaskType_TaskType_Once,
TriggerTime: "2026-04-08T15:00:00+08:00",
Status: pb.TaskStatus_TaskStatus_Pending,
CreateTime: 1700000000,
}
it := taskToMemoryItem(task)
if it == nil {
t.Fatal("不该返回 nil")
}
if it.HappenDate != "2026-04-08" {
t.Errorf("日期期望 2026-04-08,得到 %s", it.HappenDate)
}
if it.HappenTime != "15:00" {
t.Errorf("时刻期望 15:00,得到 %s", it.HappenTime)
}
if it.ClientKey != "task:42" {
t.Errorf("幂等键期望 task:42,得到 %s", it.ClientKey)
}
if it.Category != comm.MemoryCatTodo {
t.Errorf("存量任务应一律迁成 todo,得到 %s", it.Category)
}
// 旧体系里「服务端仅记录不触发」,用户从没被提醒过。
// 迁过来默认开提醒 = 给所有人补发一堆历史提醒。
if it.RemindAhead != 0 {
t.Errorf("迁移来的任务不该默认开提醒,得到 %d", it.RemindAhead)
}
if !it.UserEdited {
t.Error("迁移来的是用户资产,应标 user_edited 避免被自动清理碰到")
}
}
// ⚠️ 凌晨任务:如果先转 UTC 再取日期,00:30+08:00 会退到前一天。
func TestTaskToMemoryItem_EarlyMorningKeepsLocalDate(t *testing.T) {
task := &pb.DBTask{
Id: 1, Uid: "u1", TaskName: "晨会",
TriggerTime: "2026-04-08T00:30:00+08:00",
CreateTime: 1700000000,
}
it := taskToMemoryItem(task)
if it == nil {
t.Fatal("不该返回 nil")
}
if it.HappenDate != "2026-04-08" {
t.Errorf("凌晨任务的日期不该退到前一天,期望 2026-04-08 得到 %s", it.HappenDate)
}
}
func TestTaskToMemoryItem_RepeatMapping(t *testing.T) {
cases := map[pb.TaskType]string{
pb.TaskType_TaskType_Once: comm.MemoryRepeatOnce,
pb.TaskType_TaskType_Daily: comm.MemoryRepeatDaily,
pb.TaskType_TaskType_Weekly: comm.MemoryRepeatWeekly,
pb.TaskType_TaskType_Monthly: comm.MemoryRepeatMonthly,
// cron 没有对应的 repeat_rule,按一次性迁:猜错的重复规则会让用户
// 每天被一个他没设过的闹钟吵醒
pb.TaskType_TaskType_Cron: comm.MemoryRepeatOnce,
}
for tt, want := range cases {
task := &pb.DBTask{
Id: 1, Uid: "u1", TaskName: "x", TaskType: tt,
TriggerTime: "2026-04-08T15:00:00+08:00",
}
it := taskToMemoryItem(task)
if it == nil || it.RepeatRule != want {
t.Errorf("TaskType %v 期望 %s,得到 %v", tt, want, it)
}
}
}
func TestTaskToMemoryItem_StatusMapping(t *testing.T) {
cases := map[pb.TaskStatus]pb.MemoryState{
pb.TaskStatus_TaskStatus_Pending: pb.MemoryState_MemoryState_Pending,
pb.TaskStatus_TaskStatus_Completed: pb.MemoryState_MemoryState_Done,
pb.TaskStatus_TaskStatus_Cancelled: pb.MemoryState_MemoryState_Dropped,
}
for st, want := range cases {
if got := taskStatusToState(st); got != want {
t.Errorf("状态 %v 期望 %v 得到 %v", st, want, got)
}
}
}
// 没有触发时间时退回创建日期——happen_date 永不为空是拾忆页能工作的前提
func TestTaskToMemoryItem_FallsBackToCreateTime(t *testing.T) {
created := time.Date(2026, 3, 1, 10, 0, 0, 0, time.Local)
task := &pb.DBTask{
Id: 1, Uid: "u1", TaskName: "无时间任务",
CreateTime: created.Unix(),
}
it := taskToMemoryItem(task)
if it == nil {
t.Fatal("不该返回 nil")
}
if it.HappenDate != comm.FormatMemoryDate(created) {
t.Errorf("应退回创建日期 %s,得到 %s", comm.FormatMemoryDate(created), it.HappenDate)
}
if it.DateCertain {
t.Error("没有具体时刻时 date_certain 应为 false")
}
}
// 该跳过的都要跳过,别往新表里塞垃圾
func TestTaskToMemoryItem_SkipsUnusable(t *testing.T) {
cases := []struct {
name string
task *pb.DBTask
}{
{"nil", nil},
{"没有 uid", &pb.DBTask{Id: 1, TaskName: "x", CreateTime: 1}},
{"标题与描述都空", &pb.DBTask{Id: 1, Uid: "u1", CreateTime: 1}},
{"既无触发时间也无创建时间", &pb.DBTask{Id: 1, Uid: "u1", TaskName: "x"}},
}
for _, c := range cases {
if got := taskToMemoryItem(c.task); got != nil {
t.Errorf("%s: 应跳过,却返回了 %+v", c.name, got)
}
}
}
// 描述为空时用标题;标题为空时用描述
func TestTaskToMemoryItem_TitleFallback(t *testing.T) {
task := &pb.DBTask{
Id: 1, Uid: "u1", TaskDesc: "只有描述",
TriggerTime: "2026-04-08T15:00:00+08:00",
}
it := taskToMemoryItem(task)
if it == nil || it.Title != "只有描述" {
t.Errorf("标题空时应退回描述,得到 %v", it)
}
}