191 lines
9.9 KiB
Go
191 lines
9.9 KiB
Go
package runmgr
|
||
|
||
import (
|
||
core "agent-system-core"
|
||
"regexp"
|
||
"strings"
|
||
"testing"
|
||
"time"
|
||
)
|
||
|
||
func TestMaterialSourceInlineAnnotationsPreserveProvidedPrefix(t *testing.T) {
|
||
d := materialDocs()[0]
|
||
d.Meta.Origin = &core.DocumentOrigin{ArtifactID: "art1", ContentHash: strings.Repeat("a", 64), ParserRevision: "docx1"}
|
||
docs := []core.ParsedDocument{d}
|
||
provided := strings.TrimSpace(d.PlainText())
|
||
got := annotateProvidedMaterial(d, provided, materialSources(docs, 48000))
|
||
markers := regexp.MustCompile(`(?m)^sourceId=src_[a-f0-9]+ blockIndex=[0-9]+\n`)
|
||
if !markers.MatchString(got) {
|
||
t.Fatal("provided block has no source marker")
|
||
}
|
||
if markers.ReplaceAllString(got, "") != provided {
|
||
t.Fatal("source annotations changed the provided material bytes")
|
||
}
|
||
}
|
||
|
||
func TestMaterialSourceInlineAnnotationsNeverExposeHiddenBlocks(t *testing.T) {
|
||
d := core.ParsedDocument{Meta: core.DocMeta{Filename: "资料.txt", Origin: &core.DocumentOrigin{ArtifactID: "art2", ContentHash: strings.Repeat("b", 64), ParserRevision: "txt1"}}, Blocks: []core.DocBlock{
|
||
{Type: core.BlockPara, Text: "上线六月"},
|
||
{Type: core.BlockPara, Text: "隐藏的审批结论"},
|
||
}}
|
||
provided := "上线六月"
|
||
got := annotateProvidedMaterial(d, provided, materialSources([]core.ParsedDocument{d}, 4))
|
||
if strings.Count(got, "sourceId=") != 1 || strings.Contains(got, "隐藏的审批结论") {
|
||
t.Fatalf("unprovided block received a marker or text: %q", got)
|
||
}
|
||
if strings.Count(got, provided) != 1 {
|
||
t.Fatalf("provided prefix was duplicated: %q", got)
|
||
}
|
||
}
|
||
|
||
func TestMaterialSourceInlineAnnotationsPreserveTableAndUntrustedText(t *testing.T) {
|
||
trusted := core.ParsedDocument{Meta: core.DocMeta{Filename: "预算.xlsx", Origin: &core.DocumentOrigin{ArtifactID: "table", ContentHash: strings.Repeat("d", 64), ParserRevision: "xlsx1"}}, Blocks: []core.DocBlock{{Type: core.BlockTable, Rows: [][]string{{"项目", "预算"}, {"一期", "50万元"}}}}}
|
||
provided := strings.TrimSpace(trusted.PlainText())
|
||
got := annotateProvidedMaterial(trusted, provided, materialSources([]core.ParsedDocument{trusted}, 48000))
|
||
markers := regexp.MustCompile(`(?m)^sourceId=src_[a-f0-9]+ blockIndex=[0-9]+\n`)
|
||
if markers.ReplaceAllString(got, "") != provided || !strings.Contains(got, "一期\t50万元") {
|
||
t.Fatalf("table text changed while adding a source marker: %q", got)
|
||
}
|
||
untrusted := core.ParsedDocument{Meta: core.DocMeta{Filename: "无来源.txt"}, Blocks: []core.DocBlock{{Type: core.BlockPara, Text: "不得生成引用ID"}}}
|
||
plain := strings.TrimSpace(untrusted.PlainText())
|
||
if got := annotateProvidedMaterial(untrusted, plain, materialSources([]core.ParsedDocument{untrusted}, 48000)); got != plain {
|
||
t.Fatalf("document without Origin gained a source marker: %q", got)
|
||
}
|
||
}
|
||
|
||
func TestMaterialSourceInlineAnnotationsKeepOnlyPartialLastBlock(t *testing.T) {
|
||
d := core.ParsedDocument{Meta: core.DocMeta{Filename: "资料.txt", Origin: &core.DocumentOrigin{ArtifactID: "partial", ContentHash: strings.Repeat("e", 64), ParserRevision: "txt1"}}, Blocks: []core.DocBlock{{Type: core.BlockPara, Text: "上线六月"}, {Type: core.BlockPara, Text: "隐藏的审批结论"}}}
|
||
provided := string([]rune(strings.TrimSpace(d.PlainText()))[:7])
|
||
got := annotateProvidedMaterial(d, provided, materialSources([]core.ParsedDocument{d}, 7))
|
||
markers := regexp.MustCompile(`(?m)^sourceId=src_[a-f0-9]+ blockIndex=[0-9]+\n`)
|
||
if markers.ReplaceAllString(got, "") != provided || strings.Contains(got, "藏") {
|
||
t.Fatalf("partial block exposed unavailable text: %q", got)
|
||
}
|
||
}
|
||
|
||
func TestMaterialSourceInlineAnnotationsRejectDifferentParserRevision(t *testing.T) {
|
||
d := core.ParsedDocument{Meta: core.DocMeta{Filename: "同一工件.txt", Origin: &core.DocumentOrigin{ArtifactID: "same", ContentHash: strings.Repeat("f", 64), ParserRevision: "parser-old"}}, Blocks: []core.DocBlock{{Type: core.BlockPara, Text: "上线六月"}}}
|
||
oldSources := materialSources([]core.ParsedDocument{d}, 48000)
|
||
d.Meta.Origin.ParserRevision = "parser-new"
|
||
provided := strings.TrimSpace(d.PlainText())
|
||
if got := annotateProvidedMaterial(d, provided, oldSources); got != provided {
|
||
t.Fatalf("old parser source ID leaked into new parsing: %q", got)
|
||
}
|
||
}
|
||
|
||
func TestMaterialSourceInlineAnnotationsMatchRegistryIDs(t *testing.T) {
|
||
d := core.ParsedDocument{Meta: core.DocMeta{Filename: "多段.txt", Origin: &core.DocumentOrigin{ArtifactID: "multi", ContentHash: strings.Repeat("9", 64), ParserRevision: "txt1"}}, Blocks: []core.DocBlock{{Type: core.BlockPara, Text: "第一段"}, {Type: core.BlockPara, Text: "第二段"}, {Type: core.BlockPara, Text: "第三段"}}}
|
||
sources := materialSources([]core.ParsedDocument{d}, 48000)
|
||
got := annotateProvidedMaterial(d, strings.TrimSpace(d.PlainText()), sources)
|
||
if strings.Count(got, "sourceId=") != len(sources) {
|
||
t.Fatalf("annotation count=%d registry=%d", strings.Count(got, "sourceId="), len(sources))
|
||
}
|
||
for id := range sources {
|
||
if strings.Count(got, "sourceId="+id+" ") != 1 {
|
||
t.Fatalf("registered source %s missing or duplicated", id)
|
||
}
|
||
}
|
||
}
|
||
|
||
func TestMaterialKeyDetectsEqualLengthEdits(t *testing.T) {
|
||
a := []core.ParsedDocument{{Meta: core.DocMeta{Filename: "决定.txt", Parser: "builtin:md"}, Blocks: []core.DocBlock{{Type: core.BlockPara, Text: "上线六月"}}}}
|
||
b := []core.ParsedDocument{{Meta: a[0].Meta, Blocks: []core.DocBlock{{Type: core.BlockPara, Text: "上线七月"}}}}
|
||
if materialKey(a) == materialKey(b) {
|
||
t.Fatal("same length edit reused a prior material result")
|
||
}
|
||
}
|
||
|
||
func TestMaterialSourceQuoteRequiresActualProvidedBlock(t *testing.T) {
|
||
docs := []core.ParsedDocument{{Meta: core.DocMeta{Filename: "决定.txt", Parser: "builtin:md", Origin: &core.DocumentOrigin{ArtifactID: "art1", ContentHash: strings.Repeat("a", 64), ParserRevision: "ir1"}}, Blocks: []core.DocBlock{{Type: core.BlockPara, Text: "上线六月"}, {Type: core.BlockPara, Text: "预算未定"}}}}
|
||
sources := materialSources(docs, 5)
|
||
if len(sources) == 0 {
|
||
t.Fatal("provided source was not registered")
|
||
}
|
||
for id, src := range sources {
|
||
if src.Ref.BlockIndex != 0 {
|
||
continue
|
||
}
|
||
got, err := sources.validate(core.TaskSourceQuote{SourceID: id, BlockIndex: 0, Quote: "上线六月"})
|
||
if err != nil || got.ArtifactID != "art1" {
|
||
t.Fatal("real source rejected", err)
|
||
}
|
||
if _, err = sources.validate(core.TaskSourceQuote{SourceID: id, BlockIndex: 1, Quote: "上线六月"}); err == nil {
|
||
t.Fatal("wrong block accepted")
|
||
}
|
||
if _, err = sources.validate(core.TaskSourceQuote{SourceID: id, BlockIndex: 0, Quote: "上线七月"}); err == nil {
|
||
t.Fatal("invented quote accepted")
|
||
}
|
||
}
|
||
if _, err := sources.validate(core.TaskSourceQuote{SourceID: "foreign", Quote: "上线六月"}); err == nil {
|
||
t.Fatal("foreign source accepted")
|
||
}
|
||
}
|
||
func TestMaterialInputRevisionIncludesProcessingVersion(t *testing.T) {
|
||
items := []materialInputItem{{Parsed: materialDocs()[0], OriginalHash: strings.Repeat("a", 64)}}
|
||
if materialInputRevision(items, "recipe1") == materialInputRevision(items, "recipe2") {
|
||
t.Fatal("processing change reused result")
|
||
}
|
||
}
|
||
func TestMaterialKeyChangesWithParserAndWarnings(t *testing.T) {
|
||
a := materialDocs()
|
||
b := materialDocs()
|
||
b[0].Meta.Parser = "different-parser"
|
||
if materialKey(a) == materialKey(b) {
|
||
t.Fatal("parser version ignored")
|
||
}
|
||
b = materialDocs()
|
||
b[0].Warnings = []string{"未解析图片"}
|
||
if materialKey(a) == materialKey(b) {
|
||
t.Fatal("changed coverage warning ignored")
|
||
}
|
||
b = materialDocs()
|
||
b[0].Meta.ParsedAt = time.Now()
|
||
b[0].Meta.Origin = &core.DocumentOrigin{ArtifactID: "new-upload-id"}
|
||
if materialKey(a) != materialKey(b) {
|
||
t.Fatal("transport identity/time should not change content identity")
|
||
}
|
||
}
|
||
|
||
func TestMaterialSourceDuplicateTextDoesNotAuthorizeUnprovidedBlock(t *testing.T) {
|
||
d := core.ParsedDocument{Meta: core.DocMeta{Filename: "重复.txt", Origin: &core.DocumentOrigin{ArtifactID: "a", ContentHash: "h", ParserRevision: "txt"}}, Blocks: []core.DocBlock{{Type: core.BlockPara, Text: "相同内容"}, {Type: core.BlockPara, Text: "相同内容"}}}
|
||
registry := materialSources([]core.ParsedDocument{d}, 4)
|
||
for _, src := range registry {
|
||
if src.Ref.BlockIndex == 1 {
|
||
t.Fatal("unprovided duplicate block authorized")
|
||
}
|
||
}
|
||
}
|
||
|
||
func TestMaterialTaskExplainsBoundedEvidenceWithoutAnotherModelRound(t *testing.T) {
|
||
c := checkpointEnvironment(t)
|
||
for _, src := range c.sources {
|
||
c.attachments = []core.ParsedDocument{{Meta: core.DocMeta{Filename: "决定.txt", Origin: &core.DocumentOrigin{ArtifactID: src.Ref.ArtifactID, ContentHash: src.Ref.ContentHash, ParserRevision: src.Ref.ParserRevision}}, Blocks: []core.DocBlock{{Type: core.BlockPara, Text: src.Text}}}}
|
||
break
|
||
}
|
||
task := buildMaterialTaskFor(c)
|
||
for _, want := range []string{"publish_work_checkpoint", "evidence", "sourceIndex", "unresolved_relation", "待确认", "材料存在差异,需核对", "原样记载用 material_record,只附 sources,不附 evidence"} {
|
||
if !strings.Contains(task, want) {
|
||
t.Fatalf("material task omits %s", want)
|
||
}
|
||
}
|
||
}
|
||
|
||
func TestMaterialTaskBoundsCheckpointsToHostFinalOnlyNotice(t *testing.T) {
|
||
c := checkpointEnvironment(t)
|
||
for _, src := range c.sources {
|
||
c.attachments = []core.ParsedDocument{{Meta: core.DocMeta{Filename: "决定.txt", Origin: &core.DocumentOrigin{ArtifactID: src.Ref.ArtifactID, ContentHash: src.Ref.ContentHash, ParserRevision: src.Ref.ParserRevision}}, Blocks: []core.DocBlock{{Type: core.BlockPara, Text: src.Text}}}}
|
||
break
|
||
}
|
||
task := buildMaterialTaskFor(c)
|
||
crosscheck := strings.Index(task, "后再次调用,phaseId=crosscheck;")
|
||
bound := strings.Index(task, "检查点通常最多2次")
|
||
if crosscheck < 0 || bound < crosscheck {
|
||
t.Fatal("checkpoint bound is not stated after the crosscheck instruction")
|
||
}
|
||
for _, want := range []string{"检查点通常最多2次", "第2次即 phaseId=crosscheck", "工具结果提示不再接受检查点后", "不再调用 publish_work_checkpoint", "最后输出完整整理结果", "约1500字以内", "一次写完"} {
|
||
if !strings.Contains(task, want) {
|
||
t.Fatalf("material task omits %s", want)
|
||
}
|
||
}
|
||
}
|