#![allow(
clippy::missing_docs_in_private_items,
reason = "test helpers and fixtures do not need doc comments"
)]
use super::*;
use crate::routines::{slugify, Routine};
fn make_routine(id: &str, title: &str) -> Routine {
let mut routine = crate::test_fixtures::routine_fixture(id, title)
.no_repositories()
.prompt("do the thing")
.times(0, 0)
.build();
routine.machines = vec![];
routine
}
fn scratch_dir(tag: &str) -> std::path::PathBuf {
std::env::temp_dir().join(format!("moadim-rs-{tag}-{}", uuid::Uuid::new_v4()))
}
fn with_override_home(body: impl FnOnce(&std::path::Path)) {
let home = scratch_dir("override-home");
std::fs::create_dir_all(&home).unwrap();
let previous = std::env::var_os("MOADIM_HOME_OVERRIDE");
unsafe {
std::env::set_var("MOADIM_HOME_OVERRIDE", &home);
}
body(&home);
unsafe {
match previous {
Some(value) => std::env::set_var("MOADIM_HOME_OVERRIDE", value),
None => std::env::remove_var("MOADIM_HOME_OVERRIDE"),
}
}
let _ = std::fs::remove_dir_all(&home);
}
#[test]
fn migrate_prompts_to_subfolder_from_dir_missing_dir_returns() {
let missing = scratch_dir("prompts-subfolder-missing");
migrate_prompts_to_subfolder_from_dir(&missing);
assert!(!missing.exists());
}
#[test]
fn migrate_prompts_to_subfolder_from_dir_migrates_legacy_layout() {
let dir = scratch_dir("prompts-subfolder-migrate");
std::fs::create_dir_all(&dir).unwrap();
std::fs::write(dir.join("loose.txt"), "ignore me").unwrap();
let legacy = dir.join("legacy-routine");
std::fs::create_dir_all(&legacy).unwrap();
std::fs::write(legacy.join("prompt.md"), "old composed body").unwrap();
std::fs::write(
legacy.join("routine.toml"),
"title = \"Legacy\"\nschedule = \"@daily\"\nagent = \"claude\"\nprompt = \"raw prompt\"\n",
)
.unwrap();
migrate_prompts_to_subfolder_from_dir(&dir);
assert!(
!legacy.join("prompt.md").exists(),
"top-level prompt.md should be moved"
);
assert_eq!(
std::fs::read_to_string(legacy.join("prompts").join("prompt.compiled.md")).unwrap(),
"old composed body"
);
assert_eq!(
std::fs::read_to_string(legacy.join("prompts").join("prompt.pure.md")).unwrap(),
"raw prompt"
);
std::fs::remove_dir_all(&dir).unwrap();
}
#[test]
fn migrate_prompts_to_subfolder_from_dir_skips_already_migrated() {
let dir = scratch_dir("prompts-subfolder-skip");
std::fs::create_dir_all(&dir).unwrap();
let routine = dir.join("already-migrated");
let prompts = routine.join("prompts");
std::fs::create_dir_all(&prompts).unwrap();
std::fs::write(prompts.join("prompt.compiled.md"), "compiled").unwrap();
std::fs::write(prompts.join("prompt.pure.md"), "pure").unwrap();
std::fs::write(
routine.join("routine.toml"),
"title = \"Already\"\nschedule = \"@daily\"\nagent = \"claude\"\n",
)
.unwrap();
migrate_prompts_to_subfolder_from_dir(&dir);
assert_eq!(
std::fs::read_to_string(prompts.join("prompt.compiled.md")).unwrap(),
"compiled"
);
assert_eq!(
std::fs::read_to_string(prompts.join("prompt.pure.md")).unwrap(),
"pure"
);
std::fs::remove_dir_all(&dir).unwrap();
}
#[test]
fn migrate_prompts_to_subfolder_from_dir_defaults_missing_legacy_prompt_to_empty() {
let dir = scratch_dir("prompts-subfolder-no-legacy");
std::fs::create_dir_all(&dir).unwrap();
let routine = dir.join("no-legacy-prompt");
std::fs::create_dir_all(&routine).unwrap();
std::fs::write(
routine.join("routine.toml"),
"title = \"No Legacy\"\nschedule = \"@daily\"\nagent = \"claude\"\n",
)
.unwrap();
migrate_prompts_to_subfolder_from_dir(&dir);
assert_eq!(
std::fs::read_to_string(routine.join("prompts").join("prompt.pure.md")).unwrap(),
""
);
std::fs::remove_dir_all(&dir).unwrap();
}
include!("migrate_prompts_to_subfolder_from_dir_skips_dir_without_routine_toml_tests.rs");