| New file |
| | |
| | | package index |
| | | |
| | | import ( |
| | | "os" |
| | | "path/filepath" |
| | | "testing" |
| | | ) |
| | | |
| | | func TestRetryUnresolved(t *testing.T) { |
| | | dir := t.TempDir() |
| | | os.MkdirAll(filepath.Join(dir, "FAQ"), 0755) |
| | | os.WriteFile(filepath.Join(dir, "FAQ", "001-旧文档.md"), |
| | | []byte("---\ntitle: 旧文档\n---\n提到 [[补气失败]]\n"), 0644) |
| | | |
| | | store, _ := Open(filepath.Join(t.TempDir(), "kb.db")) |
| | | defer store.Close() |
| | | |
| | | Reconcile(store, dir) |
| | | |
| | | // 验证悬空链接入表 |
| | | var n int |
| | | store.db.QueryRow(`SELECT COUNT(*) FROM unresolved_links WHERE link_text='补气失败'`).Scan(&n) |
| | | if n != 1 { |
| | | t.Fatalf("悬空链接未入表: %d", n) |
| | | } |
| | | |
| | | // 新文档入库:标题正好是 "补气失败" |
| | | os.WriteFile(filepath.Join(dir, "FAQ", "002-补气失败.md"), |
| | | []byte("---\ntitle: 补气失败\n---\n补气失败排查\n"), 0644) |
| | | |
| | | res, err := Reconcile(store, dir) |
| | | if err != nil { |
| | | t.Fatal(err) |
| | | } |
| | | if res.Added != 1 { |
| | | t.Fatalf("新增: %+v", res) |
| | | } |
| | | |
| | | // 悬空链接应被解析:行删除 + 边建立 |
| | | store.db.QueryRow(`SELECT COUNT(*) FROM unresolved_links WHERE link_text='补气失败'`).Scan(&n) |
| | | if n != 0 { |
| | | t.Errorf("悬空行未清除: %d", n) |
| | | } |
| | | store.db.QueryRow(`SELECT COUNT(*) FROM edges WHERE relation='wikilink' AND label='补气失败'`).Scan(&n) |
| | | if n != 1 { |
| | | t.Errorf("wikilink 边未建立: %d", n) |
| | | } |
| | | var prov string |
| | | store.db.QueryRow(`SELECT provenance FROM edges WHERE relation='wikilink' AND label='补气失败'`).Scan(&prov) |
| | | if prov != "exact" { |
| | | t.Errorf("补全边应为 exact: %s", prov) |
| | | } |
| | | } |
| | | |
| | | func TestResolveWikilinkEmptyLink(t *testing.T) { |
| | | dir := t.TempDir() |
| | | os.MkdirAll(filepath.Join(dir, "FAQ"), 0755) |
| | | os.WriteFile(filepath.Join(dir, "FAQ", "001-文档.md"), |
| | | []byte("---\ntitle: 文档\n---\n提到 [[|别名]]\n"), 0644) |
| | | |
| | | store, _ := Open(filepath.Join(t.TempDir(), "kb.db")) |
| | | defer store.Close() |
| | | Reconcile(store, dir) |
| | | |
| | | // 空 link 不应 fuzzy 误建边(Contains 空串恒真) |
| | | var n int |
| | | store.db.QueryRow(`SELECT COUNT(*) FROM edges WHERE relation='wikilink' AND label='|别名'`).Scan(&n) |
| | | if n != 0 { |
| | | t.Errorf("空 link 不应建 wikilink 边: %d", n) |
| | | } |
| | | // 悬空行应入表且只入一行 |
| | | store.db.QueryRow(`SELECT COUNT(*) FROM unresolved_links WHERE link_text='|别名'`).Scan(&n) |
| | | if n != 1 { |
| | | t.Errorf("悬空行应为 1: %d", n) |
| | | } |
| | | } |
| | | |
| | | func TestTagEntityEdgeProvenance(t *testing.T) { |
| | | dir := t.TempDir() |
| | | os.MkdirAll(filepath.Join(dir, "FAQ"), 0755) |
| | | os.WriteFile(filepath.Join(dir, "FAQ", "001-文档.md"), |
| | | []byte("---\ntitle: 文档\ntags: [t1]\nentities: [张三]\n---\n内容\n"), 0644) |
| | | |
| | | store, _ := Open(filepath.Join(t.TempDir(), "kb.db")) |
| | | defer store.Close() |
| | | Reconcile(store, dir) |
| | | |
| | | // tag/entity 边的 provenance 应为 relation 本身(Minor 1 修复) |
| | | var prov string |
| | | store.db.QueryRow(`SELECT provenance FROM edges WHERE relation='tag' AND label='t1'`).Scan(&prov) |
| | | if prov != "tag" { |
| | | t.Errorf("tag 边 provenance: %q", prov) |
| | | } |
| | | store.db.QueryRow(`SELECT provenance FROM edges WHERE relation='entity' AND label='张三'`).Scan(&prov) |
| | | if prov != "entity" { |
| | | t.Errorf("entity 边 provenance: %q", prov) |
| | | } |
| | | } |
| | | |
| | | // TestGetUnresolvedLinks 覆盖 GetUnresolvedLinks 查询(explore 命令悬空链接提示用) |
| | | func TestGetUnresolvedLinks(t *testing.T) { |
| | | dir := t.TempDir() |
| | | os.MkdirAll(filepath.Join(dir, "FAQ"), 0755) |
| | | // 文档 A 有两条悬空链接;文档 B 无 |
| | | os.WriteFile(filepath.Join(dir, "FAQ", "001-文档A.md"), |
| | | []byte("---\ntitle: 文档A\n---\n提到 [[悬空甲]] 和 [[悬空乙]]\n"), 0644) |
| | | os.WriteFile(filepath.Join(dir, "FAQ", "002-文档B.md"), |
| | | []byte("---\ntitle: 文档B\n---\n无链接\n"), 0644) |
| | | |
| | | store, _ := Open(filepath.Join(t.TempDir(), "kb.db")) |
| | | defer store.Close() |
| | | Reconcile(store, dir) |
| | | |
| | | links, err := store.GetUnresolvedLinks("FAQ/001-文档A.md") |
| | | if err != nil { |
| | | t.Fatalf("GetUnresolvedLinks failed: %v", err) |
| | | } |
| | | if len(links) != 2 { |
| | | t.Fatalf("文档A 悬空链接 = %d, want 2: %v", len(links), links) |
| | | } |
| | | |
| | | // 无悬空链接的文档返回空(非 nil 错误) |
| | | links, err = store.GetUnresolvedLinks("FAQ/002-文档B.md") |
| | | if err != nil { |
| | | t.Fatalf("GetUnresolvedLinks(文档B) failed: %v", err) |
| | | } |
| | | if len(links) != 0 { |
| | | t.Errorf("文档B 悬空链接 = %d, want 0: %v", len(links), links) |
| | | } |
| | | } |