package copymission import ( "testing" libkg "haixun-backend/internal/library/knowledge" missionentity "haixun-backend/internal/model/copy_mission/domain/entity" ) func TestMatrixKnowledgeItems_PrefersGraphSelection(t *testing.T) { nodes := []libkg.Node{ {Label: "痛點A", NodeKind: "pain", SelectedForScan: true, PlacementValue: "細節A"}, {Label: "周邊B", NodeKind: "context", SelectedForScan: false}, } items := MatrixKnowledgeItems(nil, nil, nodes, nil) if len(items) != 1 { t.Fatalf("items = %v, want 1 selected graph node", items) } if items[0] != "痛點A|細節A" { t.Fatalf("items[0] = %q", items[0]) } } func TestMatrixKnowledgeItems_UsesMissionSelectionOnly(t *testing.T) { items := MatrixKnowledgeItems( []string{"受眾問題:怎麼選"}, []string{"內容支柱:懶人包"}, nil, nil, ) if len(items) != 1 || items[0] != "受眾問題:怎麼選" { t.Fatalf("items = %v", items) } } func TestMatrixKnowledgeItems_MergesGraphAndMission(t *testing.T) { nodes := []libkg.Node{ { Label: "備孕營養", PlacementValue: "葉酸與鋅很重要", SelectedForScan: true, }, { Label: "未勾選", PlacementValue: "不應出現", SelectedForScan: false, DerivedTags: libkg.DerivedTags{ Relevance: []string{"備孕飲食"}, }, }, } items := MatrixKnowledgeItems( []string{"手動補充:睡前習慣"}, nil, nodes, []string{"備孕飲食"}, ) if len(items) != 2 { t.Fatalf("items = %v", items) } } func TestMatrixKnowledgeItems_IgnoresUnselectedTagMatches(t *testing.T) { nodes := []libkg.Node{ { Label: "備孕營養", PlacementValue: "葉酸與鋅很重要", SelectedForScan: false, DerivedTags: libkg.DerivedTags{ Relevance: []string{"備孕飲食"}, }, }, } items := MatrixKnowledgeItems(nil, nil, nodes, []string{"備孕飲食"}) if len(items) != 0 { t.Fatalf("items = %v, want none without explicit selection", items) } } func TestBuildResearchMapFromGraph_RespectsManualDeselection(t *testing.T) { prev := missionentity.ResearchMap{ KnowledgeItems: []string{"圖譜痛點:細節"}, SelectedKnowledgeItems: []string{}, } out := BuildResearchMapFromGraph(prev, []libkg.Node{ {Label: "圖譜痛點", NodeKind: "pain", SelectedForScan: true, PlacementValue: "細節"}, }, nil) if len(out.SelectedKnowledgeItems) != 0 { t.Fatalf("selected = %v, want manual deselection honored", out.SelectedKnowledgeItems) } } func TestBuildResearchMapFromGraph_PreservesManualKnowledge(t *testing.T) { prev := missionentity.ResearchMap{ KnowledgeItems: []string{"手動知識:睡前"}, SelectedKnowledgeItems: []string{"手動知識:睡前"}, } out := BuildResearchMapFromGraph(prev, []libkg.Node{ {Label: "圖譜痛點", NodeKind: "pain", SelectedForScan: true, PlacementValue: "細節"}, }, nil) if len(out.KnowledgeItems) != 2 { t.Fatalf("knowledge_items = %v", out.KnowledgeItems) } if len(out.SelectedKnowledgeItems) != 2 { t.Fatalf("selected = %v", out.SelectedKnowledgeItems) } } func TestApplyDefaultNodeSelectionPreserving(t *testing.T) { nodes := []libkg.Node{ {ID: "keep", Label: "已勾", NodeKind: "context", SelectedForScan: false}, {ID: "new", Label: "新痛點", NodeKind: "pain", SelectedForScan: false}, } ApplyDefaultNodeSelectionPreserving(nodes, map[string]bool{"keep": true}) if !nodes[0].SelectedForScan { t.Fatal("expected preserved selection on existing node") } if !nodes[1].SelectedForScan { t.Fatal("expected default selection on new pain node") } }