141 lines
4.3 KiB
Go
141 lines
4.3 KiB
Go
package collector
|
||
|
||
import (
|
||
"encoding/json"
|
||
"io"
|
||
"net/http"
|
||
"net/http/httptest"
|
||
"os"
|
||
"path/filepath"
|
||
"strings"
|
||
"testing"
|
||
"time"
|
||
)
|
||
|
||
const legacyCard = `---
|
||
tags: [測試]
|
||
gloss: 測試卡
|
||
created: 2026-08-01
|
||
updated: 2026-08-01
|
||
---
|
||
# 小果被AFTEE詐貸
|
||
|
||
← [[00-INDEX]]
|
||
|
||
## 摘要
|
||
一段摘要。
|
||
|
||
## 重點
|
||
- 一條重點
|
||
|
||
## 實體
|
||
- **小果**(人物)— 當事人
|
||
|
||
## 關聯
|
||
### 內文知識關係
|
||
- 小果 >` + `> 被詐貸 >` + `> AFTEE
|
||
### 卡片關係
|
||
- [[小果被AFTEE詐貸]] >` + `> 整理出 >` + `> [[貸款爭議]]
|
||
### 出處
|
||
- ` + "`../小果被AFTEE詐貸.pdf`" + ` >` + `> 提及 >` + `> 小果被AFTEE詐貸
|
||
`
|
||
|
||
// TestRepairCardSourceBlocks 驗既有資料的處置:舊形出處就地改寫+原樣重推。
|
||
// 這是票 `inkstone/Arcrun#167` 驗收條件「不能只修新的」的機械閘。
|
||
func TestRepairCardSourceBlocks(t *testing.T) {
|
||
root := t.TempDir()
|
||
cardRel := "子資料夾/.wiki/小果被AFTEE詐貸.md"
|
||
if err := os.MkdirAll(filepath.Join(root, "子資料夾", ".wiki"), 0o755); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
if err := os.WriteFile(filepath.Join(root, filepath.FromSlash(cardRel)), []byte(legacyCard), 0o644); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
wm := &wikiManifest{Version: 1, Docs: []wikiDoc{{
|
||
Node: "子資料夾", Path: "小果被AFTEE詐貸.pdf", Status: "extracted",
|
||
Card: "小果被AFTEE詐貸", Cards: []string{cardRel},
|
||
}}}
|
||
if err := saveWikiManifest(root, wm); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
|
||
var got map[string]any
|
||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||
b, _ := io.ReadAll(r.Body)
|
||
_ = json.Unmarshal(b, &got)
|
||
w.Header().Set("Content-Type", "application/json")
|
||
_, _ = w.Write([]byte(`{"success":true}`))
|
||
}))
|
||
defer srv.Close()
|
||
|
||
cfg := &DirectConfig{
|
||
CypherURL: srv.URL, APIKey: "k", Namespace: "ns",
|
||
CardIngestWF: "rag_ingest_card",
|
||
MachineLabel: "教育部 Leo 的 Mac",
|
||
}
|
||
m := &Manifest{Root: root, Entries: map[string]*ManifestEntry{}}
|
||
|
||
res := repairCardSourceBlocks(cfg, root, m, false, false, time.Now())
|
||
if res == nil || res.Repushed != 1 {
|
||
t.Fatalf("沒有重推:%+v", res)
|
||
}
|
||
|
||
// ① 本機卡不再有內部相對路徑,且定位得到子資料夾。
|
||
fixed, err := os.ReadFile(filepath.Join(root, filepath.FromSlash(cardRel)))
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
card := string(fixed)
|
||
if strings.Contains(card, "../") {
|
||
t.Fatalf("本機卡仍帶 `../`:\n%s", card)
|
||
}
|
||
if !strings.Contains(card, "子資料夾/小果被AFTEE詐貸.pdf") {
|
||
t.Fatalf("本機卡的出處定位不到子資料夾:\n%s", card)
|
||
}
|
||
if !strings.Contains(card, "教育部 Leo 的 Mac") {
|
||
t.Fatalf("本機卡的出處沒有機器標記:\n%s", card)
|
||
}
|
||
// ② 出處以外一字不動(重萃會讓內容變樣,就地修不會)。
|
||
if !strings.Contains(card, "## 摘要\n一段摘要。") || !strings.Contains(card, "- **小果**(人物)— 當事人") {
|
||
t.Fatalf("出處以外的內容被動到了:\n%s", card)
|
||
}
|
||
|
||
// ③ 送上雲的 payload 與 direct.go 送新卡時同一組欄位,且路徑是**庫內完整路徑**。
|
||
if got["path"] != "子資料夾/小果被AFTEE詐貸.pdf" {
|
||
t.Fatalf("重推的 path 不對:%v", got["path"])
|
||
}
|
||
if got["page_name"] != "小果被AFTEE詐貸" {
|
||
t.Fatalf("重推的 page_name 不對:%v", got["page_name"])
|
||
}
|
||
if s, _ := got["card_content"].(string); strings.Contains(s, "../") {
|
||
t.Fatalf("送上雲的卡片內容仍帶 `../`:\n%s", s)
|
||
}
|
||
|
||
// ④ 修完蓋章 ⇒ 不會每輪重掃、更不會每輪重推。
|
||
if m.SourceOriginRepairedAt == 0 {
|
||
t.Fatal("修完沒蓋章,會變成每輪都跑的背景工作")
|
||
}
|
||
got = nil
|
||
if again := repairCardSourceBlocks(cfg, root, m, false, false, time.Now()); again != nil {
|
||
t.Fatalf("蓋章後又跑了一次:%+v", again)
|
||
}
|
||
if got != nil {
|
||
t.Fatal("蓋章後又重推了一次")
|
||
}
|
||
}
|
||
|
||
// TestRewriteSourceBlockLeavesNewShapeAlone:已經是新形的卡不該被再動一次
|
||
//(避免「每輪都改一點」讓使用者的檔案 mtime 無故跳動)。
|
||
func TestRewriteSourceBlockLeavesNewShapeAlone(t *testing.T) {
|
||
o := SourceOrigin{MachineLabel: "m", Library: "kb", LibraryPath: "a/b.md"}
|
||
var b strings.Builder
|
||
renderSourceLine(&b, o, "卡")
|
||
card := "## 關聯\n### 卡片關係\n" + b.String()
|
||
if hasLegacySourceLine(card) {
|
||
t.Fatalf("新形被誤判成舊形:\n%s", card)
|
||
}
|
||
if rewriteSourceBlock(card, o, "卡") != card {
|
||
t.Fatal("新形卡被重寫了")
|
||
}
|
||
}
|