billing_service_rate_multiplier_test.go 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
  1. //go:build unit
  2. package service
  3. import (
  4. "testing"
  5. "github.com/stretchr/testify/require"
  6. )
  7. // TestCalculateCost_RateMultiplier_NegativeClampedToZero 锁定负数倍率被
  8. // 钳制为 0(而非历史上的 1.0),避免配置异常导致静默按标准价扣费。
  9. func TestCalculateCost_RateMultiplier_NegativeClampedToZero(t *testing.T) {
  10. svc := newTestBillingService()
  11. tokens := UsageTokens{InputTokens: 1000, OutputTokens: 500}
  12. tests := []struct {
  13. name string
  14. multiplier float64
  15. wantRatio float64 // ActualCost / TotalCost
  16. }{
  17. {"negative clamped to 0", -1.5, 0},
  18. {"zero passes through as 0 (defense in depth)", 0, 0},
  19. {"positive 2x applied", 2.0, 2.0},
  20. {"positive 0.5x applied", 0.5, 0.5},
  21. }
  22. for _, tt := range tests {
  23. t.Run(tt.name, func(t *testing.T) {
  24. cost, err := svc.CalculateCost("claude-sonnet-4", tokens, tt.multiplier)
  25. require.NoError(t, err)
  26. require.Greater(t, cost.TotalCost, 0.0, "TotalCost should be non-zero")
  27. require.InDelta(t, tt.wantRatio*cost.TotalCost, cost.ActualCost, 1e-9)
  28. })
  29. }
  30. }
  31. // TestCalculateImageCost_RateMultiplier_NegativeClampedToZero 图片按次计费路径
  32. // 同样遵循"负数 → 0"语义。
  33. func TestCalculateImageCost_RateMultiplier_NegativeClampedToZero(t *testing.T) {
  34. svc := newTestBillingService()
  35. price := 0.04
  36. cfg := &ImagePriceConfig{Price1K: &price}
  37. tests := []struct {
  38. name string
  39. multiplier float64
  40. wantRatio float64
  41. }{
  42. {"negative clamped to 0", -0.5, 0},
  43. {"zero passes through", 0, 0},
  44. {"positive 3x applied", 3.0, 3.0},
  45. }
  46. for _, tt := range tests {
  47. t.Run(tt.name, func(t *testing.T) {
  48. cost := svc.CalculateImageCost("imagen-3", "1K", 2, cfg, tt.multiplier)
  49. require.NotNil(t, cost)
  50. require.Greater(t, cost.TotalCost, 0.0)
  51. require.InDelta(t, tt.wantRatio*cost.TotalCost, cost.ActualCost, 1e-9)
  52. })
  53. }
  54. }