#![allow(unsafe_code)]
use std::collections::HashMap;
struct EnvHomeGuard {
home: Option<std::ffi::OsString>,
userprofile: Option<std::ffi::OsString>,
}
impl Drop for EnvHomeGuard {
fn drop(&mut self) {
unsafe {
match self.home.take() {
Some(v) => std::env::set_var("HOME", v),
None => std::env::remove_var("HOME"),
}
match self.userprofile.take() {
Some(v) => std::env::set_var("USERPROFILE", v),
None => std::env::remove_var("USERPROFILE"),
}
}
}
}
#[test]
fn default_store_uses_embedded_prompts_when_home_unset() {
let prompt = default_store_with_unset_home();
assert!(prompt.contains("Know thyself, agent"));
}
fn default_store_with_unset_home() -> String {
let (store, context) = default_prompt_store_with_unset_home();
render_default_header(&store, &context)
}
fn default_embedded_placeholder_context() -> HashMap<String, String> {
let mut ctx = HashMap::from([
("plan_path".to_string(), "/p".to_string()),
("result_path".to_string(), "/r".to_string()),
("malvin_output_path".to_string(), "/logs/run".to_string()),
("workspace_dir".to_string(), "/logs/run".to_string()),
(
"malvin_command".to_string(),
"malvin --model=cursor:auto".to_string(),
),
("quality_gates".to_string(), String::new()),
("advice_path".to_string(), "./.malvin/advice.md".to_string()),
("git_extra".to_string(), String::new()),
]);
insert_header_runtime_placeholders(&mut ctx);
ctx
}
fn insert_header_runtime_placeholders(ctx: &mut HashMap<String, String>) {
ctx.insert(
"quality_gates_log".to_string(),
"/q/quality_gates.log".to_string(),
);
ctx.insert(
"logs_dir".to_string(),
"/home/.malvin_home/logs/abc123".to_string(),
);
ctx.insert(
"current_state".to_string(),
"User: test\nDate/time: now\nSandbox memory: limit 4 GiB\nRetry: not a retry".to_string(),
);
}
fn default_prompt_store_with_unset_home() -> (super::PromptStore, HashMap<String, String>) {
let _lock = crate::test_utils::test_env_lock();
let profile = tempfile::tempdir().unwrap().path().join("profile");
std::fs::create_dir_all(&profile).unwrap();
let _guard = with_unset_home_profile(profile);
let store = {
let store = super::PromptStore::default_store();
store.ensure_defaults().unwrap();
store
};
let context = default_embedded_placeholder_context();
(store, context)
}
fn with_unset_home_profile(profile: std::path::PathBuf) -> EnvHomeGuard {
let guard = EnvHomeGuard {
home: std::env::var_os("HOME"),
userprofile: std::env::var_os("USERPROFILE"),
};
unsafe {
std::env::remove_var("HOME");
std::env::set_var("USERPROFILE", profile);
}
guard
}
fn render_default_header(store: &super::PromptStore, context: &HashMap<String, String>) -> String {
store.render("header.md", context).expect("render")
}
#[test]
fn embedded_do_header_is_a_single_text_block_with_closing_newline() {
let s = super::default_file(super::DO_HEADER_MD).expect("do header must be embedded");
let lower = s.to_ascii_lowercase();
assert!(s.ends_with('\n'));
assert!(lower.contains("no stream of consciousness"));
assert!(lower.contains("do not restate"));
assert!(lower.contains("required output format"));
assert!(lower.contains("failed response"));
assert!(s.contains("__MALVIN_DM_START__"));
assert!(s.contains("__MALVIN_DM_END__"));
assert!(!lower.contains("user request is:"));
assert!(!s.contains("You'll\n find"));
}
#[test]
fn smoke_cov_embedded_defaults_units() {
let _: Option<EnvHomeGuard> = None;
let _ = default_prompt_store_with_unset_home;
let _ = with_unset_home_profile;
let _ = render_default_header;
let _ = default_embedded_placeholder_context;
}