#![allow(
clippy::unwrap_used,
clippy::expect_used,
clippy::panic,
clippy::str_to_string
)]
use embacle::pricing::{calculate_cost, calculate_cost_for, TokenCounts};
#[test]
fn test_known_model_cost() {
let cost = calculate_cost("gemini", "gemini-2.0-flash", 1000, 500);
let expected = 1000.0_f64.mul_add(0.075, 500.0 * 0.30) / 1_000_000.0;
assert!(
(cost - expected).abs() < f64::EPSILON,
"Expected {expected}, got {cost}"
);
}
#[test]
fn test_unknown_model_returns_zero() {
let cost = calculate_cost("unknown_provider", "unknown_model", 1000, 500);
assert!(
cost.abs() < f64::EPSILON,
"Expected 0.0 for unknown model, got {cost}"
);
}
#[test]
fn test_zero_tokens_returns_zero() {
let cost = calculate_cost("gemini", "gemini-2.0-flash", 0, 0);
assert!(
cost.abs() < f64::EPSILON,
"Expected 0.0 for zero tokens, got {cost}"
);
}
#[test]
fn test_prefix_matching() {
let cost_exact = calculate_cost("gemini", "gemini-2.0-flash", 1000, 500);
let cost_variant = calculate_cost("gemini", "gemini-2.0-flash-exp", 1000, 500);
assert!(
(cost_exact - cost_variant).abs() < f64::EPSILON,
"Variant model should match base pricing"
);
}
#[test]
fn test_gemini_25_pro_pricing() {
let cost = calculate_cost("gemini", "gemini-2.5-pro", 1_000_000, 500_000);
let expected = 1.25 + 5.0; assert!(
(cost - expected).abs() < 1e-10,
"Expected {expected}, got {cost}"
);
}
#[test]
fn test_groq_llama_pricing() {
let cost = calculate_cost("groq", "llama-3.3-70b-versatile", 2000, 1000);
let expected = 2000.0_f64.mul_add(0.59, 1000.0 * 0.79) / 1_000_000.0;
assert!(
(cost - expected).abs() < f64::EPSILON,
"Expected {expected}, got {cost}"
);
}
#[test]
fn test_groq_mixtral_pricing() {
let cost = calculate_cost("groq", "mixtral-8x7b-32768", 5000, 3000);
let expected = 5000.0_f64.mul_add(0.24, 3000.0 * 0.24) / 1_000_000.0;
assert!(
(cost - expected).abs() < f64::EPSILON,
"Expected {expected}, got {cost}"
);
}
#[test]
fn test_gemini_flash_lite_latest_pricing() {
let cost = calculate_cost("gemini", "gemini-flash-lite-latest", 1_000_000, 100_000);
let expected = 0.10 + 0.04; assert!(
(cost - expected).abs() < 1e-10,
"Expected {expected}, got {cost}"
);
}
#[test]
fn test_every_default_model_has_pricing() {
let production_models = [
("gemini", "gemini-flash-lite-latest"),
("gemini", "gemini-2.5-flash"),
("gemini", "gemini-2.0-flash"),
("groq", "llama-3.3-70b-versatile"),
];
for (provider, model) in production_models {
let cost = calculate_cost(provider, model, 1000, 1000);
assert!(
cost > 0.0,
"Model {provider}/{model} has ZERO pricing — every turn on it bills $0.00"
);
}
}
#[test]
fn anthropic_cache_read_bills_at_ten_percent() {
let counts = TokenCounts::new(1_000_000, 0).with_cache(1_000_000, 0);
let cost = calculate_cost_for("copilot_headless", "claude-opus-4", &counts);
assert!(
(cost - 1.50).abs() < 1e-9,
"expected $1.50 for 1M Anthropic cache-read tokens, got {cost}"
);
}
#[test]
fn anthropic_cache_write_bills_above_fresh_input() {
let written = TokenCounts::new(1_000_000, 0).with_cache(0, 1_000_000);
let fresh = TokenCounts::new(1_000_000, 0);
let write_cost = calculate_cost_for("copilot_headless", "claude-opus-4", &written);
let fresh_cost = calculate_cost_for("copilot_headless", "claude-opus-4", &fresh);
assert!(
(write_cost - 18.75).abs() < 1e-9,
"expected $18.75 for 1M Anthropic cache-write tokens, got {write_cost}"
);
assert!(
write_cost > fresh_cost,
"a cache write is a premium, not a discount: write={write_cost} fresh={fresh_cost}"
);
}
#[test]
fn reasoning_tokens_bill_at_the_output_rate() {
let without = TokenCounts::new(0, 1_000_000);
let with = TokenCounts::new(0, 1_000_000).with_reasoning(1_000_000);
let cost_without = calculate_cost_for("copilot_headless", "claude-opus-4", &without);
let cost_with = calculate_cost_for("copilot_headless", "claude-opus-4", &with);
assert!(
(cost_without - 75.0).abs() < 1e-9,
"expected $75 for 1M completion tokens, got {cost_without}"
);
assert!(
(cost_with - 150.0).abs() < 1e-9,
"reasoning tokens must bill at the output rate; got {cost_with}"
);
}
#[test]
fn cache_read_rate_is_per_provider() {
let counts = TokenCounts::new(1_000_000, 0).with_cache(1_000_000, 0);
let anthropic = calculate_cost_for("copilot_headless", "claude-opus-4", &counts);
let openai = calculate_cost_for("openai_api", "gpt-4o", &counts);
let gemini = calculate_cost_for("gemini", "gemini-2.0-flash", &counts);
assert!((anthropic - 1.50).abs() < 1e-9, "anthropic={anthropic}");
assert!((openai - 1.25).abs() < 1e-9, "openai={openai}");
assert!((gemini - 0.018_75).abs() < 1e-9, "gemini={gemini}");
}
#[test]
fn real_acp_turn_splits_prompt_across_three_rates() {
let counts = TokenCounts::new(27_862, 4).with_cache(15_320, 12_540);
let cost = calculate_cost_for("copilot_headless", "claude-opus-4", &counts);
let input = 15.0 / 1_000_000.0;
let fresh = f64::from(27_862 - 15_320 - 12_540) * input;
let read = 15_320.0 * input * 0.10;
let write = 12_540.0 * input * 1.25;
let output = 4.0 * 75.0 / 1_000_000.0;
let expected = fresh + read + write + output;
assert!(
(cost - expected).abs() < 1e-12,
"expected {expected}, got {cost}"
);
let naive = calculate_cost_for(
"copilot_headless",
"claude-opus-4",
&TokenCounts::new(27_862, 4),
);
assert!(
(cost - naive).abs() > 1e-9,
"cache-aware and all-fresh imputation must differ; both were {cost}"
);
}
#[test]
fn cache_counts_are_clamped_to_the_prompt() {
let counts = TokenCounts::new(1_000, 0).with_cache(900, 900);
let cost = calculate_cost_for("copilot_headless", "claude-opus-4", &counts);
let input = 15.0 / 1_000_000.0;
let expected = 900.0f64.mul_add(input * 0.10, 100.0 * input * 1.25);
assert!(
(cost - expected).abs() < 1e-12,
"expected {expected}, got {cost}"
);
}