package server import ( "errors" "strings" "testing" "chat-agent-system/internal/coordinator" "chat-agent-system/internal/docgov" "chat-agent-system/internal/projectinstance" "chat-agent-system/internal/workflowscope" ) func TestSelectReadableWorkflowDocumentMatchesInitialRequirementsAlias(t *testing.T) { docs := []docgov.WorkflowDocumentSummary{ {DocID: "doc_proj143_intake", TaskKey: "intake", Title: "用户初始需求收集表"}, {DocID: "doc_proj143_research", TaskKey: "research", Title: "技术与市场调研报告"}, } doc, err := selectReadableWorkflowDocument(docs, "用户初始需求表", "", nil) if err != nil { t.Fatalf("select: %v", err) } if doc.DocID != "doc_proj143_intake" { t.Fatalf("doc=%s", doc.DocID) } } func TestSelectReadableWorkflowDocumentDoesNotGuessWhenTargetMissing(t *testing.T) { docs := []docgov.WorkflowDocumentSummary{ {DocID: "doc_a", TaskKey: "intake", Title: "用户初始需求收集表"}, {DocID: "doc_b", TaskKey: "research", Title: "调研报告"}, } if _, err := selectReadableWorkflowDocument(docs, "", "", nil); err == nil { t.Fatal("expected target-required error") } } func TestSelectReadableWorkflowDocumentScopesToActiveWorkflow(t *testing.T) { docs := []docgov.WorkflowDocumentSummary{ {DocID: "doc_proj1_research", TaskKey: "bd_research", Title: "调研报告"}, {DocID: "doc_proj1_proposal", TaskKey: "rd_proposal", Title: "项目建议书"}, } scope := map[string]bool{"bd_research": true, "research": true} doc, err := selectReadableWorkflowDocument(docs, "调研报告", "main", scope) if err != nil { t.Fatalf("in-scope select: %v", err) } if doc.TaskKey != "bd_research" { t.Fatalf("want bd_research, got %s", doc.TaskKey) } _, err = selectReadableWorkflowDocument(docs, "项目建议书", "main", scope) if err == nil { t.Fatal("expected wrong-workflow error") } var wrong *coordinator.ErrWrongWorkflow if !errors.As(err, &wrong) { t.Fatalf("want ErrWrongWorkflow, got %T %v", err, err) } if !strings.Contains(wrong.Message, "切换") { t.Fatalf("guidance should mention 切换, got %q", wrong.Message) } } func TestSelectReadableWorkflowDocumentNoScopeKeepsLegacy(t *testing.T) { docs := []docgov.WorkflowDocumentSummary{ {DocID: "doc_proj1_proposal", TaskKey: "rd_proposal", Title: "项目建议书"}, } doc, err := selectReadableWorkflowDocument(docs, "项目建议书", "", nil) if err != nil { t.Fatalf("legacy passthrough: %v", err) } if doc.TaskKey != "rd_proposal" { t.Fatalf("want rd_proposal, got %s", doc.TaskKey) } } func TestSelectReadableWeightedAllowsExactCrossRead(t *testing.T) { workflowscope.SetModeForTest(workflowscope.ModeWeighted) t.Cleanup(workflowscope.ResetModeForTest) docs := []docgov.WorkflowDocumentSummary{ {DocID: "doc_proj1_research", TaskKey: "bd_research", Title: "调研报告"}, {DocID: "doc_proj1_proposal", TaskKey: "rd_proposal", Title: "项目建议书"}, } scope := map[string]bool{"bd_research": true} doc, err := selectReadableWorkflowDocument(docs, "项目建议书", "main", scope) if err != nil { t.Fatalf("weighted cross read: %v", err) } if doc.TaskKey != "rd_proposal" { t.Fatalf("want rd_proposal, got %s", doc.TaskKey) } inScope, err := selectReadableWorkflowDocument(docs, "调研报告", "main", scope) if err != nil || inScope.TaskKey != "bd_research" { t.Fatalf("in-scope still wins: %v %v", inScope, err) } } func TestCrossWorkflowTaskVisible(t *testing.T) { open := &projectinstance.StageAccess{ Restricted: true, ViewableTaskKeys: map[string]bool{"bd_research": true}, } scope := map[string]bool{"bd_research": true, "bd_hidden": true} if !crossWorkflowTaskVisible(open, scope, "rd_proposal") { t.Fatal("foreign key should be readable when the caller can view the active instance") } if crossWorkflowTaskVisible(open, scope, "bd_hidden") { t.Fatal("in-scope but not viewable must be denied") } closed := &projectinstance.StageAccess{Restricted: true, ViewableTaskKeys: map[string]bool{}} if crossWorkflowTaskVisible(closed, scope, "rd_proposal") { t.Fatal("closed instance must deny cross read") } if !crossWorkflowTaskVisible(nil, scope, "rd_proposal") { t.Fatal("unrestricted access must allow") } }