package antigravity import ( "encoding/json" "testing" "github.com/stretchr/testify/require" ) // 验证 EnableAICredits 选项控制 v1internal.enabledCreditTypes 的注入。 // 注入 ["GOOGLE_ONE_AI"] 是让 free 配额耗尽的请求落到 paidTier.availableCredits 的关键。 func TestTransformClaudeToGemini_AICreditsInjection(t *testing.T) { baseReq := func() *ClaudeRequest { return &ClaudeRequest{ Model: "claude-sonnet-4-5", Messages: []ClaudeMessage{ {Role: "user", Content: json.RawMessage(`[{"type":"text","text":"hi"}]`)}, }, } } cases := []struct { name string enable bool wantCredits []string }{ {name: "默认关闭_不注入", enable: false, wantCredits: nil}, {name: "显式启用_注入_GOOGLE_ONE_AI", enable: true, wantCredits: []string{CreditTypeGoogleOneAI}}, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { opts := DefaultTransformOptions() opts.EnableAICredits = tc.enable body, err := TransformClaudeToGeminiWithOptions(baseReq(), "project-1", "claude-sonnet-4-5", opts) require.NoError(t, err) // 用 raw map 校验 omitempty 语义(nil 时字段必须缺失,不能是 []) var raw map[string]any require.NoError(t, json.Unmarshal(body, &raw)) if tc.wantCredits == nil { _, present := raw["enabledCreditTypes"] require.False(t, present, "enabledCreditTypes 在禁用时不应出现在 payload 顶层") return } require.Contains(t, raw, "enabledCreditTypes") var typed V1InternalRequest require.NoError(t, json.Unmarshal(body, &typed)) require.Equal(t, tc.wantCredits, typed.EnabledCreditTypes) }) } } // 验证 enabledCreditTypes 注入位置在 v1internal 顶层,不是内层 request 子对象。 // 这与 CLIProxyAPI 真实行为一致;放错位置上游会忽略字段。 func TestTransformClaudeToGemini_AICreditsLocation_顶层(t *testing.T) { opts := DefaultTransformOptions() opts.EnableAICredits = true req := &ClaudeRequest{ Model: "claude-sonnet-4-5", Messages: []ClaudeMessage{ {Role: "user", Content: json.RawMessage(`[{"type":"text","text":"hi"}]`)}, }, } body, err := TransformClaudeToGeminiWithOptions(req, "p", "claude-sonnet-4-5", opts) require.NoError(t, err) var raw map[string]any require.NoError(t, json.Unmarshal(body, &raw)) require.Contains(t, raw, "enabledCreditTypes", "必须在顶层") if inner, ok := raw["request"].(map[string]any); ok { _, presentInInner := inner["enabledCreditTypes"] require.False(t, presentInInner, "不能放在内层 request 子对象") } }