claude: a Claude account's usage resets are read in the zone /usage names on Windows too, and the provider tests pass whole on Windows (goal: 插件订阅 provider 跟内置的所有逻辑都要一模一样, run on Windows and Linux) — Windows has no time zone database, so "resets Oct 1 at 3:30pm (Asia/Shanghai)" was read in the machine's own zone, hours off for anyone not in that zone; magpie now carries the database (time/tzdata). The provider tests set HOME but not USERPROFILE, which Windows takes the home from, so on Windows they read the test box's own agent sign-ins (Gemini models in a list, an extra provider, a Cursor version); every test home sets both now. Tests whose fake CLI is a shell script (Claude Code's auth status, codex --version, macOS's security) skip on Windows, as the fake devin did, and file mode bits go unchecked there. TestParseClaudeUsage fails on Windows without the change. On Windows and on Linux (WSL) the provider package passes whole, three times on Windows (15 failed before), the plugin package and the move/plugin/Grok/Devin/usage tests five times over on Linux. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.

This commit is contained in:
yetone committed 2026-10-01 13:51:24 +08:00
1 parent 5fe0906907
commit a2714f7506
49 files changed
+90 -6

No files matched your search

+1
View File
@@ -462,6 +462,7 @@ func TestCopilotSignAndModels(t *testing.T) {
// Logging out of Claude Code can leave its credentials behind; what the CLI
// says wins, so a signed-out account is not a provider.
func TestClaudeSignedOut(t *testing.T) {
shellFakes(t)
home := claudeHome(t)
claudeSignIn(t, home, time.Now().Add(time.Hour))
status := `{"loggedIn": true, "email": "me@example.com", "subscriptionType": "max"}`
@@ -92,6 +92,7 @@ func TestCollapseAntigravityModels(t *testing.T) {
func TestAntigravityLegacyPicks(t *testing.T) {
home := t.TempDir()
t.Setenv("HOME", home)
t.Setenv("USERPROFILE", home)
t.Setenv("XDG_CONFIG_HOME", filepath.Join(home, ".config"))
t.Setenv("XDG_CACHE_HOME", filepath.Join(home, ".cache"))
if err := catalog.SaveLive("antigravity", "", antigravityListed); err != nil {
+2
View File
@@ -105,6 +105,7 @@ func TestKeyBalances(t *testing.T) {
isolate(t)
h := t.TempDir()
t.Setenv("HOME", h)
t.Setenv("USERPROFILE", h)
t.Setenv("XDG_CONFIG_HOME", filepath.Join(h, ".config"))
t.Setenv("XDG_CACHE_HOME", filepath.Join(h, ".cache"))
t.Setenv("PATH", h)
@@ -320,6 +321,7 @@ func TestBalanceURLNamesTheKey(t *testing.T) {
isolate(t)
h := t.TempDir()
t.Setenv("HOME", h)
t.Setenv("USERPROFILE", h)
t.Setenv("XDG_CONFIG_HOME", filepath.Join(h, ".config"))
t.Setenv("XDG_CACHE_HOME", filepath.Join(h, ".cache"))
t.Setenv("PATH", h)
+1
View File
@@ -9,6 +9,7 @@ import (
func TestBedrockPreset(t *testing.T) {
t.Setenv("HOME", t.TempDir())
t.Setenv("USERPROFILE", t.TempDir())
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
t.Setenv("XDG_CACHE_HOME", t.TempDir())
p, err := FromPreset("bedrock")
+2
View File
@@ -13,6 +13,7 @@ import (
func TestSeveralCatalogs(t *testing.T) {
isolate(t)
t.Setenv("HOME", t.TempDir())
t.Setenv("USERPROFILE", t.TempDir())
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
cache := t.TempDir()
t.Setenv("XDG_CACHE_HOME", cache)
@@ -53,6 +54,7 @@ func TestSeveralCatalogs(t *testing.T) {
func TestOpenCodeModelAPIs(t *testing.T) {
isolate(t)
t.Setenv("HOME", t.TempDir())
t.Setenv("USERPROFILE", t.TempDir())
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
cache := t.TempDir()
t.Setenv("XDG_CACHE_HOME", cache)
+3
View File
@@ -12,9 +12,11 @@ import (
// its saved login is, so it is the one Active and not also served beside
// itself; the env magpie runs in is not handed to the CLI (#177).
func TestClaudeAccountNamedAsItsLogin(t *testing.T) {
shellFakes(t)
isolate(t)
home := t.TempDir()
t.Setenv("HOME", home)
t.Setenv("USERPROFILE", home)
t.Setenv("CLAUDE_CONFIG_DIR", "")
t.Setenv("XDG_CONFIG_HOME", filepath.Join(home, ".config"))
t.Setenv("ANTHROPIC_AUTH_TOKEN", "magpie")
@@ -55,6 +57,7 @@ func TestClaudeAccountNamedAsItsLogin(t *testing.T) {
// a second look at Claude Code's sign-in serves the last answer at once and
// asks the CLI again behind it (#123)
func TestClaudeIdentityServedWhileAsked(t *testing.T) {
shellFakes(t)
dir := t.TempDir()
exe, who := filepath.Join(dir, "claude"), filepath.Join(dir, "who")
os.WriteFile(who, []byte("a@example.com"), 0o600)
+3
View File
@@ -12,6 +12,9 @@ import (
"strconv"
"strings"
"time"
// the zone /usage names its resets in: Windows has no zone database,
// and without one a reset was read in the machine's own zone
_ "time/tzdata"
)
// claudeCLIUsage runs Claude Code's /usage for the account it is signed in
+1
View File
@@ -96,6 +96,7 @@ func TestFindCodexDaemon(t *testing.T) {
func fakeDaemon(t *testing.T) *int {
t.Helper()
t.Setenv("HOME", t.TempDir())
t.Setenv("USERPROFILE", t.TempDir())
pid := new(int)
old, oldHome := listProcesses, processCodexHome
t.Cleanup(func() {
+4
View File
@@ -50,8 +50,10 @@ func TestCodexModelsOfTheAccount(t *testing.T) {
// The models list is asked for with the newest Codex known: the CLI
// installed over the version its cache was written with.
func TestCodexVersion(t *testing.T) {
shellFakes(t)
home := t.TempDir()
t.Setenv("HOME", home)
t.Setenv("USERPROFILE", home)
writeFile(t, filepath.Join(home, ".codex", "models_cache.json"), map[string]any{"client_version": "0.160.0"})
exe := filepath.Join(t.TempDir(), "codex")
if err := os.WriteFile(exe, []byte("#!/bin/sh\necho codex-cli 0.161.1\n"), 0o755); err != nil {
@@ -86,6 +88,7 @@ func TestCodexVersion(t *testing.T) {
// Codex's requests count, and never an older version.
func TestCodexVersionSeen(t *testing.T) {
t.Setenv("HOME", t.TempDir())
t.Setenv("USERPROFILE", t.TempDir())
t.Setenv("CODEX_HOME", "")
old := codexExecutable
codexExecutable = func() string { return "" }
@@ -150,6 +153,7 @@ func TestCodexExecutableOffPath(t *testing.T) {
t.Run(name, func(t *testing.T) {
home := t.TempDir()
t.Setenv("HOME", home)
t.Setenv("USERPROFILE", home)
t.Setenv("PATH", "/usr/bin:/bin")
os.WriteFile(filepath.Join(home, ".npmrc"), []byte("registry=https://registry.npmjs.org/\nprefix = ~/custom-npm\n"), 0o644)
exe := filepath.Join(home, dir, "codex")
+1
View File
@@ -8,6 +8,7 @@ import (
func TestContextSetByUser(t *testing.T) {
home := t.TempDir()
t.Setenv("HOME", home)
t.Setenv("USERPROFILE", home)
// set, not empty: a group saved lists what Devin's CLI reports, and
// Devin given an empty one writes its config into the working directory
t.Setenv("XDG_CONFIG_HOME", filepath.Join(home, ".config"))
+1
View File
@@ -14,6 +14,7 @@ func TestAddCopy(t *testing.T) {
isolate(t)
home := t.TempDir()
t.Setenv("HOME", home)
t.Setenv("USERPROFILE", home)
t.Setenv("XDG_CONFIG_HOME", filepath.Join(home, ".config"))
t.Setenv("XDG_CACHE_HOME", filepath.Join(home, ".cache"))
src := Provider{ID: "relay", Name: "Relay", Chat: "https://api.relay.example/v1", Key: "sk-1", KeyName: "main",
+1
View File
@@ -49,6 +49,7 @@ func TestCursorNamesWithoutCapacity(t *testing.T) {
func TestCursorAvailableNames(t *testing.T) {
home := t.TempDir()
t.Setenv("HOME", home)
t.Setenv("USERPROFILE", home)
t.Setenv("XDG_CONFIG_HOME", filepath.Join(home, ".config"))
t.Setenv("XDG_CACHE_HOME", filepath.Join(home, ".cache"))
was := cursorStatus
+1
View File
@@ -76,6 +76,7 @@ func TestAskCursorStatus(t *testing.T) {
}
home := t.TempDir()
t.Setenv("HOME", home)
t.Setenv("USERPROFILE", home)
exe := filepath.Join(home, "cursor-agent")
wasExe, wasOut := CursorExecutable, cursorSignedOut
t.Cleanup(func() { CursorExecutable, cursorSignedOut = wasExe, wasOut })
+3
View File
@@ -94,6 +94,7 @@ func TestCollapseCursorModels(t *testing.T) {
func TestCursorLegacyPicks(t *testing.T) {
home := t.TempDir()
t.Setenv("HOME", home)
t.Setenv("USERPROFILE", home)
t.Setenv("XDG_CONFIG_HOME", filepath.Join(home, ".config"))
t.Setenv("XDG_CACHE_HOME", filepath.Join(home, ".cache"))
was := cursorStatus
@@ -161,6 +162,7 @@ func TestCursorContext(t *testing.T) {
func TestCursorClientVersion(t *testing.T) {
home := t.TempDir()
t.Setenv("HOME", home)
t.Setenv("USERPROFILE", home)
exe := CursorExecutable
defer func() { CursorExecutable = exe }()
CursorExecutable = func() string { return "" }
@@ -204,6 +206,7 @@ func TestTokenExpiry(t *testing.T) {
func TestCursorPluginContext(t *testing.T) {
home := t.TempDir()
t.Setenv("HOME", home)
t.Setenv("USERPROFILE", home)
t.Setenv("XDG_CONFIG_HOME", filepath.Join(home, ".config"))
t.Setenv("XDG_CACHE_HOME", filepath.Join(home, ".cache"))
os.MkdirAll(filepath.Dir(catalog.CachePath()), 0o755)
+8
View File
@@ -17,6 +17,7 @@ import (
// effort is picked only by it.
func TestDecider(t *testing.T) {
t.Setenv("HOME", t.TempDir())
t.Setenv("USERPROFILE", t.TempDir())
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
if err := Save(Provider{ID: "a", Name: "a", Key: "k", Chat: "http://127.0.0.1:1/v1", Models: []string{"m"}}); err != nil {
t.Fatal(err)
@@ -79,6 +80,7 @@ func TestAPIErrorDetail(t *testing.T) {
// as each names it, and a key checked by the gateway's own free call.
func TestDecideGateways(t *testing.T) {
t.Setenv("HOME", t.TempDir())
t.Setenv("USERPROFILE", t.TempDir())
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
t.Setenv("XDG_CACHE_HOME", t.TempDir())
for id, want := range map[string][2]string{"typesafe": {ViaSystemOne, "jev-latest"}, "vercel-jev": {ViaVercel, "typesafe-ai/jev"}, "cloudflare-jev": {ViaCloudflare, "typesafe/jev"}} {
@@ -166,6 +168,7 @@ func TestFetchDecideOpenAIJevIDs(t *testing.T) {
isolate(t)
h := t.TempDir()
t.Setenv("HOME", h)
t.Setenv("USERPROFILE", h)
t.Setenv("XDG_CONFIG_HOME", filepath.Join(h, ".config"))
t.Setenv("XDG_CACHE_HOME", filepath.Join(h, ".cache"))
var auth string
@@ -240,6 +243,7 @@ func TestFetchDecideOpenAIJevIDs(t *testing.T) {
func TestRouteDecider(t *testing.T) {
h := t.TempDir()
t.Setenv("HOME", h)
t.Setenv("USERPROFILE", h)
t.Setenv("XDG_CONFIG_HOME", filepath.Join(h, ".config"))
t.Setenv("XDG_CACHE_HOME", filepath.Join(h, ".cache"))
if _, _, err := RouteDecider(""); err == nil || !strings.Contains(err.Error(), "names no model") {
@@ -313,6 +317,7 @@ func TestRouteDecider(t *testing.T) {
func TestRouteDeciderVercelAlias(t *testing.T) {
h := t.TempDir()
t.Setenv("HOME", h)
t.Setenv("USERPROFILE", h)
t.Setenv("XDG_CONFIG_HOME", filepath.Join(h, ".config"))
t.Setenv("XDG_CACHE_HOME", filepath.Join(h, ".cache"))
if err := Save(Provider{ID: "vercel-jev", Name: "Vercel", Key: "k", Decide: "https://ai-gateway.vercel.sh/typesafe"}); err != nil {
@@ -342,6 +347,7 @@ func TestRouteDeciderVercelAlias(t *testing.T) {
func TestRouteDeciderCloudflareAlias(t *testing.T) {
h := t.TempDir()
t.Setenv("HOME", h)
t.Setenv("USERPROFILE", h)
t.Setenv("XDG_CONFIG_HOME", filepath.Join(h, ".config"))
t.Setenv("XDG_CACHE_HOME", filepath.Join(h, ".cache"))
if err := Save(Provider{ID: "cloudflare-jev", Name: "CF", Key: "k", Decide: "https://api.cloudflare.com/client/v4"}); err != nil {
@@ -361,6 +367,7 @@ func TestRouteDeciderCloudflareAlias(t *testing.T) {
func TestRouteDeciderUnfetchedAmbiguous(t *testing.T) {
h := t.TempDir()
t.Setenv("HOME", h)
t.Setenv("USERPROFILE", h)
t.Setenv("XDG_CONFIG_HOME", filepath.Join(h, ".config"))
t.Setenv("XDG_CACHE_HOME", filepath.Join(h, ".cache"))
for _, p := range []Provider{
@@ -378,6 +385,7 @@ func TestRouteDeciderUnfetchedAmbiguous(t *testing.T) {
// two System One providers, catalogs not fetched, both default to jev-latest
h2 := t.TempDir()
t.Setenv("HOME", h2)
t.Setenv("USERPROFILE", h2)
t.Setenv("XDG_CONFIG_HOME", filepath.Join(h2, ".config"))
t.Setenv("XDG_CACHE_HOME", filepath.Join(h2, ".cache"))
for _, p := range []Provider{
+1
View File
@@ -119,6 +119,7 @@ func TestDevinVariantIn(t *testing.T) {
func TestDevinEfforts(t *testing.T) {
home := t.TempDir()
t.Setenv("HOME", home)
t.Setenv("USERPROFILE", home)
t.Setenv("XDG_CONFIG_HOME", filepath.Join(home, ".config"))
t.Setenv("XDG_CACHE_HOME", filepath.Join(home, ".cache"))
devinFamiliesCached(devinListed)
+10 -2
View File
@@ -147,6 +147,7 @@ func TestDevinCredentialsPath(t *testing.T) {
}
home := t.TempDir()
t.Setenv("HOME", home)
t.Setenv("USERPROFILE", home)
t.Setenv("XDG_DATA_HOME", filepath.Join(home, "data"))
got := DevinCredentialsPath()
if got != filepath.Join(home, "data", "devin", "credentials.toml") {
@@ -366,11 +367,18 @@ const devinUnreachable = `printf '%s\n' 'Logged in (via Devin).' '' 'User / team
// the CLI and the identity back when it ends: an ask that couldn't tell now
// leaves the last account served, so a test after this one must not find
// either.
func fakeDevin(t *testing.T, exe string) {
// shellFakes skips a test whose fake CLI is a shell script, which Windows
// can't run.
func shellFakes(t *testing.T) {
t.Helper()
if runtime.GOOS == "windows" {
t.Skip("the fake devin is a shell script")
t.Skip("the fake CLI is a shell script")
}
}
func fakeDevin(t *testing.T, exe string) {
t.Helper()
shellFakes(t)
old := DevinExecutable
DevinExecutable = func() string { return exe }
t.Cleanup(func() {
+1
View File
@@ -37,6 +37,7 @@ func TestFaviconSites(t *testing.T) {
func TestFavicon(t *testing.T) {
home := t.TempDir()
t.Setenv("HOME", home)
t.Setenv("USERPROFILE", home)
t.Setenv("XDG_CONFIG_HOME", filepath.Join(home, ".config"))
png := []byte("\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR")
+2
View File
@@ -16,6 +16,7 @@ func TestFetchAddsMissingV1(t *testing.T) {
isolate(t)
h := t.TempDir()
t.Setenv("HOME", h)
t.Setenv("USERPROFILE", h)
t.Setenv("XDG_CONFIG_HOME", filepath.Join(h, ".config"))
t.Setenv("XDG_CACHE_HOME", filepath.Join(h, ".cache"))
t.Setenv("PATH", h)
@@ -74,6 +75,7 @@ func TestArkBaseKeepsItsPath(t *testing.T) {
isolate(t)
h := t.TempDir()
t.Setenv("HOME", h)
t.Setenv("USERPROFILE", h)
t.Setenv("XDG_CONFIG_HOME", filepath.Join(h, ".config"))
t.Setenv("XDG_CACHE_HOME", filepath.Join(h, ".cache"))
t.Setenv("PATH", h)
+1
View File
@@ -13,6 +13,7 @@ import (
func TestGrokEffortListPrice(t *testing.T) {
home := t.TempDir()
t.Setenv("HOME", home)
t.Setenv("USERPROFILE", home)
t.Setenv("XDG_CONFIG_HOME", filepath.Join(home, ".config"))
t.Setenv("XDG_CACHE_HOME", filepath.Join(home, ".cache"))
os.MkdirAll(filepath.Dir(catalog.CachePath()), 0o755)
+2
View File
@@ -36,6 +36,7 @@ func TestAutoGroupsSameModel(t *testing.T) {
// the one that answers.
func TestGroupImages(t *testing.T) {
t.Setenv("HOME", t.TempDir())
t.Setenv("USERPROFILE", t.TempDir())
t.Setenv("XDG_CONFIG_HOME", "")
e := func(p, m string, images bool) Entry {
return Entry{ID: p + "/" + m, Model: m, Name: m, Provider: Provider{ID: p}, Images: images}
@@ -55,6 +56,7 @@ func TestGroupImages(t *testing.T) {
func TestGroupImagesKeepUnknownMemberUnknown(t *testing.T) {
t.Setenv("HOME", t.TempDir())
t.Setenv("USERPROFILE", t.TempDir())
t.Setenv("XDG_CONFIG_HOME", "")
yes := true
entries := []Entry{
+1
View File
@@ -12,6 +12,7 @@ import (
func effortHome(t *testing.T) {
t.Helper()
t.Setenv("HOME", t.TempDir())
t.Setenv("USERPROFILE", t.TempDir())
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
t.Setenv("XDG_CACHE_HOME", t.TempDir())
for _, p := range []Provider{
+1
View File
@@ -10,6 +10,7 @@ import (
// has one anyway.
func TestGroupsInGroups(t *testing.T) {
t.Setenv("HOME", t.TempDir())
t.Setenv("USERPROFILE", t.TempDir())
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
for _, id := range []string{"a", "b", "c"} {
if err := Save(Provider{ID: id, Name: id, Key: "k", Chat: "http://127.0.0.1:1/v1", Models: []string{"m", "x"}}); err != nil {
+1
View File
@@ -10,6 +10,7 @@ import (
// name it by the new one.
func TestRenameGroup(t *testing.T) {
t.Setenv("HOME", t.TempDir())
t.Setenv("USERPROFILE", t.TempDir())
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
for _, id := range []string{"a", "b"} {
if err := Save(Provider{ID: id, Name: id, Key: "k", Chat: "http://127.0.0.1:1/v1", Models: []string{"gpt-6-astra", "x"}}); err != nil {
+2
View File
@@ -228,6 +228,7 @@ func TestRuledEntry(t *testing.T) {
// doesn't have is refused.
func TestSaveGroupRules(t *testing.T) {
t.Setenv("HOME", t.TempDir())
t.Setenv("USERPROFILE", t.TempDir())
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
for _, id := range []string{"a", "b"} {
if err := Save(Provider{ID: id, Name: id, Key: "k", Chat: "http://127.0.0.1:1/v1", Models: []string{"m", "big"}}); err != nil {
@@ -251,6 +252,7 @@ func TestSaveGroupRules(t *testing.T) {
// another group, never itself. Without intents it keeps none.
func TestSaveGroupClassifier(t *testing.T) {
t.Setenv("HOME", t.TempDir())
t.Setenv("USERPROFILE", t.TempDir())
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
for _, id := range []string{"a", "b"} {
if err := Save(Provider{ID: id, Name: id, Key: "k", Chat: "http://127.0.0.1:1/v1", Models: []string{"m", "big"}}); err != nil {
+1
View File
@@ -21,6 +21,7 @@ func ids(es []Entry) []string {
func TestHiddenModels(t *testing.T) {
isolate(t)
t.Setenv("HOME", t.TempDir())
t.Setenv("USERPROFILE", t.TempDir())
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
t.Setenv("XDG_CACHE_HOME", t.TempDir())
for _, id := range []string{"relay", "other"} {
+2
View File
@@ -18,6 +18,7 @@ import (
func TestStoreIcon(t *testing.T) {
home := t.TempDir()
t.Setenv("HOME", home)
t.Setenv("USERPROFILE", home)
t.Setenv("XDG_CONFIG_HOME", filepath.Join(home, ".config"))
png := []byte("\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR")
@@ -55,6 +56,7 @@ func TestStoreIcon(t *testing.T) {
func TestFetchIcon(t *testing.T) {
home := t.TempDir()
t.Setenv("HOME", home)
t.Setenv("USERPROFILE", home)
t.Setenv("XDG_CONFIG_HOME", filepath.Join(home, ".config"))
png := []byte("\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR")
+1 -1
View File
@@ -86,7 +86,7 @@ func TestSignInInstallFails(t *testing.T) {
t.Fatal(err)
}
st = waitPast(t, st.ID, "installing")
if st.State != "failed" || !strings.Contains(st.Error, "Error: Failed to download") || !strings.Contains(st.Error, "install.") {
if st.State != "failed" || !strings.Contains(st.Error, "Error: Failed to download") || !strings.Contains(st.Error, "install it yourself") {
t.Fatalf("state %+v", st)
}
}
+1
View File
@@ -18,6 +18,7 @@ func TestKeyQuotasKeepLast(t *testing.T) {
isolate(t)
h := t.TempDir()
t.Setenv("HOME", h)
t.Setenv("USERPROFILE", h)
t.Setenv("XDG_CONFIG_HOME", filepath.Join(h, ".config"))
t.Setenv("XDG_CACHE_HOME", filepath.Join(h, ".cache"))
t.Setenv("PATH", h)
+1
View File
@@ -19,6 +19,7 @@ func kiroSandbox(t *testing.T) string {
t.Helper()
home := t.TempDir()
t.Setenv("HOME", home)
t.Setenv("USERPROFILE", home)
t.Setenv("XDG_CONFIG_HOME", filepath.Join(home, ".config"))
t.Setenv("XDG_CACHE_HOME", filepath.Join(home, ".cache"))
db, ide, exe, ask := kiroCLIDB, kiroIDEDir, KiroExecutable, askKiroIdentity
+1
View File
@@ -15,6 +15,7 @@ func limitsHome(t *testing.T) {
t.Helper()
home := t.TempDir()
t.Setenv("HOME", home)
t.Setenv("USERPROFILE", home)
t.Setenv("XDG_CONFIG_HOME", filepath.Join(home, ".config"))
t.Setenv("XDG_CACHE_HOME", filepath.Join(home, ".cache"))
catalog.Reset()
+2 -1
View File
@@ -4,6 +4,7 @@ import (
"encoding/json"
"os"
"path/filepath"
"runtime"
"strings"
"testing"
"time"
@@ -42,7 +43,7 @@ func TestCodexLogins(t *testing.T) {
if strings.Join(users, ",") != "me@example.com,work@example.com" || active != "work@example.com" {
t.Fatalf("logins %v, active %q", users, active)
}
if fi, err := os.Stat(loginsPath()); err != nil || fi.Mode().Perm() != 0o600 {
if fi, err := os.Stat(loginsPath()); err != nil || runtime.GOOS != "windows" && fi.Mode().Perm() != 0o600 {
t.Fatalf("logins.json mode: %v %v", fi, err)
}
// the agent refreshes the active login in place; a switch keeps that
+1
View File
@@ -33,6 +33,7 @@ func makerHome(t *testing.T) {
t.Helper()
home := t.TempDir()
t.Setenv("HOME", home)
t.Setenv("USERPROFILE", home)
t.Setenv("XDG_CONFIG_HOME", filepath.Join(home, ".config"))
t.Setenv("XDG_CACHE_HOME", filepath.Join(home, ".cache"))
if err := os.MkdirAll(filepath.Dir(catalog.CachePath()), 0o755); err != nil {
+1
View File
@@ -24,6 +24,7 @@ func prefsHome(t *testing.T) {
t.Helper()
home := t.TempDir()
t.Setenv("HOME", home)
t.Setenv("USERPROFILE", home)
t.Setenv("XDG_CONFIG_HOME", filepath.Join(home, ".config"))
t.Setenv("XDG_CACHE_HOME", filepath.Join(home, ".cache"))
t.Setenv("CLAUDE_CONFIG_DIR", filepath.Join(home, ".claude"))
+3
View File
@@ -14,6 +14,7 @@ import (
func TestExplicitTextOnlyBeatsCrossProviderImageGuess(t *testing.T) {
home := t.TempDir()
t.Setenv("HOME", home)
t.Setenv("USERPROFILE", home)
t.Setenv("XDG_CONFIG_HOME", filepath.Join(home, ".config"))
t.Setenv("XDG_CACHE_HOME", filepath.Join(home, ".cache"))
if err := os.MkdirAll(filepath.Dir(catalog.CachePath()), 0o755); err != nil {
@@ -114,6 +115,7 @@ func TestOffKeyIsNotFetched(t *testing.T) {
isolate(t)
h := t.TempDir()
t.Setenv("HOME", h)
t.Setenv("USERPROFILE", h)
t.Setenv("XDG_CONFIG_HOME", filepath.Join(h, ".config"))
t.Setenv("XDG_CACHE_HOME", filepath.Join(h, ".cache"))
t.Setenv("PATH", h)
@@ -199,6 +201,7 @@ func modelNamed(ms []catalog.Model, id string) (catalog.Model, bool) {
func TestRejectsTemperatureFromFetchedList(t *testing.T) {
home := t.TempDir()
t.Setenv("HOME", home)
t.Setenv("USERPROFILE", home)
t.Setenv("XDG_CACHE_HOME", home)
no, yes := false, true
+1
View File
@@ -15,6 +15,7 @@ func TestFetchFromModelsURL(t *testing.T) {
isolate(t)
h := t.TempDir()
t.Setenv("HOME", h)
t.Setenv("USERPROFILE", h)
t.Setenv("XDG_CONFIG_HOME", filepath.Join(h, ".config"))
t.Setenv("XDG_CACHE_HOME", filepath.Join(h, ".cache"))
t.Setenv("PATH", h)
+1
View File
@@ -12,6 +12,7 @@ import (
func TestNative(t *testing.T) {
home := t.TempDir()
t.Setenv("HOME", home)
t.Setenv("USERPROFILE", home)
t.Setenv("XDG_CONFIG_HOME", filepath.Join(home, ".config"))
t.Setenv("XDG_CACHE_HOME", filepath.Join(home, ".cache"))
catalog.Reset()
+1
View File
@@ -9,6 +9,7 @@ import (
// off: an account's too, which keeps only the user's settings.
func TestProviderOffKept(t *testing.T) {
t.Setenv("HOME", t.TempDir())
t.Setenv("USERPROFILE", t.TempDir())
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
t.Setenv("XDG_CACHE_HOME", t.TempDir())
if err := Save(Provider{ID: "relay", Name: "Relay", Key: "sk-1", Chat: "https://relay.example.com/v1", Models: []string{"m"}}); err != nil {
+1
View File
@@ -217,6 +217,7 @@ func TestPlanQuotas(t *testing.T) {
isolate(t)
h := t.TempDir()
t.Setenv("HOME", h)
t.Setenv("USERPROFILE", h)
t.Setenv("XDG_CONFIG_HOME", filepath.Join(h, ".config"))
t.Setenv("XDG_CACHE_HOME", filepath.Join(h, ".cache"))
t.Setenv("PATH", h)
+1
View File
@@ -21,6 +21,7 @@ import (
func TestPluginOwnIcon(t *testing.T) {
home := t.TempDir()
t.Setenv("HOME", home)
t.Setenv("USERPROFILE", home)
t.Setenv("XDG_CONFIG_HOME", filepath.Join(home, ".config"))
t.Setenv("XDG_CACHE_HOME", filepath.Join(home, ".cache"))
t.Setenv("MAGPIE_PLUGIN_MARKET", "off")
+1
View File
@@ -16,6 +16,7 @@ func priceHome(t *testing.T) {
t.Helper()
home := t.TempDir()
t.Setenv("HOME", home)
t.Setenv("USERPROFILE", home)
t.Setenv("XDG_CONFIG_HOME", filepath.Join(home, ".config"))
t.Setenv("XDG_CACHE_HOME", filepath.Join(home, ".cache"))
catalog.Reset()
+2
View File
@@ -37,6 +37,7 @@ func TestAddNameWithoutLatin(t *testing.T) {
isolate(t)
home := t.TempDir()
t.Setenv("HOME", home)
t.Setenv("USERPROFILE", home)
t.Setenv("XDG_CONFIG_HOME", filepath.Join(home, ".config"))
t.Setenv("XDG_CACHE_HOME", filepath.Join(home, ".cache"))
for _, c := range []struct{ name, url, key, want string }{
@@ -62,6 +63,7 @@ func TestAddSecondOfPreset(t *testing.T) {
isolate(t)
home := t.TempDir()
t.Setenv("HOME", home)
t.Setenv("USERPROFILE", home)
t.Setenv("XDG_CONFIG_HOME", filepath.Join(home, ".config"))
t.Setenv("XDG_CACHE_HOME", filepath.Join(home, ".cache"))
add := func(ws string) string {
+1
View File
@@ -12,6 +12,7 @@ import (
func TestRename(t *testing.T) {
isolate(t)
t.Setenv("HOME", t.TempDir())
t.Setenv("USERPROFILE", t.TempDir())
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
t.Setenv("XDG_CACHE_HOME", t.TempDir())
for _, id := range []string{"relay", "other"} {
+3
View File
@@ -14,6 +14,7 @@ func TestSavedButSignedOut(t *testing.T) {
isolate(t)
home := t.TempDir()
t.Setenv("HOME", home)
t.Setenv("USERPROFILE", home)
t.Setenv("XDG_CONFIG_HOME", filepath.Join(home, ".config"))
t.Setenv("CLAUDE_CONFIG_DIR", "")
if err := writeLogins([]savedLogin{
@@ -65,6 +66,7 @@ func TestSavedButSignedOutClaudeSaysWhy(t *testing.T) {
if w := why(); !strings.Contains(w, "nothing at "+filepath.Join(home, ".claude", ".credentials.json")) {
t.Fatalf("no credentials: %q", w)
}
shellFakes(t)
claudeSignIn(t, home, time.Now().Add(time.Hour))
exe := filepath.Join(home, "claude")
os.WriteFile(exe, []byte("#!/bin/sh\necho '{\"loggedIn\": false}'\n"), 0o755)
@@ -116,6 +118,7 @@ func TestSavedButSignedOutCanBeRemoved(t *testing.T) {
// under its account: another item for the same service (one an earlier
// sign-in left) that comes first by service alone isn't taken for it.
func TestClaudeKeychainReadsItsAccount(t *testing.T) {
shellFakes(t)
home := claudeHome(t)
t.Setenv("CLAUDE_CONFIG_DIR", "")
t.Setenv("USER", "tester")
+1
View File
@@ -14,6 +14,7 @@ import (
// through magpie then is the account Claude Code uses, not one kept beside a
// stale one, and it shows up as a provider (#31).
func TestClaudeSignInOverStaleCredentials(t *testing.T) {
shellFakes(t)
home := claudeHome(t)
fake := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch r.URL.Path {
+2 -1
View File
@@ -6,6 +6,7 @@ import (
"net/http"
"net/http/httptest"
"os"
"runtime"
"strings"
"sync/atomic"
"testing"
@@ -129,7 +130,7 @@ func TestStepFunSession(t *testing.T) {
if err := SaveStepFunSession(ctx, "ai", acc, ref, "web-1"); err != nil {
t.Fatal(err)
}
if fi, err := os.Stat(stepfunPath()); err != nil || fi.Mode().Perm() != 0o600 {
if fi, err := os.Stat(stepfunPath()); err != nil || runtime.GOOS != "windows" && fi.Mode().Perm() != 0o600 {
t.Fatalf("session file: %v %v", fi, err)
}
p := Provider{ID: "stepfun", Name: "StepFun", Icon: "stepfun-color", Chat: "https://api.stepfun.ai/step_plan/v1"}
+2 -1
View File
@@ -3,6 +3,7 @@ package provider
import (
"os"
"path/filepath"
"runtime"
"testing"
)
@@ -31,7 +32,7 @@ func TestPrivateWritesKeepSymlink(t *testing.T) {
if string(b) != `{"a":1}` {
t.Errorf("%s: target %q", name, b)
}
if st, _ := os.Stat(target); st.Mode().Perm() != 0o600 {
if st, _ := os.Stat(target); runtime.GOOS != "windows" && st.Mode().Perm() != 0o600 {
t.Errorf("%s: mode %v", name, st.Mode().Perm())
}
}
+3
View File
@@ -16,6 +16,7 @@ import (
func TestTestUsesEachEndpointsKey(t *testing.T) {
home := t.TempDir()
t.Setenv("HOME", home)
t.Setenv("USERPROFILE", home)
t.Setenv("XDG_CONFIG_HOME", filepath.Join(home, ".config"))
t.Setenv("XDG_CACHE_HOME", filepath.Join(home, ".cache"))
seen := map[string]string{} // path → key and model it got
@@ -66,6 +67,7 @@ func TestTestUsesEachEndpointsKey(t *testing.T) {
func TestTestModels(t *testing.T) {
home := t.TempDir()
t.Setenv("HOME", home)
t.Setenv("USERPROFILE", home)
t.Setenv("XDG_CONFIG_HOME", filepath.Join(home, ".config"))
t.Setenv("XDG_CACHE_HOME", filepath.Join(home, ".cache"))
var mu sync.Mutex
@@ -114,6 +116,7 @@ func TestTestModels(t *testing.T) {
func TestTestModelsDraws(t *testing.T) {
home := t.TempDir()
t.Setenv("HOME", home)
t.Setenv("USERPROFILE", home)
t.Setenv("XDG_CONFIG_HOME", filepath.Join(home, ".config"))
t.Setenv("XDG_CACHE_HOME", filepath.Join(home, ".cache"))
var mu sync.Mutex
+1
View File
@@ -18,6 +18,7 @@ func TestZhipuKeyTeamFields(t *testing.T) {
isolate(t)
h := t.TempDir()
t.Setenv("HOME", h)
t.Setenv("USERPROFILE", h)
t.Setenv("XDG_CONFIG_HOME", filepath.Join(h, ".config"))
t.Setenv("XDG_CACHE_HOME", filepath.Join(h, ".cache"))
t.Setenv("PATH", h)