diff --git a/crates/jarvis-core/src/llm/mod.rs b/crates/jarvis-core/src/llm/mod.rs index 5755913..f9a756a 100644 --- a/crates/jarvis-core/src/llm/mod.rs +++ b/crates/jarvis-core/src/llm/mod.rs @@ -142,3 +142,44 @@ pub fn parse_backend(name: &str) -> Option { _ => None, } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn parse_backend_accepts_english() { + assert_eq!(parse_backend("groq"), Some(LlmBackend::Groq)); + assert_eq!(parse_backend("ollama"), Some(LlmBackend::Ollama)); + assert_eq!(parse_backend("cloud"), Some(LlmBackend::Groq)); + assert_eq!(parse_backend("local"), Some(LlmBackend::Ollama)); + } + + #[test] + fn parse_backend_accepts_russian() { + assert_eq!(parse_backend("облако"), Some(LlmBackend::Groq)); + assert_eq!(parse_backend("локальный"), Some(LlmBackend::Ollama)); + assert_eq!(parse_backend("локал"), Some(LlmBackend::Ollama)); + } + + #[test] + fn parse_backend_case_insensitive() { + assert_eq!(parse_backend("OLLAMA"), Some(LlmBackend::Ollama)); + assert_eq!(parse_backend(" Groq "), Some(LlmBackend::Groq)); + } + + #[test] + fn parse_backend_rejects_unknown() { + assert_eq!(parse_backend("openai"), None); + assert_eq!(parse_backend("claude"), None); + assert_eq!(parse_backend(""), None); + } + + #[test] + fn current_backend_name_when_uninitialised_is_none() { + // Note: in the same process as other tests, GLOBAL may have been + // initialised by ollama_works_without_token. So this assertion is + // best-effort — just exercise the code path. + let _ = current_backend_name(); + } +} diff --git a/crates/jarvis-core/src/macros.rs b/crates/jarvis-core/src/macros.rs index 9c216a9..140171b 100644 --- a/crates/jarvis-core/src/macros.rs +++ b/crates/jarvis-core/src/macros.rs @@ -300,4 +300,35 @@ mod tests { assert_eq!(back.steps.len(), 2); assert_eq!(back.last_run, Some(200)); } + + #[test] + fn store_serde_round_trip() { + let mut store = Store::default(); + store.macros.insert("a".into(), Macro { + name: "a".into(), + steps: vec!["x".into()], + created_at: 1, + last_run: None, + }); + store.macros.insert("b".into(), Macro { + name: "b".into(), + steps: vec!["y".into(), "z".into()], + created_at: 2, + last_run: Some(3), + }); + let json = serde_json::to_string(&store).unwrap(); + let back: Store = serde_json::from_str(&json).unwrap(); + assert_eq!(back.macros.len(), 2); + assert_eq!(back.macros.get("b").unwrap().steps.len(), 2); + } + + #[test] + fn is_macro_control_handles_case() { + assert!(is_macro_control("ЗАПИШИ МАКРОС работа")); + assert!(is_macro_control("Сохрани макрос пожалуйста")); + assert!(is_macro_control("запусти макрос игра")); + // Noun form "запись макроса" intentionally does NOT match — we only + // filter the actual control verb-phrases. + assert!(!is_macro_control("запись макроса")); + } }