package replyexport import ( "testing" "time" ) func TestEvaluatePolicy_Matrix(t *testing.T) { tests := []struct { name string opts PolicyOptions wantKind ContentKind wantPolicy ExportPolicy wantReason ReasonCode hasFormats bool expectedFormat string }{ { name: "1. 助手已完成完整长文 -> full", opts: PolicyOptions{ Role: "assistant", Status: "completed", Content: "## 风险评估报告\n\n根据现有临床数据,该方案具有以下风险:\n1. 电气安全性需重新打标\n2. 传感器存在温漂", }, wantKind: KindDocumentText, wantPolicy: PolicyFull, hasFormats: true, }, { name: "2. 助手已完成 + 完整正文 + 辅助卡片 -> full (仅导出正文)", opts: PolicyOptions{ Role: "assistant", Status: "completed", Content: "## 变更建议书\n\n经系统审核,以下第 3 条款存在重大缺陷,建议采纳修改意见:\n- 原文:无过温保护\n- 修改后:增加热敏电阻切断机制", HasInteractiveCard: true, }, wantKind: KindDocumentText, wantPolicy: PolicyFull, hasFormats: true, }, { name: "3. 助手纯交互卡片 (短引导语) -> none, CARD_ONLY", opts: PolicyOptions{ Role: "assistant", Status: "completed", Content: "请确认以下操作卡片:", HasInteractiveCard: true, }, wantKind: KindActionCard, wantPolicy: PolicyNone, wantReason: ReasonCardOnly, hasFormats: false, }, { name: "4. 用户消息 -> none, NOT_ASSISTANT", opts: PolicyOptions{ Role: "user", Content: "请帮我分析一下项目进度", }, wantKind: KindConversationalText, wantPolicy: PolicyNone, wantReason: ReasonNotAssistant, }, { name: "5. 系统消息 -> none, NOT_ASSISTANT", opts: PolicyOptions{ Role: "system", Content: "系统已建立新会话", }, wantKind: KindConversationalText, wantPolicy: PolicyNone, wantReason: ReasonNotAssistant, }, { name: "6. 流式生成中 -> none, NOT_COMPLETED", opts: PolicyOptions{ Role: "assistant", Status: "streaming_status", Content: "正在研判您的意图...", }, wantKind: KindStatusUpdate, wantPolicy: PolicyNone, wantReason: ReasonNotCompleted, }, { name: "7. 失败/已取消消息 -> none, ERROR_OR_CANCELLED", opts: PolicyOptions{ Role: "assistant", Status: "failed", HasError: true, Content: "任务执行失败,网络超时", }, wantKind: KindErrorNotice, wantPolicy: PolicyNone, wantReason: ReasonErrorOrCancelled, }, { name: "8. 极短寒暄 -> copy_only", opts: PolicyOptions{ Role: "assistant", Status: "completed", Content: "好的,收到!", }, wantKind: KindConversationalText, wantPolicy: PolicyCopyOnly, hasFormats: true, }, { name: "9. 空正文 -> none, EMPTY_BODY", opts: PolicyOptions{ Role: "assistant", Status: "completed", Content: " \n\t ", }, wantKind: KindStatusUpdate, wantPolicy: PolicyNone, wantReason: ReasonEmptyBody, }, { name: "10. 受限敏感内容 -> none, CONTENT_RESTRICTED", opts: PolicyOptions{ Role: "assistant", Status: "completed", Content: "敏感内容正文", IsRestricted: true, }, wantKind: KindDocumentText, wantPolicy: PolicyNone, wantReason: ReasonContentRestricted, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { kind, cap := EvaluatePolicy(tt.opts) if kind != tt.wantKind { t.Errorf("kind = %v, want %v", kind, tt.wantKind) } if cap.Policy != tt.wantPolicy { t.Errorf("policy = %v, want %v", cap.Policy, tt.wantPolicy) } if tt.wantReason != "" && cap.ReasonCode != tt.wantReason { t.Errorf("reasonCode = %v, want %v", cap.ReasonCode, tt.wantReason) } if tt.hasFormats && len(cap.Formats) == 0 { t.Errorf("expected non-empty formats, got empty") } if !tt.hasFormats && len(cap.Formats) > 0 { t.Errorf("expected empty formats, got %v", cap.Formats) } if cap.ContentSha256 == "" { t.Errorf("expected non-empty ContentSha256") } }) } } func TestDeriveTitle(t *testing.T) { cases := []struct { input string wantTitle string }{ { input: "# 临床评估备忘录\n正文内容...", wantTitle: "临床评估备忘录", }, { input: "## 2.1 架构设计对比分析\n内容...", wantTitle: "2.1 架构设计对比分析", }, { input: "针对用户提出的第三阶段审核驳回要求,项目组给出如下补救措施:\n1. 增加测试...", wantTitle: "针对用户提出的第三阶段审核驳回要求,项目组给出如下补救措施:", }, } for _, tc := range cases { got := DeriveTitle(tc.input, testTime()) if got != tc.wantTitle { t.Errorf("DeriveTitle(%q) = %q, want %q", tc.input, got, tc.wantTitle) } } } func testTime() (t time.Time) { return time.Date(2026, 9, 10, 15, 30, 0, 0, time.Local) }