use config_agent::{load_settings, Settings}; use permissions::{Mode, PermissionDecision, Tool}; use llm_core::ProviderType; use std::{env, fs}; #[test] fn precedence_env_overrides_files() { let tmp = tempfile::tempdir().unwrap(); let project_file = tmp.path().join(".owlen.toml"); fs::write(&project_file, r#"model="local-model""#).unwrap(); unsafe { env::set_var("OWLEN_MODEL", "env-model"); } let s = load_settings(Some(tmp.path().to_str().unwrap())).unwrap(); assert_eq!(s.model, "env-model"); } #[test] fn default_mode_is_plan() { let s = Settings::default(); assert_eq!(s.mode, "plan"); } #[test] fn settings_create_permission_manager_with_plan_mode() { let s = Settings::default(); let mgr = s.create_permission_manager(); // Plan mode should allow read operations assert_eq!(mgr.check(Tool::Read, None), PermissionDecision::Allow); // Plan mode should ask for write operations assert_eq!(mgr.check(Tool::Write, None), PermissionDecision::Ask); } #[test] fn settings_parse_mode_from_config() { let tmp = tempfile::tempdir().unwrap(); let project_file = tmp.path().join(".owlen.toml"); fs::write(&project_file, r#"mode="code""#).unwrap(); let s = load_settings(Some(tmp.path().to_str().unwrap())).unwrap(); assert_eq!(s.mode, "code"); assert_eq!(s.get_mode(), Mode::Code); let mgr = s.create_permission_manager(); // Code mode should allow everything assert_eq!(mgr.check(Tool::Write, None), PermissionDecision::Allow); assert_eq!(mgr.check(Tool::Bash, None), PermissionDecision::Allow); } #[test] fn default_provider_is_ollama() { let s = Settings::default(); assert_eq!(s.provider, "ollama"); assert_eq!(s.get_provider(), Some(ProviderType::Ollama)); } #[test] fn provider_from_config_file() { let tmp = tempfile::tempdir().unwrap(); let project_file = tmp.path().join(".owlen.toml"); fs::write(&project_file, r#"provider="anthropic""#).unwrap(); let s = load_settings(Some(tmp.path().to_str().unwrap())).unwrap(); assert_eq!(s.provider, "anthropic"); assert_eq!(s.get_provider(), Some(ProviderType::Anthropic)); } #[test] #[ignore] // Ignore due to env var interaction in parallel tests fn provider_from_env_var() { let tmp = tempfile::tempdir().unwrap(); unsafe { env::set_var("OWLEN_PROVIDER", "openai"); env::remove_var("PROVIDER"); env::remove_var("ANTHROPIC_API_KEY"); env::remove_var("OPENAI_API_KEY"); } let s = load_settings(Some(tmp.path().to_str().unwrap())).unwrap(); assert_eq!(s.provider, "openai"); assert_eq!(s.get_provider(), Some(ProviderType::OpenAI)); unsafe { env::remove_var("OWLEN_PROVIDER"); } } #[test] #[ignore] // Ignore due to env var interaction in parallel tests fn provider_from_provider_env_var() { let tmp = tempfile::tempdir().unwrap(); unsafe { env::set_var("PROVIDER", "anthropic"); env::remove_var("OWLEN_PROVIDER"); env::remove_var("ANTHROPIC_API_KEY"); env::remove_var("OPENAI_API_KEY"); } let s = load_settings(Some(tmp.path().to_str().unwrap())).unwrap(); assert_eq!(s.provider, "anthropic"); assert_eq!(s.get_provider(), Some(ProviderType::Anthropic)); unsafe { env::remove_var("PROVIDER"); } } #[test] fn anthropic_api_key_from_owlen_env() { let tmp = tempfile::tempdir().unwrap(); let project_file = tmp.path().join(".owlen.toml"); fs::write(&project_file, r#"provider="anthropic""#).unwrap(); unsafe { env::set_var("OWLEN_ANTHROPIC_API_KEY", "sk-ant-test123"); } let s = load_settings(Some(tmp.path().to_str().unwrap())).unwrap(); assert_eq!(s.anthropic_api_key, Some("sk-ant-test123".to_string())); assert_eq!(s.get_provider_api_key(), Some("sk-ant-test123".to_string())); unsafe { env::remove_var("OWLEN_ANTHROPIC_API_KEY"); } } #[test] fn openai_api_key_from_owlen_env() { let tmp = tempfile::tempdir().unwrap(); let project_file = tmp.path().join(".owlen.toml"); fs::write(&project_file, r#"provider="openai""#).unwrap(); unsafe { env::set_var("OWLEN_OPENAI_API_KEY", "sk-test-456"); } let s = load_settings(Some(tmp.path().to_str().unwrap())).unwrap(); assert_eq!(s.openai_api_key, Some("sk-test-456".to_string())); assert_eq!(s.get_provider_api_key(), Some("sk-test-456".to_string())); unsafe { env::remove_var("OWLEN_OPENAI_API_KEY"); } } #[test] #[ignore] // Ignore due to env var interaction in parallel tests fn api_keys_from_config_file() { let tmp = tempfile::tempdir().unwrap(); let project_file = tmp.path().join(".owlen.toml"); fs::write(&project_file, r#" provider = "anthropic" anthropic_api_key = "sk-ant-from-file" openai_api_key = "sk-openai-from-file" "#).unwrap(); // Clear any env vars that might interfere unsafe { env::remove_var("ANTHROPIC_API_KEY"); env::remove_var("OPENAI_API_KEY"); env::remove_var("OWLEN_ANTHROPIC_API_KEY"); env::remove_var("OWLEN_OPENAI_API_KEY"); } let s = load_settings(Some(tmp.path().to_str().unwrap())).unwrap(); assert_eq!(s.anthropic_api_key, Some("sk-ant-from-file".to_string())); assert_eq!(s.openai_api_key, Some("sk-openai-from-file".to_string())); assert_eq!(s.get_provider_api_key(), Some("sk-ant-from-file".to_string())); } #[test] #[ignore] // Ignore due to env var interaction in parallel tests fn anthropic_api_key_from_standard_env() { let tmp = tempfile::tempdir().unwrap(); let project_file = tmp.path().join(".owlen.toml"); fs::write(&project_file, r#"provider="anthropic""#).unwrap(); unsafe { env::set_var("ANTHROPIC_API_KEY", "sk-ant-std"); env::remove_var("OWLEN_ANTHROPIC_API_KEY"); env::remove_var("PROVIDER"); env::remove_var("OWLEN_PROVIDER"); } let s = load_settings(Some(tmp.path().to_str().unwrap())).unwrap(); assert_eq!(s.anthropic_api_key, Some("sk-ant-std".to_string())); assert_eq!(s.get_provider_api_key(), Some("sk-ant-std".to_string())); unsafe { env::remove_var("ANTHROPIC_API_KEY"); } } #[test] #[ignore] // Ignore due to env var interaction in parallel tests fn openai_api_key_from_standard_env() { let tmp = tempfile::tempdir().unwrap(); let project_file = tmp.path().join(".owlen.toml"); fs::write(&project_file, r#"provider="openai""#).unwrap(); unsafe { env::set_var("OPENAI_API_KEY", "sk-openai-std"); env::remove_var("OWLEN_OPENAI_API_KEY"); env::remove_var("PROVIDER"); env::remove_var("OWLEN_PROVIDER"); } let s = load_settings(Some(tmp.path().to_str().unwrap())).unwrap(); assert_eq!(s.openai_api_key, Some("sk-openai-std".to_string())); assert_eq!(s.get_provider_api_key(), Some("sk-openai-std".to_string())); unsafe { env::remove_var("OPENAI_API_KEY"); } } #[test] #[ignore] // Ignore due to env var interaction in parallel tests fn owlen_prefix_overrides_standard_env() { let tmp = tempfile::tempdir().unwrap(); unsafe { env::set_var("ANTHROPIC_API_KEY", "sk-ant-std"); env::set_var("OWLEN_ANTHROPIC_API_KEY", "sk-ant-owlen"); } let s = load_settings(Some(tmp.path().to_str().unwrap())).unwrap(); // OWLEN_ prefix should take precedence assert_eq!(s.anthropic_api_key, Some("sk-ant-owlen".to_string())); unsafe { env::remove_var("ANTHROPIC_API_KEY"); env::remove_var("OWLEN_ANTHROPIC_API_KEY"); } } #[test] fn effective_model_uses_provider_default() { // Test Anthropic provider default let mut s = Settings::default(); s.provider = "anthropic".to_string(); assert_eq!(s.get_effective_model(), "claude-sonnet-4-20250514"); // Test OpenAI provider default s.provider = "openai".to_string(); assert_eq!(s.get_effective_model(), "gpt-4o"); // Test Ollama provider default s.provider = "ollama".to_string(); assert_eq!(s.get_effective_model(), "qwen3:8b"); } #[test] fn effective_model_respects_explicit_model() { let mut s = Settings::default(); s.provider = "anthropic".to_string(); s.model = "claude-opus-4-20250514".to_string(); // Should use explicit model, not provider default assert_eq!(s.get_effective_model(), "claude-opus-4-20250514"); }