Address CSV export and field alignment review

This commit is contained in:
赵义仑
2026-06-24 16:31:35 +08:00
parent 9fab4c73ed
commit 915702f8f3
5 changed files with 304 additions and 16 deletions

View File

@@ -4,6 +4,7 @@ import (
"archive/zip"
"context"
"database/sql"
"encoding/csv"
"os"
"path/filepath"
"testing"
@@ -70,6 +71,27 @@ func TestInferHeaderFieldsSkipsTitleRow(t *testing.T) {
}
}
func TestInferHeaderFieldsAlignsByLogicalColumnWithColSpan(t *testing.T) {
table := Table{
Rows: []Row{
{Cells: []Cell{{Text: "序号", ColIndex: 0, ColSpan: 1}, {Text: "客户信息", ColIndex: 1, ColSpan: 2}, {Text: "工单编号", ColIndex: 3, ColSpan: 1}}},
{Cells: []Cell{{Text: "1", ColIndex: 0, ColSpan: 1}, {Text: "高先生", ColIndex: 1, ColSpan: 1}, {Text: "靖远县乌兰镇", ColIndex: 2, ColSpan: 1}, {Text: "9726060110063361", ColIndex: 3, ColSpan: 1}}},
},
}
fields := inferFields(table)
got := fieldMap(fields)
if got["序号"] != "1" {
t.Fatalf("序号 = %q, want 1", got["序号"])
}
if got["客户信息"] != "高先生\n靖远县乌兰镇" {
t.Fatalf("客户信息 = %q, want combined logical-column value", got["客户信息"])
}
if got["工单编号"] != "9726060110063361" {
t.Fatalf("工单编号 = %q, want 9726060110063361", got["工单编号"])
}
}
func TestImportDocumentWritesSQLiteTables(t *testing.T) {
dbPath := filepath.Join(t.TempDir(), "import.sqlite")
db, err := sql.Open("sqlite", dbPath)
@@ -115,6 +137,59 @@ func TestImportDocumentWritesSQLiteTables(t *testing.T) {
}
}
func TestRunExportsFieldsCSV(t *testing.T) {
dir := t.TempDir()
dbPath := filepath.Join(dir, "import.sqlite")
outPath := filepath.Join(dir, "fields.csv")
xml := `<?xml version="1.0" encoding="UTF-8"?>
<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
<w:body>
<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>9726060110063361</w:t></w:r></w:p></w:tc></w:tr>
</w:tbl>
</w:body>
</w:document>`
docxPath := filepath.Join(dir, "sample.docx")
if err := writeTestDocx(docxPath, []byte(xml)); err != nil {
t.Fatalf("write test docx: %v", err)
}
if err := run([]string{"-reset", "-quiet", "-db", dbPath, docxPath}); err != nil {
t.Fatalf("import run: %v", err)
}
if err := run([]string{"export-fields", "-db", dbPath, "-out", outPath}); err != nil {
t.Fatalf("export run: %v", err)
}
f, err := os.Open(outPath)
if err != nil {
t.Fatalf("open csv: %v", err)
}
defer f.Close()
records, err := csv.NewReader(f).ReadAll()
if err != nil {
t.Fatalf("read csv: %v", err)
}
if len(records) != 3 {
t.Fatalf("got %d csv records, want header + 2 fields: %#v", len(records), records)
}
if records[0][0] != "filename" || records[0][1] != "key" || records[0][2] != "value" {
t.Fatalf("unexpected header: %#v", records[0])
}
if records[2][1] != "内容" || records[2][2] != "9726060110063361" {
t.Fatalf("unexpected exported field: %#v", records[2])
}
}
func fieldMap(fields []Field) map[string]string {
out := map[string]string{}
for _, field := range fields {
out[field.Key] = field.Value
}
return out
}
func writeTestDocx(path string, documentXML []byte) error {
f, err := os.Create(path)
if err != nil {