0021c274e8
leo 08-04 實撞(Oscar 截圖):托盤顯示「🟢 新版 v0.15.6 已就緒」, 點下去重啟後**版本又是 v0.15.4**。同一套機制在 leo 機器正常。 真兇=`selfupdate.go` 寫死 `/Applications/Arcrun RAG.app`: · leo 有把 app 放進 /Applications ⇒ 剛好蓋對他正在跑的那份 ⇒ 一直正常 · Oscar 從下載資料夾直接跑 ⇒ 蓋到一個他沒在跑的路徑 · 而且 **ditto 會自動建出該目錄並回傳成功**(實測 exit 0,非報錯) ⇒ 畫面說「更新完成」、版本卻永遠是舊的=**靜默失敗** ⇒ 不是新舊 Mac 的差別,是 **app 放置位置**的差別(leo 機器實查證實)。 修法:改用 os.Executable() 往上推 .app(runningAppBundlePath), 更新**當前真的在跑的那份**——放哪都能更新,也不再無中生有 /Applications 副本。 找不到 .app 結構時誠實回錯,不猜路徑亂蓋(蓋錯比不更新更難查)。 ⚠️ 「檢查更新」這條路**保留且必須修好**——leo:「這是我解決每次都要撞 沒簽章問題的解法,不能說它無用」。本次是修它,不是繞過它。 測試:新增 t184_test.go(不得回傳寫死 /Applications/.app 推導對三種放置位置 /ditto 靜默建目錄的認知回歸);順手把 t182 的 TestAccountEngineLabel 改寫成 新判準(explicit 決定,非 config 殘留字串)。兩模組全綠。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
56 lines
2.1 KiB
Go
56 lines
2.1 KiB
Go
package main
|
||
|
||
import (
|
||
"os"
|
||
"path/filepath"
|
||
"strings"
|
||
"testing"
|
||
)
|
||
|
||
// t184:更新必須蓋在「正在跑的那個 .app」,不是寫死 /Applications。
|
||
// leo 08-04 實撞:Oscar 從下載資料夾跑 → ditto 自動建 /Applications 副本並回成功
|
||
// → 他重開仍是舊版,畫面卻說更新完成(靜默失敗)。
|
||
func TestRunningAppBundlePathNotHardcoded(t *testing.T) {
|
||
got, err := runningAppBundlePath()
|
||
// 測試執行檔不在 .app 裡 → 應誠實回錯,**不可**回傳寫死的 /Applications 路徑
|
||
if err == nil && strings.HasPrefix(got, "/Applications/") {
|
||
t.Errorf("不該回寫死的 /Applications 路徑:%q", got)
|
||
}
|
||
if err == nil && !strings.HasSuffix(got, ".app") {
|
||
t.Errorf("回傳的不是 .app:%q", got)
|
||
}
|
||
}
|
||
|
||
// 模擬真實 .app 結構:<dir>/Arcrun RAG.app/Contents/MacOS/arcrun-tray
|
||
// 驗證「往上三層」的推導正確——放在哪個目錄都要算得出來。
|
||
func TestAppBundleDerivationFromExePath(t *testing.T) {
|
||
for _, base := range []string{"/Applications", "/Users/oscar/Downloads", "/Volumes/USB"} {
|
||
exe := filepath.Join(base, "Arcrun RAG.app", "Contents", "MacOS", "arcrun-tray")
|
||
app := filepath.Dir(filepath.Dir(filepath.Dir(exe)))
|
||
want := filepath.Join(base, "Arcrun RAG.app")
|
||
if app != want {
|
||
t.Errorf("從 %s 推導錯:got %q want %q", base, app, want)
|
||
}
|
||
}
|
||
}
|
||
|
||
// ditto 對不存在的目標會自動建目錄且回成功——這正是靜默失敗的成因,留測防回歸認知。
|
||
func TestDittoCreatesMissingTargetSilently(t *testing.T) {
|
||
dir := t.TempDir()
|
||
src := filepath.Join(dir, "Fake.app", "Contents")
|
||
if err := os.MkdirAll(src, 0o755); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
if err := os.WriteFile(filepath.Join(src, "x"), []byte("hi"), 0o644); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
dst := filepath.Join(dir, "nowhere", "Fake.app")
|
||
if _, err := runCmd("ditto", filepath.Join(dir, "Fake.app"), dst); err != nil {
|
||
t.Skipf("此環境沒有 ditto:%v", err)
|
||
}
|
||
if _, err := os.Stat(dst); err != nil {
|
||
t.Fatal("前提失效:ditto 應自動建出目標")
|
||
}
|
||
t.Log("確認:ditto 蓋到不存在的路徑會成功建出 ⇒ 寫死路徑必然靜默失敗")
|
||
}
|