Ariver
2026-06-30 5b5cba7030b7f4dd519868fe310bb4fce893bf91
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
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
}