mirror of
https://github.com/router-for-me/CLIProxyAPI.git
synced 2026-02-18 04:10:51 +08:00
test(thinking): remove legacy unit and integration tests
This commit is contained in:
@@ -1,288 +0,0 @@
|
||||
// Package claude implements thinking configuration for Claude models.
|
||||
package claude
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/router-for-me/CLIProxyAPI/v6/internal/registry"
|
||||
"github.com/router-for-me/CLIProxyAPI/v6/internal/thinking"
|
||||
"github.com/tidwall/gjson"
|
||||
)
|
||||
|
||||
// =============================================================================
|
||||
// Unit Tests: Applier Creation and Interface
|
||||
// =============================================================================
|
||||
|
||||
func TestNewApplier(t *testing.T) {
|
||||
applier := NewApplier()
|
||||
if applier == nil {
|
||||
t.Fatal("NewApplier() returned nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplierImplementsInterface(t *testing.T) {
|
||||
var _ thinking.ProviderApplier = (*Applier)(nil)
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Unit Tests: Budget and Disable Logic (Pre-validated Config)
|
||||
// =============================================================================
|
||||
|
||||
// TestClaudeApplyBudgetAndNone tests budget values and disable modes.
|
||||
// NOTE: These tests assume config has been pre-validated by ValidateConfig.
|
||||
// Apply trusts the input and does not perform clamping.
|
||||
func TestClaudeApplyBudgetAndNone(t *testing.T) {
|
||||
applier := NewApplier()
|
||||
modelInfo := buildClaudeModelInfo()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
config thinking.ThinkingConfig
|
||||
wantType string
|
||||
wantBudget int
|
||||
wantBudgetOK bool
|
||||
}{
|
||||
// Valid pre-validated budget values
|
||||
{"budget 16k", thinking.ThinkingConfig{Mode: thinking.ModeBudget, Budget: 16384}, "enabled", 16384, true},
|
||||
{"budget min", thinking.ThinkingConfig{Mode: thinking.ModeBudget, Budget: 1024}, "enabled", 1024, true},
|
||||
{"budget max", thinking.ThinkingConfig{Mode: thinking.ModeBudget, Budget: 128000}, "enabled", 128000, true},
|
||||
{"budget mid", thinking.ThinkingConfig{Mode: thinking.ModeBudget, Budget: 50000}, "enabled", 50000, true},
|
||||
// Disable cases
|
||||
{"budget zero disables", thinking.ThinkingConfig{Mode: thinking.ModeBudget, Budget: 0}, "disabled", 0, false},
|
||||
{"mode none disables", thinking.ThinkingConfig{Mode: thinking.ModeNone, Budget: 0}, "disabled", 0, false},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result, err := applier.Apply([]byte(`{}`), tt.config, modelInfo)
|
||||
if err != nil {
|
||||
t.Fatalf("Apply() error = %v", err)
|
||||
}
|
||||
|
||||
thinkingType := gjson.GetBytes(result, "thinking.type").String()
|
||||
if thinkingType != tt.wantType {
|
||||
t.Fatalf("thinking.type = %q, want %q", thinkingType, tt.wantType)
|
||||
}
|
||||
|
||||
budgetValue := gjson.GetBytes(result, "thinking.budget_tokens")
|
||||
if budgetValue.Exists() != tt.wantBudgetOK {
|
||||
t.Fatalf("thinking.budget_tokens exists = %v, want %v", budgetValue.Exists(), tt.wantBudgetOK)
|
||||
}
|
||||
if tt.wantBudgetOK {
|
||||
if got := int(budgetValue.Int()); got != tt.wantBudget {
|
||||
t.Fatalf("thinking.budget_tokens = %d, want %d", got, tt.wantBudget)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestClaudeApplyPassthroughBudget tests that Apply trusts pre-validated budget values.
|
||||
// It does NOT perform clamping - that's ValidateConfig's responsibility.
|
||||
func TestClaudeApplyPassthroughBudget(t *testing.T) {
|
||||
applier := NewApplier()
|
||||
modelInfo := buildClaudeModelInfo()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
config thinking.ThinkingConfig
|
||||
wantBudget int
|
||||
}{
|
||||
// Apply should pass through the budget value as-is
|
||||
// (ValidateConfig would have clamped these, but Apply trusts the input)
|
||||
{"passes through any budget", thinking.ThinkingConfig{Mode: thinking.ModeBudget, Budget: 500}, 500},
|
||||
{"passes through large budget", thinking.ThinkingConfig{Mode: thinking.ModeBudget, Budget: 200000}, 200000},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result, err := applier.Apply([]byte(`{}`), tt.config, modelInfo)
|
||||
if err != nil {
|
||||
t.Fatalf("Apply() error = %v", err)
|
||||
}
|
||||
|
||||
if got := int(gjson.GetBytes(result, "thinking.budget_tokens").Int()); got != tt.wantBudget {
|
||||
t.Fatalf("thinking.budget_tokens = %d, want %d (passthrough)", got, tt.wantBudget)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Unit Tests: Mode Passthrough (Strict Layering)
|
||||
// =============================================================================
|
||||
|
||||
// TestClaudeApplyModePassthrough tests that non-Budget/None modes pass through unchanged.
|
||||
// Apply expects ValidateConfig to have already converted Level/Auto to Budget.
|
||||
func TestClaudeApplyModePassthrough(t *testing.T) {
|
||||
applier := NewApplier()
|
||||
modelInfo := buildClaudeModelInfo()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
config thinking.ThinkingConfig
|
||||
body string
|
||||
}{
|
||||
{"ModeLevel passes through", thinking.ThinkingConfig{Mode: thinking.ModeLevel, Level: "high"}, `{"model":"test"}`},
|
||||
{"ModeAuto passes through", thinking.ThinkingConfig{Mode: thinking.ModeAuto, Budget: -1}, `{"model":"test"}`},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result, err := applier.Apply([]byte(tt.body), tt.config, modelInfo)
|
||||
if err != nil {
|
||||
t.Fatalf("Apply() error = %v", err)
|
||||
}
|
||||
|
||||
// Should return body unchanged
|
||||
if string(result) != tt.body {
|
||||
t.Fatalf("Apply() = %s, want %s (passthrough)", string(result), tt.body)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Unit Tests: Output Format
|
||||
// =============================================================================
|
||||
|
||||
// TestClaudeApplyOutputFormat tests the exact JSON output format.
|
||||
//
|
||||
// Claude expects:
|
||||
//
|
||||
// {
|
||||
// "thinking": {
|
||||
// "type": "enabled",
|
||||
// "budget_tokens": 16384
|
||||
// }
|
||||
// }
|
||||
func TestClaudeApplyOutputFormat(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
config thinking.ThinkingConfig
|
||||
wantJSON string
|
||||
}{
|
||||
{
|
||||
"enabled with budget",
|
||||
thinking.ThinkingConfig{Mode: thinking.ModeBudget, Budget: 16384},
|
||||
`{"thinking":{"type":"enabled","budget_tokens":16384}}`,
|
||||
},
|
||||
{
|
||||
"disabled",
|
||||
thinking.ThinkingConfig{Mode: thinking.ModeNone, Budget: 0},
|
||||
`{"thinking":{"type":"disabled"}}`,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
applier := NewApplier()
|
||||
modelInfo := buildClaudeModelInfo()
|
||||
|
||||
result, err := applier.Apply([]byte(`{}`), tt.config, modelInfo)
|
||||
if err != nil {
|
||||
t.Fatalf("Apply() error = %v", err)
|
||||
}
|
||||
if string(result) != tt.wantJSON {
|
||||
t.Fatalf("Apply() = %s, want %s", result, tt.wantJSON)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Unit Tests: Body Merging
|
||||
// =============================================================================
|
||||
|
||||
// TestClaudeApplyWithExistingBody tests applying config to existing request body.
|
||||
func TestClaudeApplyWithExistingBody(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
body string
|
||||
config thinking.ThinkingConfig
|
||||
wantBody string
|
||||
}{
|
||||
{
|
||||
"add to empty body",
|
||||
`{}`,
|
||||
thinking.ThinkingConfig{Mode: thinking.ModeBudget, Budget: 16384},
|
||||
`{"thinking":{"type":"enabled","budget_tokens":16384}}`,
|
||||
},
|
||||
{
|
||||
"preserve existing fields",
|
||||
`{"model":"claude-sonnet-4-5","messages":[]}`,
|
||||
thinking.ThinkingConfig{Mode: thinking.ModeBudget, Budget: 8192},
|
||||
`{"model":"claude-sonnet-4-5","messages":[],"thinking":{"type":"enabled","budget_tokens":8192}}`,
|
||||
},
|
||||
{
|
||||
"override existing thinking",
|
||||
`{"thinking":{"type":"enabled","budget_tokens":1000}}`,
|
||||
thinking.ThinkingConfig{Mode: thinking.ModeBudget, Budget: 16384},
|
||||
`{"thinking":{"type":"enabled","budget_tokens":16384}}`,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
applier := NewApplier()
|
||||
modelInfo := buildClaudeModelInfo()
|
||||
|
||||
result, err := applier.Apply([]byte(tt.body), tt.config, modelInfo)
|
||||
if err != nil {
|
||||
t.Fatalf("Apply() error = %v", err)
|
||||
}
|
||||
if string(result) != tt.wantBody {
|
||||
t.Fatalf("Apply() = %s, want %s", result, tt.wantBody)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestClaudeApplyWithNilBody tests handling of nil/empty body.
|
||||
func TestClaudeApplyWithNilBody(t *testing.T) {
|
||||
applier := NewApplier()
|
||||
modelInfo := buildClaudeModelInfo()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
body []byte
|
||||
wantBudget int
|
||||
}{
|
||||
{"nil body", nil, 16384},
|
||||
{"empty body", []byte{}, 16384},
|
||||
{"empty object", []byte(`{}`), 16384},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
config := thinking.ThinkingConfig{Mode: thinking.ModeBudget, Budget: 16384}
|
||||
result, err := applier.Apply(tt.body, config, modelInfo)
|
||||
if err != nil {
|
||||
t.Fatalf("Apply() error = %v", err)
|
||||
}
|
||||
|
||||
if got := gjson.GetBytes(result, "thinking.type").String(); got != "enabled" {
|
||||
t.Fatalf("thinking.type = %q, want %q", got, "enabled")
|
||||
}
|
||||
if got := int(gjson.GetBytes(result, "thinking.budget_tokens").Int()); got != tt.wantBudget {
|
||||
t.Fatalf("thinking.budget_tokens = %d, want %d", got, tt.wantBudget)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Helper Functions
|
||||
// =============================================================================
|
||||
|
||||
func buildClaudeModelInfo() *registry.ModelInfo {
|
||||
return ®istry.ModelInfo{
|
||||
ID: "claude-sonnet-4-5",
|
||||
Thinking: ®istry.ThinkingSupport{
|
||||
Min: 1024,
|
||||
Max: 128000,
|
||||
ZeroAllowed: true,
|
||||
DynamicAllowed: false,
|
||||
},
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user