use llmshim::models::{available_models, spec, ModelCapabilities, Support, MODELS};
#[test]
fn models_registry_has_all_providers() {
let providers: Vec<&str> = MODELS.iter().map(|m| m.provider).collect();
assert!(providers.contains(&"openai"));
assert!(providers.contains(&"anthropic"));
assert!(providers.contains(&"gemini"));
assert!(providers.contains(&"xai"));
}
#[test]
fn models_registry_has_expected_count() {
assert_eq!(MODELS.len(), 23);
}
#[test]
fn models_registry_includes_gpt_5_5() {
assert!(MODELS.iter().any(|m| m.id == "openai/gpt-5.5"));
}
#[test]
fn models_ids_have_provider_prefix() {
for m in MODELS {
assert!(m.id.contains('/'), "Model {} missing provider prefix", m.id);
assert!(
m.id.starts_with(&format!("{}/", m.provider)),
"Model {} prefix doesn't match provider {}",
m.id,
m.provider
);
}
}
#[test]
fn available_models_filters_by_provider() {
let registered = vec!["anthropic", "openai"];
let models = available_models(®istered);
for m in &models {
assert!(
m.provider == "anthropic" || m.provider == "openai",
"Unexpected provider: {}",
m.provider
);
}
assert!(models.iter().all(|m| m.provider != "gemini"));
assert!(models.iter().all(|m| m.provider != "xai"));
}
#[test]
fn available_models_empty_providers_returns_empty() {
let models = available_models(&[]);
assert!(models.is_empty());
}
#[test]
fn available_models_all_providers_returns_all() {
let registered = vec!["openai", "anthropic", "gemini", "xai"];
let models = available_models(®istered);
assert_eq!(models.len(), MODELS.len());
}
#[test]
fn available_models_unknown_provider_ignored() {
let registered = vec!["nonexistent"];
let models = available_models(®istered);
assert!(models.is_empty());
}
#[test]
fn spec_looks_up_by_full_id_and_bare_name() {
let by_id = spec("openai/gpt-5.6-sol").expect("lookup by full id");
let by_name = spec("gpt-5.6-sol").expect("lookup by bare name");
assert_eq!(by_id.id, by_name.id);
assert_eq!(by_id.name, "gpt-5.6-sol");
}
#[test]
fn spec_returns_none_for_unregistered() {
assert!(spec("openai/does-not-exist").is_none());
}
#[test]
fn undocumented_spec_fields_stay_unknown_not_guessed() {
let m = spec("xai/grok-4.5").unwrap();
assert_eq!(m.max_output_tokens, None);
assert_eq!(m.capabilities.streaming, Support::Unknown);
assert_eq!(m.capabilities.parallel_tool_calls, Support::Unknown);
assert_eq!(m.context_window_tokens, Some(500_000));
assert_eq!(m.capabilities.tools, Support::Supported);
}
#[test]
fn verified_specs_are_populated() {
let opus = spec("anthropic/claude-opus-4-8").unwrap();
assert_eq!(opus.context_window_tokens, Some(1_000_000));
assert_eq!(opus.max_output_tokens, Some(128_000));
assert_eq!(opus.capabilities.images, Support::Supported);
assert_eq!(opus.capabilities.prompt_cache, Support::Supported);
let haiku = spec("anthropic/claude-haiku-4-5-20251001").unwrap();
assert_eq!(haiku.context_window_tokens, Some(200_000));
assert_eq!(haiku.max_output_tokens, Some(64_000));
let mini = spec("openai/gpt-5.4-mini").unwrap();
assert_eq!(mini.context_window_tokens, Some(400_000));
}
#[test]
fn documented_capability_exceptions_are_recorded() {
assert_eq!(
spec("openai/gpt-5.5-pro").unwrap().capabilities.streaming,
Support::Unsupported
);
assert_eq!(
spec("openai/gpt-5.4-pro")
.unwrap()
.capabilities
.structured_output,
Support::Unsupported
);
}
#[test]
fn default_capabilities_are_all_unknown() {
let caps = ModelCapabilities::default();
assert_eq!(caps, ModelCapabilities::unknown());
assert_eq!(caps.reasoning, Support::Unknown);
assert_eq!(caps.structured_output, Support::Unknown);
}
#[test]
fn reasoning_support_is_populated_for_every_model() {
for m in MODELS {
assert_ne!(
m.capabilities.reasoning,
Support::Unknown,
"{} has unpopulated reasoning support",
m.id
);
}
}
#[test]
fn reasoning_support_matches_provider_behavior() {
for id in [
"openai/gpt-5.6-sol",
"anthropic/claude-opus-4-8",
"xai/grok-4.5",
] {
assert_eq!(
spec(id).unwrap().capabilities.reasoning,
Support::Supported,
"{id} should support a reasoning control"
);
}
for id in [
"xai/grok-4.20-beta-0309-reasoning",
"xai/grok-4.20-beta-0309-non-reasoning",
"xai/grok-4.20-multi-agent-beta-0309",
] {
assert_eq!(
spec(id).unwrap().capabilities.reasoning,
Support::Unsupported,
"{id} rejects reasoning controls"
);
}
}