Files
dobotai-platform/internal/questiontable/export_rewrite_test.go

138 lines
4.0 KiB
Go

package questiontable
import (
"context"
"strings"
"testing"
"time"
)
type answerRewriterStub struct {
rewritten string
err error
}
func (s answerRewriterStub) Rewrite(ctx context.Context, content string) (string, error) {
return s.rewritten, s.err
}
func TestRunOnceRewritesAnswerBeforeInsert(t *testing.T) {
repo := newStubRepo()
inserter := newStubInserter()
inserter.recordID = "rec-rewrite-1"
repo.claimFn = func(ctx context.Context, limit int, maxAttempts int, staleBefore time.Time) ([]PendingExport, error) {
return []PendingExport{
{
ExportID: "exp-rewrite",
Row: Row{
Question: "机械臂如何学习使用呢",
Answer: "原始答案含[[3](#_Toc1)]和![图](resource://abc)",
AskedTime: time.Now(),
AskerName: "张三",
AskerUnionID: "union-z",
TriggerPerson: "张三",
Department: "研发部",
Region: "华东",
QuestionImageURLs: []string{"https://weknora-api.example/i/001"},
},
Attempts: 0,
},
}, nil
}
rw := answerRewriterStub{rewritten: "转换后答案[3]", err: nil}
d, err := NewDispatcher(repo, inserter, &DispatcherOptions{Rewriter: rw})
if err != nil {
t.Fatalf("NewDispatcher: %v", err)
}
stats, err := d.RunOnce(context.Background())
if err != nil {
t.Fatalf("RunOnce: %v", err)
}
if stats.Claimed != 1 || stats.Exported != 1 || stats.Failed != 0 {
t.Fatalf("stats=%+v", stats)
}
if len(inserter.rows) != 1 {
t.Fatalf("rows=%d, want 1", len(inserter.rows))
}
row := inserter.rows[0]
if row.Answer != "转换后答案[3]" {
t.Fatalf("Answer=%q, want rewritten", row.Answer)
}
}
func TestRunOnceRewriterErrorFallsBackToOriginalAnswer(t *testing.T) {
repo := newStubRepo()
inserter := newStubInserter()
inserter.recordID = "rec-fallback-1"
repo.claimFn = func(ctx context.Context, limit int, maxAttempts int, staleBefore time.Time) ([]PendingExport, error) {
return []PendingExport{
{
ExportID: "exp-fallback",
Row: Row{
Question: "问题",
Answer: "原始答案",
AskedTime: time.Now(),
},
Attempts: 0,
},
}, nil
}
rw := answerRewriterStub{rewritten: "", err: context.DeadlineExceeded}
d, err := NewDispatcher(repo, inserter, &DispatcherOptions{Rewriter: rw})
if err != nil {
t.Fatalf("NewDispatcher: %v", err)
}
stats, err := d.RunOnce(context.Background())
if err != nil {
t.Fatalf("RunOnce: %v", err)
}
if stats.Failed != 0 || stats.Exported != 1 {
t.Fatalf("stats=%+v", stats)
}
if len(inserter.rows) != 1 || inserter.rows[0].Answer != "原始答案" {
t.Fatalf("rows=%+v, want fallback original answer", inserter.rows)
}
}
func TestRowToFieldsIncludesQuestionImageURLsAndImageMarker(t *testing.T) {
r := Row{
Question: "请描述并分析这张图片。",
Answer: "回答了。",
AskedTime: time.Now(),
AskerName: "张三",
AskerUnionID: "union-z",
TriggerPerson: "张三",
Department: "研发部",
Region: "华东",
QuestionImageURLs: []string{
"https://weknora-api.example/i/001",
"https://weknora-api.example/i/002",
},
}
fields := r.ToFields()
original, ok := fields[FieldOriginalQuestion].(string)
if !ok {
t.Fatalf("OriginalQuestion type=%T", fields[FieldOriginalQuestion])
}
if !strings.HasPrefix(original, "[图片]") {
t.Fatalf("OriginalQuestion=%q, want [图片] prefix", original)
}
// Image URLs must be rendered as markdown image syntax so the Notable cell
// previews them (same as the answer column), not as a plain-text link.
if !strings.Contains(original, "![图片1](https://weknora-api.example/i/001)") ||
!strings.Contains(original, "![图片2](https://weknora-api.example/i/002)") {
t.Fatalf("OriginalQuestion=%q, missing markdown image syntax", original)
}
// Without image URLs, no [图片] prefix.
plain := Row{Question: "普通问题", AskedTime: time.Now()}
if got := plain.ToFields()[FieldOriginalQuestion]; got != "普通问题" {
t.Fatalf("plain OriginalQuestion=%q, want unchanged", got)
}
}