govctl 0.9.2

Project governance CLI for RFC, ADR, and Work Item management
use super::*;
use crate::config::Config;
use std::fs;

fn test_config(temp_dir: &tempfile::TempDir) -> Config {
    let mut config = Config {
        gov_root: temp_dir.path().join("gov"),
        ..Config::default()
    };
    config.paths.docs_output = temp_dir.path().join("docs");
    config
}

#[test]
fn execute_ops_removes_created_files_when_later_apply_fails()
-> Result<(), Box<dyn std::error::Error>> {
    let temp_dir = tempfile::tempdir()?;
    let config = test_config(&temp_dir);
    fs::create_dir_all(&config.gov_root)?;
    let created = config.gov_root.join("created.txt");
    let bad_target = config.gov_root.join("bad-target");
    fs::create_dir_all(&bad_target)?;

    let result = execute_ops(
        &config,
        &[
            FileOp::Write {
                path: created.clone(),
                content: "created".to_string(),
            },
            FileOp::Write {
                path: bad_target,
                content: "cannot replace directory".to_string(),
            },
        ],
    );

    assert!(result.is_err());
    assert!(
        !created.exists(),
        "created migration target should be removed on rollback"
    );
    Ok(())
}

#[test]
fn execute_ops_restores_modified_and_deleted_files_when_later_apply_fails()
-> Result<(), Box<dyn std::error::Error>> {
    let temp_dir = tempfile::tempdir()?;
    let config = test_config(&temp_dir);
    fs::create_dir_all(&config.gov_root)?;
    let modified = config.gov_root.join("modified.txt");
    let deleted = config.gov_root.join("deleted.txt");
    let bad_target = config.gov_root.join("bad-target");
    fs::write(&modified, "old")?;
    fs::write(&deleted, "gone")?;
    fs::create_dir_all(&bad_target)?;

    let result = execute_ops(
        &config,
        &[
            FileOp::Write {
                path: modified.clone(),
                content: "new".to_string(),
            },
            FileOp::Delete {
                path: deleted.clone(),
            },
            FileOp::Write {
                path: bad_target,
                content: "cannot replace directory".to_string(),
            },
        ],
    );

    assert!(result.is_err());
    assert_eq!(fs::read_to_string(modified)?, "old");
    assert_eq!(fs::read_to_string(deleted)?, "gone");
    Ok(())
}