patchloom 0.8.0

Structured file editing library and CLI for AI agents: parser-backed JSON/YAML/TOML edits, AST-aware code operations, multi-file batching, markdown operations, and MCP server
Documentation
use super::*;

#[test]
fn test_agent_rules_outputs_markdown() {
    Command::cargo_bin("patchloom")
        .unwrap()
        .arg("agent-rules")
        .assert()
        .success()
        .stdout(predicates::str::contains("# Patchloom"))
        .stdout(predicates::str::contains(
            "## Batching (the main speed win)",
        ))
        .stdout(predicates::str::contains("## Structured edits"));
}

#[test]
fn test_agent_rules_includes_version() {
    let output = Command::cargo_bin("patchloom")
        .unwrap()
        .arg("agent-rules")
        .output()
        .unwrap();

    assert!(output.status.success());
    let stdout = String::from_utf8_lossy(&output.stdout);
    // Version from Cargo.toml is embedded in the output
    assert!(stdout.contains("Generated by patchloom v"));
    // Should not contain the raw template placeholder
    assert!(!stdout.contains("{{VERSION}}"));
}

#[test]
fn test_agent_rules_mode_cli_omits_mcp() {
    Command::cargo_bin("patchloom")
        .unwrap()
        .args(["agent-rules", "--mode", "cli"])
        .assert()
        .success()
        .stdout(predicates::str::contains("## Batching"))
        .stdout(predicates::str::contains("## Structured edits"))
        .stdout(predicates::str::contains("## MCP mode").not());
}

#[test]
fn test_agent_rules_mode_mcp_omits_cli() {
    Command::cargo_bin("patchloom")
        .unwrap()
        .args(["agent-rules", "--mode", "mcp"])
        .assert()
        .success()
        .stdout(predicates::str::contains("## MCP mode"))
        // MCP mode must not mention batch/transaction tools or CLI concepts
        .stdout(predicates::str::contains("batch({\"operations\":").not())
        .stdout(predicates::str::contains("transaction({\"operations\":").not())
        .stdout(predicates::str::contains("search_replace").not())
        .stdout(predicates::str::contains("run_terminal_command").not())
        .stdout(predicates::str::contains("## Exit codes").not())
        .stdout(predicates::str::contains("--apply").not())
        .stdout(predicates::str::contains("--check").not())
        // CLI-only h2 sections must be absent
        .stdout(predicates::str::contains("\n## Batching").not())
        .stdout(predicates::str::contains("\n## Structured edits").not());
}

#[test]
fn test_agent_rules_platform_linux_omits_windows() {
    Command::cargo_bin("patchloom")
        .unwrap()
        .args(["agent-rules", "--platform", "linux"])
        .assert()
        .success()
        .stdout(predicates::str::contains("<<'EOF'"))
        .stdout(predicates::str::contains("batch ops.txt").not());
}

#[test]
fn test_agent_rules_platform_windows_omits_heredoc() {
    Command::cargo_bin("patchloom")
        .unwrap()
        .args(["agent-rules", "--platform", "windows"])
        .assert()
        .success()
        .stdout(predicates::str::contains("batch ops.txt"))
        .stdout(predicates::str::contains("<<'EOF'").not());
}

#[test]
fn test_agent_rules_mode_and_platform_compose() {
    // --mode mcp should have no CLI sections regardless of platform
    Command::cargo_bin("patchloom")
        .unwrap()
        .args(["agent-rules", "--mode", "mcp", "--platform", "windows"])
        .assert()
        .success()
        .stdout(predicates::str::contains("## MCP mode"))
        .stdout(predicates::str::contains("batch({\"operations\":").not())
        .stdout(predicates::str::contains("transaction({\"operations\":").not())
        .stdout(predicates::str::contains("\n## Batching").not())
        .stdout(predicates::str::contains("batch ops.txt").not())
        .stdout(predicates::str::contains("## Exit codes").not());
}

// ---------------------------------------------------------------------------
// init command
// ---------------------------------------------------------------------------

#[test]
fn test_agents_doc_project_inventory_matches_repo_state() {
    let agents = fs::read_to_string(repo_root().join("AGENTS.md")).unwrap();

    assert!(
        agents.contains(
            "cmd/mod.rs           Command enum (clap Subcommand), dispatch(), built-in agent-rules"
        ),
        "AGENTS.md should describe the current agent-rules implementation location"
    );
    assert!(
        agents.contains(
            "25 operation types including all doc/md/replace/tidy/file/patch/read/search ops"
        ),
        "AGENTS.md should describe the current tx operation count"
    );
}

// ── binary file handling ─────────────────────────────────────────────