package service import ( "testing" "time" "github.com/Wei-Shaw/sub2api/internal/pkg/antigravity" ) func TestAccountHasUsableCredits(t *testing.T) { cases := []struct { name string acct *Account want bool }{ {name: "nil 账号_false", acct: nil, want: false}, {name: "Extra 为空_false(保守策略)", acct: &Account{}, want: false}, { name: "余额 0_false", acct: &Account{Extra: map[string]any{ extraKeyCreditsBalance: 0.0, extraKeyCreditsCheckedAt: time.Now().UTC().Format(time.RFC3339), }}, want: false, }, { name: "余额 > 0_无耗尽标记_true", acct: &Account{Extra: map[string]any{ extraKeyCreditsBalance: 1.5, extraKeyCreditsCheckedAt: time.Now().UTC().Format(time.RFC3339), }}, want: true, }, { name: "余额 > 0_刚耗尽_false", acct: &Account{Extra: map[string]any{ extraKeyCreditsBalance: 5.0, extraKeyCreditsCheckedAt: time.Now().UTC().Format(time.RFC3339), extraKeyCreditsExhaustedAt: time.Now().UTC().Format(time.RFC3339), }}, want: false, }, { name: "余额 > 0_耗尽标记已过期_true", acct: &Account{Extra: map[string]any{ extraKeyCreditsBalance: 5.0, extraKeyCreditsCheckedAt: time.Now().UTC().Format(time.RFC3339), extraKeyCreditsExhaustedAt: time.Now().Add(-2 * time.Hour).UTC().Format(time.RFC3339), }}, want: true, }, { name: "余额来自字符串_仍可识别", acct: &Account{Extra: map[string]any{ extraKeyCreditsBalance: "10.5", }}, want: true, }, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { if got := AccountHasUsableCredits(tc.acct); got != tc.want { t.Errorf("AccountHasUsableCredits = %v, want %v", got, tc.want) } }) } } func TestRefreshAccountCreditsFromLoadCodeAssist_累加_GOOGLE_ONE_AI(t *testing.T) { acct := &Account{Extra: map[string]any{ // 设置一个旧的耗尽标记,验证刷新后会被清除 extraKeyCreditsExhaustedAt: time.Now().Add(-1 * time.Minute).UTC().Format(time.RFC3339), }} resp := &antigravity.LoadCodeAssistResponse{ PaidTier: &antigravity.PaidTierInfo{ AvailableCredits: []antigravity.AvailableCredit{ {CreditType: antigravity.CreditTypeGoogleOneAI, CreditAmount: "8.5"}, {CreditType: "OTHER_TYPE", CreditAmount: "100.0"}, // 应被忽略 {CreditType: "", CreditAmount: "1.5"}, // 空 type 视为 GOOGLE_ONE_AI 兼容 }, }, } refreshAccountCreditsFromLoadCodeAssist(acct, resp) if got := readFloat(acct.Extra[extraKeyCreditsBalance]); got != 10.0 { t.Errorf("余额累加错误: got %v, want 10.0", got) } if _, present := acct.Extra[extraKeyCreditsExhaustedAt]; present { t.Errorf("刷新后耗尽标记应被清除") } if !AccountHasUsableCredits(acct) { t.Errorf("刷新后账号应可用 credits") } } func TestRefreshAccountCreditsFromLoadCodeAssist_无_paidTier_余额_0(t *testing.T) { acct := &Account{} refreshAccountCreditsFromLoadCodeAssist(acct, &antigravity.LoadCodeAssistResponse{}) if got := readFloat(acct.Extra[extraKeyCreditsBalance]); got != 0 { t.Errorf("无 paidTier 时余额应为 0: got %v", got) } if AccountHasUsableCredits(acct) { t.Errorf("零余额账号不应被视为可用") } }