package main import ( "archive/zip" "context" "database/sql" "encoding/csv" "os" "path/filepath" "testing" _ "modernc.org/sqlite" ) func TestParseDocumentXMLExtractsTableCells(t *testing.T) { xml := ` 报备表 序号 事件过程 1 起因处理经过 ` tables, err := parseDocumentXML([]byte(xml)) if err != nil { t.Fatalf("parseDocumentXML returned error: %v", err) } if len(tables) != 1 { t.Fatalf("got %d tables, want 1", len(tables)) } if got := tables[0].Rows[0].Cells[0].Text; got != "报备表" { t.Fatalf("title cell text = %q, want 报备表", got) } if got := tables[0].Rows[0].Cells[0].ColSpan; got != 2 { t.Fatalf("title cell colspan = %d, want 2", got) } if got := tables[0].Rows[2].Cells[1].Text; got != "起因\n处理经过" { t.Fatalf("multiline text = %q, want 起因\\n处理经过", got) } } func TestInferHeaderFieldsSkipsTitleRow(t *testing.T) { table := Table{ Rows: []Row{ {Cells: []Cell{{Text: "报备表", ColSpan: 2}}}, {Cells: []Cell{{Text: "序号", ColSpan: 1}, {Text: "事件过程", ColSpan: 1}}}, {Cells: []Cell{{Text: "1", ColSpan: 1}, {Text: "客户反映设备位置不合理", ColSpan: 1}}}, }, } fields := inferFields(table) if len(fields) != 2 { t.Fatalf("got %d fields, want 2", len(fields)) } if fields[0].Key != "序号" || fields[0].Value != "1" || fields[0].SourceKind != "header_row" { t.Fatalf("unexpected first field: %#v", fields[0]) } if fields[1].Key != "事件过程" || fields[1].Value != "客户反映设备位置不合理" { t.Fatalf("unexpected second field: %#v", fields[1]) } } 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) if err != nil { t.Fatalf("open sqlite: %v", err) } defer db.Close() xml := ` 报备表 序号事件过程 1客户反映设备位置不合理 ` docxPath := filepath.Join(t.TempDir(), "sample.docx") if err := writeTestDocx(docxPath, []byte(xml)); err != nil { t.Fatalf("write test docx: %v", err) } if err := importDocument(context.Background(), db, docxPath); err != nil { t.Fatalf("importDocument: %v", err) } var cells int if err := db.QueryRow(`SELECT COUNT(*) FROM cells`).Scan(&cells); err != nil { t.Fatalf("count cells: %v", err) } if cells != 5 { t.Fatalf("got %d cells, want 5", cells) } var value string if err := db.QueryRow(`SELECT value FROM fields WHERE key = '事件过程'`).Scan(&value); err != nil { t.Fatalf("query field: %v", err) } if value != "客户反映设备位置不合理" { t.Fatalf("field value = %q", value) } } func TestRunExportsFieldsCSV(t *testing.T) { dir := t.TempDir() dbPath := filepath.Join(dir, "import.sqlite") outPath := filepath.Join(dir, "fields.csv") xml := ` 字段内容 工单编号9726060110063361 ` 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 { return err } defer f.Close() zw := zip.NewWriter(f) defer zw.Close() w, err := zw.Create("word/document.xml") if err != nil { return err } _, err = w.Write(documentXML) return err }