package correctioncsv_test
|
|
import (
|
"bytes"
|
"encoding/csv"
|
"encoding/json"
|
"os"
|
"path/filepath"
|
"testing"
|
"time"
|
"voicesnap/internal/correctioncsv"
|
"voicesnap/internal/history"
|
"voicesnap/internal/userdict"
|
)
|
|
func TestCorrectionCSVEndToEndPreviewThenAppend(t *testing.T) {
|
home := t.TempDir()
|
t.Setenv("HOME", home)
|
t.Setenv("XDG_CONFIG_HOME", filepath.Join(home, ".config"))
|
|
store := userdict.New()
|
if _, err := store.AppendNewReplacements([]userdict.Replacement{
|
{From: "点 CSV", To: ".csv"},
|
{From: "麦克", To: "Mac"},
|
}); err != nil {
|
t.Fatal(err)
|
}
|
|
exported, err := correctioncsv.BuildHistoryCSV([]history.Entry{
|
{Timestamp: time.Date(2026, 5, 30, 13, 9, 0, 0, time.UTC).UnixMilli(), Text: "普通中文句子"},
|
{Timestamp: time.Date(2026, 5, 30, 13, 10, 0, 0, time.UTC).UnixMilli(), Text: "CSV 2026, \"quoted\"\nnext"},
|
{Timestamp: time.Date(2026, 5, 30, 13, 11, 0, 0, time.UTC).UnixMilli(), Text: "已经后处理的最终文本"},
|
}, time.UTC)
|
if err != nil {
|
t.Fatal(err)
|
}
|
|
records := readCSV(t, exported)
|
if len(records) != 5 {
|
t.Fatalf("expected header, example, and 3 history rows, got %d rows", len(records))
|
}
|
records[2][3] = "点 PDF"
|
records[2][4] = ".pdf"
|
records[2][5] = "点 CSV"
|
records[2][6] = ".csv"
|
records[2][7] = "麦克"
|
records[2][8] = "Mike"
|
records[3][3] = "换\n行"
|
records[3][4] = "换行词"
|
|
importData := writeCSV(t, records)
|
before := readUserDictFile(t, store.Path())
|
|
preview, err := correctioncsv.ParseAndPreviewCSV(importData, store.GetAll(), correctioncsv.Options{})
|
if err != nil {
|
t.Fatal(err)
|
}
|
afterPreview := readUserDictFile(t, store.Path())
|
if !bytes.Equal(before, afterPreview) {
|
t.Fatal("preview changed userdict.json before confirmation")
|
}
|
|
if preview.Summary.New != 2 {
|
t.Fatalf("expected 2 new rules, got %+v", preview.Summary)
|
}
|
if preview.Summary.DictDuplicate != 1 {
|
t.Fatalf("expected 1 dictionary duplicate, got %+v", preview.Summary)
|
}
|
if preview.Summary.Conflict != 1 {
|
t.Fatalf("expected 1 conflict, got %+v", preview.Summary)
|
}
|
|
added, err := store.AppendNewReplacements(toReplacements(preview.NewRules))
|
if err != nil {
|
t.Fatal(err)
|
}
|
if len(added) != 2 {
|
t.Fatalf("expected 2 appended rules, got %d", len(added))
|
}
|
if got := store.Apply("点 PDF 和 换 行 和 点 CSV 和 麦克"); got != ".pdf 和 换行词 和 .csv 和 Mac" {
|
t.Fatalf("unexpected applied text: %q", got)
|
}
|
}
|
|
func toReplacements(rules []correctioncsv.Rule) []userdict.Replacement {
|
replacements := make([]userdict.Replacement, 0, len(rules))
|
for _, rule := range rules {
|
replacements = append(replacements, userdict.Replacement{From: rule.From, To: rule.To})
|
}
|
return replacements
|
}
|
|
func readCSV(t *testing.T, data []byte) [][]string {
|
t.Helper()
|
reader := csv.NewReader(bytes.NewReader(bytes.TrimPrefix(data, []byte{0xEF, 0xBB, 0xBF})))
|
records, err := reader.ReadAll()
|
if err != nil {
|
t.Fatal(err)
|
}
|
return records
|
}
|
|
func writeCSV(t *testing.T, records [][]string) []byte {
|
t.Helper()
|
var buf bytes.Buffer
|
writer := csv.NewWriter(&buf)
|
for _, row := range records {
|
if err := writer.Write(row); err != nil {
|
t.Fatal(err)
|
}
|
}
|
writer.Flush()
|
if err := writer.Error(); err != nil {
|
t.Fatal(err)
|
}
|
return buf.Bytes()
|
}
|
|
func readUserDictFile(t *testing.T, path string) []byte {
|
t.Helper()
|
data, err := os.ReadFile(path)
|
if err != nil {
|
t.Fatal(err)
|
}
|
var parsed any
|
if err := json.Unmarshal(data, &parsed); err != nil {
|
t.Fatal(err)
|
}
|
return data
|
}
|