use crate::brain::Provider;
use crate::brain::provider::custom_openai_compatible::{
OpenAIProvider, is_token_field_mismatch, uses_max_completion_tokens,
};
#[test]
fn openai_provider_creation() {
let provider = OpenAIProvider::new("test-key".to_string());
assert_eq!(provider.name(), "openai");
}
#[test]
fn local_provider_creation() {
let provider = OpenAIProvider::local("http://localhost:1234/v1/chat/completions".to_string());
assert_eq!(provider.name(), "openai-compatible");
}
#[test]
fn supported_models_include_gpt4() {
let provider = OpenAIProvider::new("test-key".to_string());
let models = provider.supported_models();
assert!(models.contains(&"gpt-4".to_string()));
assert!(models.contains(&"gpt-3.5-turbo".to_string()));
}
#[test]
fn context_window_known_models() {
let provider = OpenAIProvider::new("test-key".to_string());
assert_eq!(provider.context_window("gpt-4"), Some(8_192));
assert_eq!(
provider.context_window("gpt-4-turbo-preview"),
Some(128_000)
);
assert_eq!(provider.context_window("gpt-4o"), Some(128_000));
assert_eq!(provider.context_window("gpt-4o-mini"), Some(128_000));
assert_eq!(provider.context_window("gpt-4.1"), Some(1_047_576));
assert_eq!(provider.context_window("gpt-4.1-mini"), Some(1_047_576));
assert_eq!(provider.context_window("gpt-5"), Some(1_047_576));
assert_eq!(provider.context_window("gpt-5-mini"), Some(1_047_576));
assert_eq!(provider.context_window("o1-mini"), Some(200_000));
assert_eq!(provider.context_window("o3-mini"), Some(200_000));
assert_eq!(provider.context_window("o4-mini"), Some(200_000));
}
#[test]
fn context_window_unknown_returns_none() {
let provider = OpenAIProvider::new("test-key".to_string());
assert_eq!(provider.context_window("unknown"), None);
}
#[test]
fn calculate_cost_gpt5_nano() {
let provider = OpenAIProvider::new("test-key".to_string());
let cost = provider.calculate_cost("gpt-5-nano", 1000, 1000);
assert!(
(cost - 0.0005).abs() < 0.0001,
"expected ~0.0005 but got {cost}"
);
}
#[test]
fn gpt41_uses_max_completion_tokens() {
assert!(uses_max_completion_tokens("gpt-4.1-mini"));
assert!(uses_max_completion_tokens("gpt-4.1-nano"));
assert!(uses_max_completion_tokens("gpt-4.1"));
}
#[test]
fn gpt5_uses_max_completion_tokens() {
assert!(uses_max_completion_tokens("gpt-5-mini"));
assert!(uses_max_completion_tokens("gpt-5"));
}
#[test]
fn o_series_uses_max_completion_tokens() {
assert!(uses_max_completion_tokens("o1-mini"));
assert!(uses_max_completion_tokens("o1-preview"));
assert!(uses_max_completion_tokens("o3-mini"));
assert!(uses_max_completion_tokens("o4-mini"));
}
#[test]
fn older_models_use_max_tokens() {
assert!(!uses_max_completion_tokens("gpt-4o"));
assert!(!uses_max_completion_tokens("gpt-4o-mini"));
assert!(!uses_max_completion_tokens("gpt-3.5-turbo"));
assert!(!uses_max_completion_tokens("gpt-4-turbo"));
}
#[test]
fn detects_max_tokens_unsupported_error() {
assert!(is_token_field_mismatch(
"Unsupported parameter: 'max_tokens' is not supported with this model"
));
}
#[test]
fn detects_max_completion_tokens_unsupported_error() {
assert!(is_token_field_mismatch(
"Unsupported parameter: 'max_completion_tokens' is not supported"
));
}
#[test]
fn ignores_unrelated_errors() {
assert!(!is_token_field_mismatch("Rate limit exceeded"));
assert!(!is_token_field_mismatch("Invalid API key"));
assert!(!is_token_field_mismatch("model not found"));
}
#[test]
fn extra_headers_builder() {
let provider = OpenAIProvider::new("key".to_string())
.with_extra_headers(vec![("X-Custom".to_string(), "value".to_string())]);
assert_eq!(provider.extra_headers.len(), 1);
assert_eq!(provider.extra_headers[0].0, "X-Custom");
}
#[test]
fn with_name_changes_provider_name() {
let provider = OpenAIProvider::new("key".to_string()).with_name("GitHub Copilot");
assert_eq!(provider.name(), "GitHub Copilot");
}
#[test]
fn with_base_url_changes_provider() {
let provider =
OpenAIProvider::with_base_url("key".to_string(), "https://example.com/v1/chat".to_string());
assert_eq!(provider.name(), "openai-compatible");
}