Files
xls_doc/internal/docfill/p0_test.go
2026-06-18 20:03:47 +08:00

275 lines
7.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package docfill
import (
"database/sql"
"os"
"path/filepath"
"strings"
"testing"
)
func TestRunResolvesConfigRelativePathsAndSanitizesOutputFileNames(t *testing.T) {
dir := t.TempDir()
taskDir := filepath.Join(dir, "task")
if err := os.MkdirAll(taskDir, 0o755); err != nil {
t.Fatalf("make task dir: %v", err)
}
writeWorkbook(t, filepath.Join(taskDir, "data.xlsx"), "Daily", [][]string{
{"name", "done"},
{"张/三:测试", "已完成"},
})
writeWorkbook(t, filepath.Join(taskDir, "template.xlsx"), "日报", [][]string{
{"{{name}}", "{{done}}"},
})
configPath := filepath.Join(taskDir, "task.json")
writeJSON(t, configPath, map[string]any{
"data": map[string]any{
"type": "excel",
"path": "./data.xlsx",
"sheet": "Daily",
},
"template": map[string]any{
"path": "./template.xlsx",
},
"output": map[string]any{
"path": "./out/日报_{{name}}.xlsx",
},
})
result, err := RunWithOptions(configPath, RunOptions{})
if err != nil {
t.Fatalf("RunWithOptions returned error: %v", err)
}
wantPath := filepath.Join(taskDir, "out", "日报_张_三_测试.xlsx")
if len(result.Files) != 1 || result.Files[0] != wantPath {
t.Fatalf("result files = %#v, want %q", result.Files, wantPath)
}
assertWorkbookCell(t, wantPath, "日报", "A1", "张/三:测试")
}
func TestRunUsesVarsForSQLiteParamsAndTemplateDefaults(t *testing.T) {
dir := t.TempDir()
dbPath := filepath.Join(dir, "daily.db")
templatePath := filepath.Join(dir, "template.docx")
configPath := filepath.Join(dir, "task.json")
seedP0SQLite(t, dbPath, `
create table daily (name text, date text, done text);
insert into daily values
('张三', '2026-06-18', '完成旧日报'),
('李四', '2026-06-19', '完成新日报');
`)
writeMinimalDocx(t, templatePath, "批次:{{batch}}\n日期{{date}}\n员工{{name}}\n内容{{done}}")
writeJSON(t, configPath, map[string]any{
"vars": map[string]any{
"date": "2026-06-18",
"batch": "默认批次",
},
"data": map[string]any{
"type": "sqlite",
"path": dbPath,
"query": "select name, date, done from daily where date = ?",
"params": []any{"{{date}}"},
},
"template": map[string]any{
"path": templatePath,
},
"output": map[string]any{
"path": filepath.Join(dir, "out", "日报_{{batch}}_{{date}}_{{name}}.docx"),
},
})
result, err := RunWithOptions(configPath, RunOptions{
Vars: map[string]string{
"date": "2026-06-19",
"batch": "命令行批次",
},
})
if err != nil {
t.Fatalf("RunWithOptions returned error: %v", err)
}
if len(result.Files) != 1 {
t.Fatalf("expected 1 generated file, got %#v", result.Files)
}
got := readZipEntry(t, result.Files[0], "word/document.xml")
if !strings.Contains(got, "批次:命令行批次") || !strings.Contains(got, "员工:李四") {
t.Fatalf("unexpected rendered docx body: %q", got)
}
if strings.Contains(got, "张三") || strings.Contains(result.Files[0], "默认批次") {
t.Fatalf("CLI vars did not override config vars: file=%q body=%q", result.Files[0], got)
}
}
func TestRunSupportsExcelHeaderRow(t *testing.T) {
dir := t.TempDir()
dataPath := filepath.Join(dir, "data.xlsx")
templatePath := filepath.Join(dir, "template.xlsx")
configPath := filepath.Join(dir, "task.json")
writeWorkbook(t, dataPath, "Daily", [][]string{
{"日报导出数据"},
{"name", "done"},
{"张三", "完成日报"},
})
writeWorkbook(t, templatePath, "日报", [][]string{
{"员工", "{{name}}"},
{"完成", "{{done}}"},
})
writeJSON(t, configPath, map[string]any{
"data": map[string]any{
"type": "excel",
"path": dataPath,
"sheet": "Daily",
"header_row": 2,
},
"template": map[string]any{
"path": templatePath,
},
"output": map[string]any{
"path": filepath.Join(dir, "out", "日报_{{name}}.xlsx"),
},
})
if err := Run(configPath); err != nil {
t.Fatalf("Run returned error: %v", err)
}
assertWorkbookCell(t, filepath.Join(dir, "out", "日报_张三.xlsx"), "日报", "B1", "张三")
}
func TestRunRefusesToOverwriteUnlessConfigured(t *testing.T) {
dir := t.TempDir()
dataPath := filepath.Join(dir, "data.xlsx")
templatePath := filepath.Join(dir, "template.xlsx")
configPath := filepath.Join(dir, "task.json")
outputPath := filepath.Join(dir, "out", "日报_张三.xlsx")
writeWorkbook(t, dataPath, "Daily", [][]string{
{"name"},
{"张三"},
})
writeWorkbook(t, templatePath, "日报", [][]string{{"{{name}}"}})
if err := os.MkdirAll(filepath.Dir(outputPath), 0o755); err != nil {
t.Fatalf("make output dir: %v", err)
}
if err := os.WriteFile(outputPath, []byte("existing"), 0o644); err != nil {
t.Fatalf("write existing output: %v", err)
}
writeJSON(t, configPath, map[string]any{
"data": map[string]any{
"type": "excel",
"path": dataPath,
"sheet": "Daily",
},
"template": map[string]any{
"path": templatePath,
},
"output": map[string]any{
"path": outputPath,
},
})
err := Run(configPath)
if err == nil || !strings.Contains(err.Error(), "already exists") {
t.Fatalf("expected already exists error, got %v", err)
}
writeJSON(t, configPath, map[string]any{
"data": map[string]any{
"type": "excel",
"path": dataPath,
"sheet": "Daily",
},
"template": map[string]any{
"path": templatePath,
},
"output": map[string]any{
"path": outputPath,
"overwrite": true,
},
})
if err := Run(configPath); err != nil {
t.Fatalf("Run with overwrite returned error: %v", err)
}
assertWorkbookCell(t, outputPath, "日报", "A1", "张三")
}
func TestRunFailsWhenTemplatePlaceholderIsMissing(t *testing.T) {
dir := t.TempDir()
dataPath := filepath.Join(dir, "data.xlsx")
templatePath := filepath.Join(dir, "template.xlsx")
configPath := filepath.Join(dir, "task.json")
writeWorkbook(t, dataPath, "Daily", [][]string{
{"name"},
{"张三"},
})
writeWorkbook(t, templatePath, "日报", [][]string{{"{{name}}", "{{missing}}"}})
writeJSON(t, configPath, map[string]any{
"data": map[string]any{
"type": "excel",
"path": dataPath,
"sheet": "Daily",
},
"template": map[string]any{
"path": templatePath,
},
"output": map[string]any{
"path": filepath.Join(dir, "out", "日报_{{name}}.xlsx"),
},
})
err := Run(configPath)
if err == nil || !strings.Contains(err.Error(), "missing template field") {
t.Fatalf("expected missing template field error, got %v", err)
}
}
func TestRunFailsWhenRenderedTemplateStillHasPlaceholder(t *testing.T) {
dir := t.TempDir()
dataPath := filepath.Join(dir, "data.xlsx")
templatePath := filepath.Join(dir, "template.xlsx")
configPath := filepath.Join(dir, "task.json")
writeWorkbook(t, dataPath, "Daily", [][]string{
{"name", "done"},
{"张三", "{{still_pending}}"},
})
writeWorkbook(t, templatePath, "日报", [][]string{{"{{name}}", "{{done}}"}})
writeJSON(t, configPath, map[string]any{
"data": map[string]any{
"type": "excel",
"path": dataPath,
"sheet": "Daily",
},
"template": map[string]any{
"path": templatePath,
},
"output": map[string]any{
"path": filepath.Join(dir, "out", "日报_{{name}}.xlsx"),
},
})
err := Run(configPath)
if err == nil || !strings.Contains(err.Error(), "unresolved placeholder") {
t.Fatalf("expected unresolved placeholder error, got %v", err)
}
}
func seedP0SQLite(t *testing.T, path, statements string) {
t.Helper()
db, err := sql.Open("sqlite", path)
if err != nil {
t.Fatalf("open sqlite: %v", err)
}
defer db.Close()
if _, err := db.Exec(statements); err != nil {
t.Fatalf("seed sqlite: %v", err)
}
}