Details (original message): Implement the backend: store/bus/runmgr core, mock and LLM runners (agent-native client), HITL three-branch routing, subagent runs, builtin and declarative HTTP tools, ingest parsers (md/txt/docx/pdf-text), knowledge fulltext, layered settings, profiles, plugin host, REST+SSE API, single-binary entrypoint; e2e and unit tests.
103 lines
3.1 KiB
Go
103 lines
3.1 KiB
Go
package ingest
|
||
|
||
import (
|
||
"archive/zip"
|
||
"bytes"
|
||
"encoding/xml"
|
||
"strings"
|
||
"testing"
|
||
|
||
core "agent-system-core"
|
||
)
|
||
|
||
func TestParseMarkdown(t *testing.T) {
|
||
doc := Parse("笔记.md", "text/markdown", []byte("# 标题一\n\n段落甲。\n\n- 要点 1\n- 要点 2\n\n## 标题二\n\n段落乙。\n"))
|
||
if doc.Meta.Parser != "builtin:md" || doc.Meta.Confidence != 1.0 {
|
||
t.Fatalf("meta: %+v", doc.Meta)
|
||
}
|
||
var heads, paras, lists int
|
||
for _, b := range doc.Blocks {
|
||
switch b.Type {
|
||
case core.BlockHeading:
|
||
heads++
|
||
case core.BlockPara:
|
||
paras++
|
||
case core.BlockList:
|
||
lists++
|
||
if len(b.Items) != 2 {
|
||
t.Errorf("list items: %v", b.Items)
|
||
}
|
||
}
|
||
}
|
||
if heads != 2 || paras != 2 || lists != 1 {
|
||
t.Errorf("blocks: heads=%d paras=%d lists=%d", heads, paras, lists)
|
||
}
|
||
if !strings.Contains(doc.PlainText(), "# 标题一") {
|
||
t.Error("PlainText missing heading")
|
||
}
|
||
}
|
||
|
||
func TestParseUnknownBinary(t *testing.T) {
|
||
doc := Parse("blob.bin", "application/octet-stream", []byte{0x00, 0x01, 0x02, 0xFF})
|
||
if len(doc.Blocks) != 0 {
|
||
t.Error("binary should not produce blocks")
|
||
}
|
||
if len(doc.Warnings) == 0 {
|
||
t.Error("binary should carry explicit warning (fail visible, not silent)")
|
||
}
|
||
}
|
||
|
||
// 构造最小 docx(zip + word/document.xml)验证 OOXML 解析。
|
||
func TestParseDocx(t *testing.T) {
|
||
var buf bytes.Buffer
|
||
zw := zip.NewWriter(&buf)
|
||
docXML := `<?xml version="1.0"?>
|
||
<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
|
||
<w:body>
|
||
<w:p><w:pPr><w:pStyle w:val="Heading1"/></w:pPr><w:r><w:t>总则</w:t></w:r></w:p>
|
||
<w:p><w:r><w:t>本文件说明医疗器械文档要求。</w:t></w:r></w:p>
|
||
<w:tbl>
|
||
<w:tr><w:tc><w:p><w:r><w:t>项</w:t></w:r></w:p></w:tc><w:tc><w:p><w:r><w:t>值</w:t></w:r></w:p></w:tc></w:tr>
|
||
<w:tr><w:tc><w:p><w:r><w:t>版本</w:t></w:r></w:p></w:tc><w:tc><w:p><w:r><w:t>1.0</w:t></w:r></w:p></w:tc></w:tr>
|
||
</w:tbl>
|
||
</w:body>
|
||
</w:document>`
|
||
if f, err := zw.Create("word/document.xml"); err == nil {
|
||
f.Write([]byte(docXML))
|
||
} else {
|
||
t.Fatal(err)
|
||
}
|
||
zw.Close()
|
||
|
||
doc := Parse("报告.docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document", buf.Bytes())
|
||
if doc.Meta.Parser != "builtin:docx" || len(doc.Warnings) != 0 {
|
||
t.Fatalf("meta: %+v warnings: %v", doc.Meta, doc.Warnings)
|
||
}
|
||
var heading, para, table bool
|
||
for _, b := range doc.Blocks {
|
||
switch b.Type {
|
||
case core.BlockHeading:
|
||
heading = b.Level == 1 && b.Text == "总则"
|
||
case core.BlockPara:
|
||
para = strings.Contains(b.Text, "医疗器械")
|
||
case core.BlockTable:
|
||
table = len(b.Rows) == 2 && b.Rows[1][1] == "1.0"
|
||
}
|
||
}
|
||
if !heading || !para || !table {
|
||
t.Errorf("docx blocks wrong: heading=%v para=%v table=%v blocks=%+v", heading, para, table, doc.Blocks)
|
||
}
|
||
if !strings.Contains(doc.PlainText(), "医疗器械") {
|
||
t.Error("PlainText missing docx text")
|
||
}
|
||
}
|
||
|
||
func TestParsePDFInvalid(t *testing.T) {
|
||
doc := Parse("scan.pdf", "application/pdf", []byte("not a pdf"))
|
||
if len(doc.Warnings) == 0 || doc.Meta.Confidence > 0.5 {
|
||
t.Errorf("invalid pdf should warn with low confidence: %+v", doc.Meta)
|
||
}
|
||
}
|
||
|
||
var _ = xml.Marshal
|