#!/usr/bin/env bash # 迴歸測試:scripts/isep-doctor(inkstone/ISEP#150)——全離線 # 用假的 claude 可執行檔(shell 腳本)代替真的 CLI/Desktop,走的是 doctor 真正的 subprocess 那條路。 # 真的 Claude Code 版本的實測在 scripts/test-isep-doctor-live.sh。 set -u HERE="$(cd "$(dirname "$0")" && pwd)" T=$(mktemp -d); trap 'rm -rf "$T"' EXIT pass=0; fail=0 URL=https://git.uncle6.me/inkstone/ISEP.git mkfake() { # 路徑 版本 plugin-list 輸出(原樣印出) mkdir -p "$(dirname "$1")" printf '%s' "$3" > "$1.out" cat > "$1" <&1); CODE=$?; } ok() { pass=$((pass+1)); echo "ok $1"; } bad() { fail=$((fail+1)); echo "FAIL $1 (exit=$CODE)"; printf '%s\n' "$OUT" | sed 's/^/ /'; } expect() { # 名稱 離開碼 要有的樣式(| 分隔,可空) 不准有的樣式(可空) local p miss="" [ "$CODE" = "$2" ] || miss="exit" local IFS='|' for p in $3; do printf '%s' "$OUT" | grep -q -- "$p" || miss="$miss 缺[$p]"; done if [ -n "${4:-}" ] && printf '%s' "$OUT" | grep -q -- "$4"; then miss="$miss 多了[$4]"; fi [ -z "$miss" ] && ok "$1" || { bad "$1 →$miss"; } } mkdir -p "$T/home/plugins" echo "{\"inkstone\":{\"source\":{\"source\":\"git\",\"url\":\"$URL\"}}}" > "$T/home/plugins/known_marketplaces.json" SET_PATH="{\"extraKnownMarketplaces\":{\"inkstone\":{\"source\":{\"source\":\"git\",\"url\":\"$URL\",\"path\":\"/Users/x/ISEP\"}}},\"model\":\"keep\"}" SET_CLEAN="{\"extraKnownMarketplaces\":{\"inkstone\":{\"source\":{\"source\":\"git\",\"url\":\"$URL\"}}}}" LOADED='[{"id":"isep@inkstone","version":"0.30.1","enabled":true}]' NOTFOUND='[{"id":"isep@inkstone","version":"0.30.1","enabled":true,"errors":["Marketplace inkstone not found"]}]' # ① 假陽性(c6991):設定有 path,但這個 Claude Code 自己回報載入正常 → ✅、不准點名 path echo "$SET_PATH" > "$T/home/settings.json" mkfake "$T/b/cli" 2.1.220 "$LOADED" export ISEP_DOCTOR_CLAUDE_BINS="CLI=$T/b/cli"; run expect "① 有 path 但實際載入(2.1.220 形狀)→ ✅ 不點名 path" 0 "✅ CLI 2.1.220" "path" # ② 真陽性(c6990):同一份設定,CLI 載得進、Desktop 載不進 → 1;兩邊各講各的;點名 path;給修法 mkfake "$T/b/desk" 2.1.266 "$NOTFOUND" export ISEP_DOCTOR_CLAUDE_BINS="CLI=$T/b/cli:Desktop=$T/b/desk"; run expect "② CLI 載得進、Desktop 載不進 → 1,逐一講、點名 path" 1 "✅ CLI 2.1.220|❌ Desktop 2.1.266|Marketplace inkstone not found|多了 path|^ python3 " printf '%s' "$OUT" | grep -q "CLI 與 Desktop 都一樣" && bad "② 不准再說 CLI 與 Desktop 都一樣" || ok "② 沒有把整台機器講成同一個結論" # ③ 真陰性:拿掉 path,兩邊都載入 → 0 echo "$SET_CLEAN" > "$T/home/settings.json" mkfake "$T/b/desk" 2.1.266 "$LOADED"; run expect "③ 沒有 path、兩邊都載入 → 0" 0 "✅ CLI 2.1.220|✅ Desktop 2.1.266" "❌" # ④ 別的原因失敗(設定沒有多餘欄位)→ 1,照實轉述,不編原因、不給 path 修法 mkfake "$T/b/desk" 2.1.266 '[{"id":"isep@inkstone","version":"0.30.1","enabled":true,"errors":["Plugin directory missing"]}]'; run expect "④ 其他錯誤照實轉述、不編原因" 1 "❌ Desktop|Plugin directory missing" "修法(一行" # ⑤ 沒安裝 → 1 mkfake "$T/b/desk" 2.1.266 '[]'; run expect "⑤ 沒安裝 → 1" 1 "❌ Desktop 2.1.266:isep@inkstone 沒有安裝" # ⑥ 查不了(輸出不是 JSON)+另一個正常 → 2,◐,不准講成 ❌ 或 ✅ mkfake "$T/b/desk" 2.1.266 'Error: something broke'; run expect "⑥ 一個查不了、一個正常 → 2" 2 "◐ Desktop|讀不到不等於沒載入|✅ CLI" "❌" # ⑦ 一個 Claude Code 都找不到 → 2 export ISEP_DOCTOR_CLAUDE_BINS=""; run expect "⑦ 找不到任何 Claude Code → 2" 2 "◐ 查不了" # ⑧ 修法那一行真的修得好(在假 HOME 上原封不動執行印給 leo 的那一行) echo "$SET_PATH" > "$T/home/settings.json" mkfake "$T/b/desk" 2.1.266 "$NOTFOUND" export ISEP_DOCTOR_CLAUDE_BINS="Desktop=$T/b/desk"; run fixline=$(printf '%s\n' "$OUT" | grep '^ python3 ' | sed 's/^ //') mkdir -p "$T/fake/.claude" && cp "$T/home/settings.json" "$T/fake/.claude/settings.json" HOME="$T/fake" bash -c "$fixline" if [ -n "$fixline" ] && python3 -c "import json,sys;d=json.load(open('$T/fake/.claude/settings.json'));s=d['extraKnownMarketplaces']['inkstone']['source'];sys.exit(0 if 'path' not in s and d['model']=='keep' and s['url'].endswith('ISEP.git') else 1)"; then ok "⑧ 修法一行拿掉 path、其他設定不動" else fail=$((fail+1)); echo "FAIL ⑧ 修法一行"; cat "$T/fake/.claude/settings.json"; fi # ⑧b 修完再問一次(Desktop 改回報正常)→ 0:出路走得通 cp "$T/fake/.claude/settings.json" "$T/home/settings.json"; mkfake "$T/b/desk" 2.1.266 "$LOADED"; run expect "⑧b 照修法修完再跑 → ✅" 0 "✅ Desktop" "多了 path" # ⑨ 自動尋找:Desktop 取數字上最新的那一份(2.1.99 < 2.1.266,字串排序會選錯) unset ISEP_DOCTOR_CLAUDE_BINS D="$T/h9/Library/Application Support/Claude/claude-code" mkfake "$D/2.1.99/claude.app/Contents/MacOS/claude" 2.1.99 "$NOTFOUND" mkfake "$D/2.1.266/claude.app/Contents/MacOS/claude" 2.1.266 "$LOADED" OUT=$(HOME="$T/h9" PATH="/usr/bin:/bin" ISEP_DOCTOR_CLAUDE_HOME="$T/home" /usr/bin/env python3 "$HERE/isep-doctor" 2>&1); CODE=$? expect "⑨ Desktop 取最新版本(數字排序)" 0 "✅ Desktop 2.1.266" "2.1.99" echo "pass=$pass fail=$fail"; [ "$fail" = 0 ]