ax_rd
4 hours ago 60eb89c12ee0661785395bff90940204b16dcb3a
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
package index
 
import (
    "os"
    "path/filepath"
    "testing"
    "time"
)
 
func TestReconcileAdd(t *testing.T) {
    dir := t.TempDir()
    if err := os.MkdirAll(filepath.Join(dir, "FAQ"), 0755); err != nil {
        t.Fatal(err)
    }
    content := "---\ntitle: 测试文档\ntags: [t1]\nstatus: 已解决\n---\n正文\n"
    if err := os.WriteFile(filepath.Join(dir, "FAQ", "001-测试文档.md"), []byte(content), 0644); err != nil {
        t.Fatal(err)
    }
 
    store, err := Open(filepath.Join(t.TempDir(), "kb.db"))
    if err != nil {
        t.Fatal(err)
    }
    defer store.Close()
 
    res, err := Reconcile(store, dir)
    if err != nil {
        t.Fatal(err)
    }
    if res.Added != 1 || res.Unchanged != 0 {
        t.Errorf("新增场景: %+v", res)
    }
    var title, status string
    if err := store.db.QueryRow(`SELECT title, status FROM nodes WHERE path='FAQ/001-测试文档.md'`).Scan(&title, &status); err != nil {
        t.Fatal(err)
    }
    if title != "测试文档" || status != "已解决" {
        t.Errorf("节点字段错误: %s / %s", title, status)
    }
}
 
func TestReconcileModify(t *testing.T) {
    dir := t.TempDir()
    if err := os.MkdirAll(filepath.Join(dir, "FAQ"), 0755); err != nil {
        t.Fatal(err)
    }
    p := filepath.Join(dir, "FAQ", "001-测试文档.md")
    if err := os.WriteFile(p, []byte("---\ntitle: 旧标题\n---\n旧内容\n"), 0644); err != nil {
        t.Fatal(err)
    }
 
    store, err := Open(filepath.Join(t.TempDir(), "kb.db"))
    if err != nil {
        t.Fatal(err)
    }
    defer store.Close()
    if _, err := Reconcile(store, dir); err != nil {
        t.Fatal(err)
    }
 
    // 修改内容(title 变新标题,内容加"补气")
    time.Sleep(1100 * time.Millisecond) // mtime 秒级精度,确保 mtime 变化
    if err := os.WriteFile(p, []byte("---\ntitle: 新标题\n---\n新内容补气\n"), 0644); err != nil {
        t.Fatal(err)
    }
 
    res, err := Reconcile(store, dir)
    if err != nil {
        t.Fatal(err)
    }
    if res.Modified != 1 || res.Added != 0 {
        t.Errorf("修改场景: %+v", res)
    }
    var title string
    if err := store.db.QueryRow(`SELECT title FROM nodes WHERE path='FAQ/001-测试文档.md'`).Scan(&title); err != nil {
        t.Fatal(err)
    }
    if title != "新标题" {
        t.Errorf("标题未更新: %s", title)
    }
}
 
func TestReconcileDelete(t *testing.T) {
    dir := t.TempDir()
    if err := os.MkdirAll(filepath.Join(dir, "FAQ"), 0755); err != nil {
        t.Fatal(err)
    }
    p := filepath.Join(dir, "FAQ", "001-测试文档.md")
    if err := os.WriteFile(p, []byte("---\ntitle: 测试文档\n---\n内容\n"), 0644); err != nil {
        t.Fatal(err)
    }
 
    store, err := Open(filepath.Join(t.TempDir(), "kb.db"))
    if err != nil {
        t.Fatal(err)
    }
    defer store.Close()
    if _, err := Reconcile(store, dir); err != nil {
        t.Fatal(err)
    }
    if err := os.Remove(p); err != nil {
        t.Fatal(err)
    }
 
    res, err := Reconcile(store, dir)
    if err != nil {
        t.Fatal(err)
    }
    if res.Deleted != 1 {
        t.Errorf("删除场景: %+v", res)
    }
    var n int
    if err := store.db.QueryRow(`SELECT COUNT(*) FROM nodes`).Scan(&n); err != nil {
        t.Fatal(err)
    }
    if n != 0 {
        t.Errorf("节点未删净: %d", n)
    }
}
 
func TestReconcileUnchanged(t *testing.T) {
    dir := t.TempDir()
    if err := os.MkdirAll(filepath.Join(dir, "FAQ"), 0755); err != nil {
        t.Fatal(err)
    }
    if err := os.WriteFile(filepath.Join(dir, "FAQ", "001-测试文档.md"),
        []byte("---\ntitle: 测试文档\n---\n内容\n"), 0644); err != nil {
        t.Fatal(err)
    }
 
    store, err := Open(filepath.Join(t.TempDir(), "kb.db"))
    if err != nil {
        t.Fatal(err)
    }
    defer store.Close()
    if _, err := Reconcile(store, dir); err != nil {
        t.Fatal(err)
    }
 
    res, err := Reconcile(store, dir)
    if err != nil {
        t.Fatal(err)
    }
    if res.Unchanged != 1 || res.Added != 0 || res.Modified != 0 {
        t.Errorf("未变场景: %+v", res)
    }
}
 
func TestQuickCheck(t *testing.T) {
    dir := t.TempDir()
    if err := os.MkdirAll(filepath.Join(dir, "FAQ"), 0755); err != nil {
        t.Fatal(err)
    }
    if err := os.WriteFile(filepath.Join(dir, "FAQ", "001-测试文档.md"),
        []byte("---\ntitle: 测试文档\n---\n内容\n"), 0644); err != nil {
        t.Fatal(err)
    }
 
    store, err := Open(filepath.Join(t.TempDir(), "kb.db"))
    if err != nil {
        t.Fatal(err)
    }
    defer store.Close()
    if _, err := Reconcile(store, dir); err != nil {
        t.Fatal(err)
    }
 
    dirty, err := QuickCheck(store, dir)
    if err != nil {
        t.Fatal(err)
    }
    if dirty {
        t.Error("无差异时 QuickCheck 应 false")
    }
}