package service import ( "encoding/json" "testing" "github.com/stretchr/testify/require" ) func TestIsClaudeCodeClient(t *testing.T) { tests := []struct { name string userAgent string metadataUserID string want bool }{ { name: "Claude Code client", userAgent: "claude-cli/1.0.62 (darwin; arm64)", metadataUserID: "session_123e4567-e89b-12d3-a456-426614174000", want: true, }, { name: "Claude Code without version suffix", userAgent: "claude-cli/2.0.0", metadataUserID: "session_abc", want: true, }, { name: "Missing metadata user_id", userAgent: "claude-cli/1.0.0", metadataUserID: "", want: false, }, { name: "Different user agent", userAgent: "curl/7.68.0", metadataUserID: "user123", want: false, }, { name: "Empty user agent", userAgent: "", metadataUserID: "user123", want: false, }, { name: "Similar but not Claude CLI", userAgent: "claude-api/1.0.0", metadataUserID: "user123", want: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got := isClaudeCodeClient(tt.userAgent, tt.metadataUserID) require.Equal(t, tt.want, got) }) } } func TestSystemIncludesClaudeCodePrompt(t *testing.T) { tests := []struct { name string system any want bool }{ { name: "nil system", system: nil, want: false, }, { name: "empty string", system: "", want: false, }, { name: "string with Claude Code prompt", system: claudeCodeSystemPrompt, want: true, }, { name: "string with different content", system: "You are a helpful assistant.", want: false, }, { name: "empty array", system: []any{}, want: false, }, { name: "array with Claude Code prompt", system: []any{ map[string]any{ "type": "text", "text": claudeCodeSystemPrompt, }, }, want: true, }, { name: "array with Claude Code prompt in second position", system: []any{ map[string]any{"type": "text", "text": "First prompt"}, map[string]any{"type": "text", "text": claudeCodeSystemPrompt}, }, want: true, }, { name: "array without Claude Code prompt", system: []any{ map[string]any{"type": "text", "text": "Custom prompt"}, }, want: false, }, { name: "array with partial match (should not match)", system: []any{ map[string]any{"type": "text", "text": "You are Claude"}, }, want: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got := systemIncludesClaudeCodePrompt(tt.system) require.Equal(t, tt.want, got) }) } } func TestInjectClaudeCodePrompt(t *testing.T) { tests := []struct { name string body string system any wantSystemLen int wantFirstText string wantSecondText string }{ { name: "nil system", body: `{"model":"claude-3"}`, system: nil, wantSystemLen: 1, wantFirstText: claudeCodeSystemPrompt, }, { name: "empty string system", body: `{"model":"claude-3"}`, system: "", wantSystemLen: 1, wantFirstText: claudeCodeSystemPrompt, }, { name: "string system", body: `{"model":"claude-3"}`, system: "Custom prompt", wantSystemLen: 2, wantFirstText: claudeCodeSystemPrompt, wantSecondText: "Custom prompt", }, { name: "string system equals Claude Code prompt", body: `{"model":"claude-3"}`, system: claudeCodeSystemPrompt, wantSystemLen: 1, wantFirstText: claudeCodeSystemPrompt, }, { name: "array system", body: `{"model":"claude-3"}`, system: []any{map[string]any{"type": "text", "text": "Custom"}}, // Claude Code + Custom = 2 wantSystemLen: 2, wantFirstText: claudeCodeSystemPrompt, wantSecondText: "Custom", }, { name: "array system with existing Claude Code prompt (should dedupe)", body: `{"model":"claude-3"}`, system: []any{ map[string]any{"type": "text", "text": claudeCodeSystemPrompt}, map[string]any{"type": "text", "text": "Other"}, }, // Claude Code at start + Other = 2 (deduped) wantSystemLen: 2, wantFirstText: claudeCodeSystemPrompt, wantSecondText: "Other", }, { name: "empty array", body: `{"model":"claude-3"}`, system: []any{}, wantSystemLen: 1, wantFirstText: claudeCodeSystemPrompt, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := injectClaudeCodePrompt([]byte(tt.body), tt.system) var parsed map[string]any err := json.Unmarshal(result, &parsed) require.NoError(t, err) system, ok := parsed["system"].([]any) require.True(t, ok, "system should be an array") require.Len(t, system, tt.wantSystemLen) first, ok := system[0].(map[string]any) require.True(t, ok) require.Equal(t, tt.wantFirstText, first["text"]) require.Equal(t, "text", first["type"]) // Check cache_control cc, ok := first["cache_control"].(map[string]any) require.True(t, ok) require.Equal(t, "ephemeral", cc["type"]) if tt.wantSecondText != "" && len(system) > 1 { second, ok := system[1].(map[string]any) require.True(t, ok) require.Equal(t, tt.wantSecondText, second["text"]) } }) } }