Files
Zhichang Yu 0784bef5b0 Port dataset-level structure merge for timeline/graph/mindmap (#18201)
Ports Python dataset-level structure aggregation (timeline, graph, mindmap) to Go. Mindmap emits entity/relation rows and merges like graph. Adds dataset_merge guard, engine gate, resolveDatasetStructureKind, kind-required structure graph GET/DELETE API, per-index task-id fields.
2026-08-13 18:37:47 +08:00

97 lines
2.9 KiB
Go

package mindmap
import (
"strings"
"testing"
"ragflow/internal/utility"
)
func TestRenderPrompt(t *testing.T) {
got := renderPrompt("THE TEXT")
if !strings.Contains(got, "-TEXT-\nTHE TEXT") {
t.Fatalf("input_text not substituted: %q", got)
}
if strings.Contains(got, "{input_text}") {
t.Fatalf("placeholder survived: %q", got)
}
// The verbatim prompt body must be present.
if !strings.Contains(got, "Generate a title for user's 'TEXT'。") {
t.Fatalf("prompt body drifted")
}
}
func TestPackSections_Budget(t *testing.T) {
// budget = max(4096*0.8, 4096-512) = 3584; with the len-based fake
// tokenizer each section of 2000 tokens packs one per batch.
tok := fakeTok{}
sections := []string{strings.Repeat("a", 8000), strings.Repeat("b", 8000), "short"}
got := packSections(sections, tok)
if len(got) != 2 {
t.Fatalf("batches = %d, want 2 (2000+2000 > 3584 splits)", len(got))
}
// An oversized section is never split: it forms its own batch.
big := packSections([]string{strings.Repeat("x", 20000)}, tok)
if len(big) != 1 {
t.Fatalf("oversized section must stay whole: %d batches", len(big))
}
}
type fakeTok struct{}
func (fakeTok) NumTokens(s string) int { return len(s) / 4 }
func TestTreeToProducts_ParentLinks(t *testing.T) {
root := &utility.Node{ID: "root", Children: []*utility.Node{
{ID: "A", Children: []*utility.Node{{ID: "A1"}, {ID: "A2"}}},
{ID: "B"},
}}
products := treeToProducts("t1", "d1", root)
// 5 entities (root, A, A1, A2, B) + 4 relations (root→A, A→A1, A→A2, root→B).
if len(products) != 9 {
t.Fatalf("products = %d, want 9 (5 entities + 4 relations)", len(products))
}
entCount, relCount := 0, 0
fromTo := map[string]bool{}
for _, p := range products {
kind, _ := p.Meta["kind"].(string)
switch kind {
case "entity":
entCount++
if p.Meta["entity_type"] != "mindmap" {
t.Errorf("entity %v type = %v, want mindmap", p.Meta["name"], p.Meta["entity_type"])
}
if p.Meta["compile_kwd"] != "mindmap" {
t.Errorf("entity %v compile_kwd = %v, want mindmap", p.Meta["name"], p.Meta["compile_kwd"])
}
case "relation":
relCount++
from, _ := p.Meta["from"].(string)
to, _ := p.Meta["to"].(string)
fromTo[from+"->"+to] = true
if p.Meta["relation_type"] != "related" {
t.Errorf("relation %v->%v type = %v, want related", from, to, p.Meta["relation_type"])
}
default:
t.Errorf("unexpected kind %q", kind)
}
}
if entCount != 5 || relCount != 4 {
t.Errorf("entities=%d relations=%d, want 5/4", entCount, relCount)
}
for _, edge := range []string{"root->A", "A->A1", "A->A2", "root->B"} {
if !fromTo[edge] {
t.Errorf("missing relation %s", edge)
}
}
}
func TestTreeToProducts_EmptyAndNil(t *testing.T) {
if got := treeToProducts("t1", "d1", nil); len(got) != 0 {
t.Errorf("nil root produced %d products", len(got))
}
if got := treeToProducts("t1", "d1", &utility.Node{ID: ""}); len(got) != 0 {
t.Errorf("empty root id produced %d products", len(got))
}
}