- 專案骨架:Elixir + Mix escript(單檔可執行 bear),HTTP 一律 Req - 設定/憑證檔讀寫:0600、原子寫入(rename)、O_CREAT|O_EXCL 防 symlink - PAT Bearer 呼叫 /userinfo;--json 輸出;規格化退出碼 - 補齊 main 規格承諾的 BEAR_TOKEN 環境變數(優先於憑證檔、不寫入) - login 無效 PAT 退出碼 3(依 docs/commands.md §3.1);token --refresh 用法錯誤 2(§3.3) - 35 個單元測試;mix precommit(compile --warnings-as-errors + format + test)全綠 - 沿用已關閉 PR #3 的實作(feat/pat-mode-mvp 分支),文件改依 main 現行版本更新 apps 管理指令待 #5 規格與 alterminal/bear#28 API 就緒後實作。
63 lines
1.8 KiB
Elixir
63 lines
1.8 KiB
Elixir
defmodule BearCli.CredentialsTest do
|
|
use ExUnit.Case, async: true
|
|
|
|
alias BearCli.Credentials
|
|
|
|
test "save/load round-trips JSON" do
|
|
path = tmp_path()
|
|
on_exit(fn -> File.rm(path) end)
|
|
|
|
assert :ok ==
|
|
Credentials.save(
|
|
%{"issuer" => "x", "access_token" => "tok", "email" => "a@b.c"},
|
|
path
|
|
)
|
|
|
|
assert {:ok, %{"access_token" => "tok", "email" => "a@b.c"}} = Credentials.load(path)
|
|
end
|
|
|
|
test "save creates the file with 0600 permissions" do
|
|
path = tmp_path()
|
|
on_exit(fn -> File.rm(path) end)
|
|
:ok = Credentials.save(%{"access_token" => "tok"}, path)
|
|
|
|
mode = File.stat!(path).mode
|
|
assert Bitwise.band(mode, 0o777) == 0o600
|
|
end
|
|
|
|
test "save creates the parent directory" do
|
|
base = Path.join(System.tmp_dir!(), "bear_cli_nested_#{System.unique_integer([:positive])}")
|
|
path = Path.join([base, "sub", "credentials.json"])
|
|
on_exit(fn -> File.rm_rf(base) end)
|
|
|
|
:ok = Credentials.save(%{"a" => "b"}, path)
|
|
assert File.regular?(path)
|
|
end
|
|
|
|
test "load returns :error for a missing file" do
|
|
assert :error == Credentials.load("/nonexistent/credentials.json")
|
|
end
|
|
|
|
test "load returns :error for corrupt JSON" do
|
|
path = tmp_path()
|
|
on_exit(fn -> File.rm(path) end)
|
|
File.write!(path, "{not json")
|
|
|
|
assert :error == Credentials.load(path)
|
|
end
|
|
|
|
test "delete removes the file and is idempotent" do
|
|
path = tmp_path()
|
|
on_exit(fn -> File.rm(path) end)
|
|
:ok = Credentials.save(%{"a" => "b"}, path)
|
|
|
|
assert :ok == Credentials.delete(path)
|
|
assert :error == Credentials.load(path)
|
|
assert :ok == Credentials.delete(path)
|
|
end
|
|
|
|
defp tmp_path do
|
|
Path.join(System.tmp_dir!(), "bear_cli_creds_#{System.unique_integer([:positive])}.json")
|
|
end
|
|
end
|