moadim 3.2.8

Loop engine for AI agents — routines over REST, MCP, and a built-in web UI
#![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 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-gitignore");
    std::fs::create_dir_all(&home).unwrap();
    let previous = std::env::var_os("MOADIM_HOME_OVERRIDE");
    // SAFETY: tests in this crate run single-threaded per binary.
    unsafe {
        std::env::set_var("MOADIM_HOME_OVERRIDE", &home);
    }
    body(&home);
    // SAFETY: single-threaded test execution.
    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);
}

fn make_routine(id: &str, title: &str) -> Routine {
    crate::test_fixtures::routine_fixture(id, title).build()
}

#[test]
fn write_routine_does_not_create_a_per_routine_gitignore() {
    with_override_home(|_home| {
        let id = "rs-gitignore-none-id";
        let title = "Rs Gitignore None Routine";
        let slug = slugify(title);
        write_routine(&make_routine(id, title)).unwrap();

        assert!(
            !crate::paths::routine_gitignore_path(&slug).exists(),
            "write_routine must no longer generate a per-routine .gitignore; \
             the config dir's root .gitignore covers routine dirs recursively"
        );
    });
}

#[test]
fn write_routine_leaves_a_legacy_per_routine_gitignore_untouched() {
    with_override_home(|_home| {
        let id = "rs-gitignore-keep-id";
        let title = "Rs Gitignore Keep Routine";
        let slug = slugify(title);
        std::fs::create_dir_all(crate::paths::routine_dir(&slug)).unwrap();
        // Simulate a file generated by an older daemon, including a user-added pattern.
        let legacy = "*.compiled.*\n*.local.*\n*.log\nrun.sh\nmy-custom-pattern\n";
        std::fs::write(crate::paths::routine_gitignore_path(&slug), legacy).unwrap();

        write_routine(&make_routine(id, title)).unwrap();

        let content = std::fs::read_to_string(crate::paths::routine_gitignore_path(&slug)).unwrap();
        assert_eq!(
            content, legacy,
            "an existing per-routine .gitignore must be left byte-for-byte untouched"
        );
    });
}