forjar 1.4.0

Rust-native Infrastructure as Code — bare-metal first, BLAKE3 state, provenance tracing
Documentation
//! Tests: Coverage for graph_core, graph_cross, graph_analysis.

use super::graph_analysis::*;
use super::graph_core::*;
use super::graph_cross::*;
use std::io::Write;

#[cfg(test)]
mod tests {
    use super::*;

    fn write_temp_config(yaml: &str) -> tempfile::NamedTempFile {
        let mut f = tempfile::NamedTempFile::new().unwrap();
        f.write_all(yaml.as_bytes()).unwrap();
        f.flush().unwrap();
        f
    }

    fn config_with_deps() -> String {
        "version: \"1.0\"\nname: t\nmachines:\n  m:\n    hostname: m\n    addr: 127.0.0.1\nresources:\n  a:\n    type: file\n    machine: m\n    path: /tmp/a\n    content: a\n  b:\n    type: file\n    machine: m\n    path: /tmp/b\n    content: b\n    depends_on: [a]\n  c:\n    type: file\n    machine: m\n    path: /tmp/c\n    content: c\n    depends_on: [b]\n".to_string()
    }

    fn config_no_deps() -> String {
        "version: \"1.0\"\nname: t\nmachines:\n  m:\n    hostname: m\n    addr: 127.0.0.1\nresources:\n  x:\n    type: file\n    machine: m\n    path: /tmp/x\n    content: x\n  y:\n    type: file\n    machine: m\n    path: /tmp/y\n    content: y\n".to_string()
    }

    fn config_diamond() -> String {
        "version: \"1.0\"\nname: t\nmachines:\n  m:\n    hostname: m\n    addr: 127.0.0.1\nresources:\n  root:\n    type: file\n    machine: m\n    path: /tmp/root\n    content: r\n  left:\n    type: file\n    machine: m\n    path: /tmp/left\n    content: l\n    depends_on: [root]\n  right:\n    type: file\n    machine: m\n    path: /tmp/right\n    content: r\n    depends_on: [root]\n  bottom:\n    type: file\n    machine: m\n    path: /tmp/bottom\n    content: b\n    depends_on: [left, right]\n".to_string()
    }

    fn config_single_resource() -> String {
        "version: \"1.0\"\nname: t\nmachines:\n  m:\n    hostname: m\n    addr: 127.0.0.1\nresources:\n  only:\n    type: file\n    machine: m\n    path: /tmp/only\n    content: x\n".to_string()
    }

    fn config_multi_machine() -> String {
        "version: \"1.0\"\nname: t\nmachines:\n  web:\n    hostname: web\n    addr: 10.0.0.1\n  db:\n    hostname: db\n    addr: 10.0.0.2\nresources:\n  app:\n    type: file\n    machine: web\n    path: /tmp/app\n    content: app\n  schema:\n    type: file\n    machine: db\n    path: /tmp/schema\n    content: schema\n  migrate:\n    type: file\n    machine: db\n    path: /tmp/migrate\n    content: mig\n    depends_on: [schema]\n  deploy:\n    type: file\n    machine: web\n    path: /tmp/deploy\n    content: dep\n    depends_on: [app, migrate]\n".to_string()
    }

    fn config_mixed_types() -> String {
        "version: \"1.0\"\nname: t\nmachines:\n  m:\n    hostname: m\n    addr: 127.0.0.1\nresources:\n  svc:\n    type: service\n    machine: m\n    name: mysvc\n  conf:\n    type: file\n    machine: m\n    path: /etc/myapp.conf\n    content: cfg\n    depends_on: [svc]\n  data:\n    type: file\n    machine: m\n    path: /tmp/data\n    content: d\n".to_string()
    }

    // ── cmd_graph_critical_path ──

    #[test]
    fn test_critical_path_with_chain() {
        let f = write_temp_config(&config_with_deps());
        let result = cmd_graph_critical_path(f.path());
        assert!(result.is_ok());
    }

    #[test]
    fn test_critical_path_no_deps() {
        let f = write_temp_config(&config_no_deps());
        let result = cmd_graph_critical_path(f.path());
        assert!(result.is_ok());
    }

    #[test]
    fn test_critical_path_diamond() {
        let f = write_temp_config(&config_diamond());
        let result = cmd_graph_critical_path(f.path());
        assert!(result.is_ok());
    }

    #[test]
    fn test_critical_path_single_resource() {
        let f = write_temp_config(&config_single_resource());
        let result = cmd_graph_critical_path(f.path());
        assert!(result.is_ok());
    }

    #[test]
    fn test_critical_path_multi_machine() {
        let f = write_temp_config(&config_multi_machine());
        let result = cmd_graph_critical_path(f.path());
        assert!(result.is_ok());
    }

    #[test]
    fn test_critical_path_mixed_types() {
        let f = write_temp_config(&config_mixed_types());
        let result = cmd_graph_critical_path(f.path());
        assert!(result.is_ok());
    }

    // ── cmd_graph_affected ──

    #[test]
    fn test_affected_root_resource() {
        let f = write_temp_config(&config_with_deps());
        let result = cmd_graph_affected(f.path(), "a");
        assert!(result.is_ok());
    }

    #[test]
    fn test_affected_middle_resource() {
        let f = write_temp_config(&config_with_deps());
        let result = cmd_graph_affected(f.path(), "b");
        assert!(result.is_ok());
    }

    #[test]
    fn test_affected_leaf_resource() {
        let f = write_temp_config(&config_with_deps());
        let result = cmd_graph_affected(f.path(), "c");
        assert!(result.is_ok());
    }

    #[test]
    fn test_affected_nonexistent_resource() {
        let f = write_temp_config(&config_with_deps());
        let result = cmd_graph_affected(f.path(), "nonexistent");
        assert!(result.is_err());
    }

    #[test]
    fn test_affected_no_deps() {
        let f = write_temp_config(&config_no_deps());
        let result = cmd_graph_affected(f.path(), "x");
        assert!(result.is_ok());
    }

    #[test]
    fn test_affected_diamond_root() {
        let f = write_temp_config(&config_diamond());
        let result = cmd_graph_affected(f.path(), "root");
        assert!(result.is_ok());
    }

    #[test]
    fn test_affected_diamond_branch() {
        let f = write_temp_config(&config_diamond());
        let result = cmd_graph_affected(f.path(), "left");
        assert!(result.is_ok());
    }

    #[test]
    fn test_affected_single_resource() {
        let f = write_temp_config(&config_single_resource());
        let result = cmd_graph_affected(f.path(), "only");
        assert!(result.is_ok());
    }

    // ── cmd_graph_reverse ──

    #[test]
    fn test_reverse_with_deps() {
        let f = write_temp_config(&config_with_deps());
        let result = cmd_graph_reverse(f.path());
        assert!(result.is_ok());
    }

    #[test]
    fn test_reverse_no_deps() {
        let f = write_temp_config(&config_no_deps());
        let result = cmd_graph_reverse(f.path());
        assert!(result.is_ok());
    }

    #[test]
    fn test_reverse_diamond() {
        let f = write_temp_config(&config_diamond());
        let result = cmd_graph_reverse(f.path());
        assert!(result.is_ok());
    }

    #[test]
    fn test_reverse_single_resource() {
        let f = write_temp_config(&config_single_resource());
        let result = cmd_graph_reverse(f.path());
        assert!(result.is_ok());
    }

    #[test]
    fn test_reverse_multi_machine() {
        let f = write_temp_config(&config_multi_machine());
        let result = cmd_graph_reverse(f.path());
        assert!(result.is_ok());
    }

    #[test]
    fn test_reverse_mixed_types() {
        let f = write_temp_config(&config_mixed_types());
        let result = cmd_graph_reverse(f.path());
        assert!(result.is_ok());
    }

    // ── cmd_graph_change_impact ──

    #[test]
    fn test_change_impact_root_text() {
        let f = write_temp_config(&config_with_deps());
        let result = cmd_graph_change_impact(f.path(), "a", false);
        assert!(result.is_ok());
    }

    #[test]
    fn test_change_impact_root_json() {
        let f = write_temp_config(&config_with_deps());
        let result = cmd_graph_change_impact(f.path(), "a", true);
        assert!(result.is_ok());
    }

    #[test]
    fn test_change_impact_leaf_text() {
        let f = write_temp_config(&config_with_deps());
        let result = cmd_graph_change_impact(f.path(), "c", false);
        assert!(result.is_ok());
    }

    #[test]
    fn test_change_impact_leaf_json() {
        let f = write_temp_config(&config_with_deps());
        let result = cmd_graph_change_impact(f.path(), "c", true);
        assert!(result.is_ok());
    }

    #[test]
    fn test_change_impact_middle_text() {
        let f = write_temp_config(&config_with_deps());
        let result = cmd_graph_change_impact(f.path(), "b", false);
        assert!(result.is_ok());
    }

    #[test]
    fn test_change_impact_middle_json() {
        let f = write_temp_config(&config_with_deps());
        let result = cmd_graph_change_impact(f.path(), "b", true);
        assert!(result.is_ok());
    }

    #[test]
    fn test_change_impact_nonexistent() {
        let f = write_temp_config(&config_with_deps());
        let result = cmd_graph_change_impact(f.path(), "nonexistent", false);
        assert!(result.is_err());
    }

    #[test]
    fn test_change_impact_no_deps_text() {
        let f = write_temp_config(&config_no_deps());
        let result = cmd_graph_change_impact(f.path(), "x", false);
        assert!(result.is_ok());
    }

    #[test]
    fn test_change_impact_no_deps_json() {
        let f = write_temp_config(&config_no_deps());
        let result = cmd_graph_change_impact(f.path(), "x", true);
        assert!(result.is_ok());
    }

    #[test]
    fn test_change_impact_diamond_root_json() {
        let f = write_temp_config(&config_diamond());
        let result = cmd_graph_change_impact(f.path(), "root", true);
        assert!(result.is_ok());
    }

    #[test]
    fn test_change_impact_diamond_root_text() {
        let f = write_temp_config(&config_diamond());
        let result = cmd_graph_change_impact(f.path(), "root", false);
        assert!(result.is_ok());
    }

    #[test]
    fn test_change_impact_multi_machine_json() {
        let f = write_temp_config(&config_multi_machine());
        let result = cmd_graph_change_impact(f.path(), "schema", true);
        assert!(result.is_ok());
    }

    // ── compute_change_impact (exercised through cmd_graph_change_impact) ──
    // The above tests already exercise compute_change_impact transitively.
    // Additional edge cases below target the BFS traversal paths explicitly.

    #[test]
    fn test_change_impact_single_resource_text() {
        let f = write_temp_config(&config_single_resource());
        let result = cmd_graph_change_impact(f.path(), "only", false);
        assert!(result.is_ok());
    }

    #[test]
    fn test_change_impact_single_resource_json() {
        let f = write_temp_config(&config_single_resource());
        let result = cmd_graph_change_impact(f.path(), "only", true);
        assert!(result.is_ok());
    }

    #[test]
    fn test_change_impact_diamond_branch_json() {
        let f = write_temp_config(&config_diamond());
        let result = cmd_graph_change_impact(f.path(), "left", true);
        assert!(result.is_ok());
    }

    #[test]
    fn test_change_impact_diamond_bottom_text() {
        let f = write_temp_config(&config_diamond());
        let result = cmd_graph_change_impact(f.path(), "bottom", false);
        assert!(result.is_ok());
    }

    // ── cmd_graph_resource_types ──

    #[test]
    fn test_resource_types_text() {
        let f = write_temp_config(&config_with_deps());
        let result = cmd_graph_resource_types(f.path(), false);
        assert!(result.is_ok());
    }

    #[test]
    fn test_resource_types_json() {
        let f = write_temp_config(&config_with_deps());
        let result = cmd_graph_resource_types(f.path(), true);
        assert!(result.is_ok());
    }

    #[test]
    fn test_resource_types_mixed_text() {
        let f = write_temp_config(&config_mixed_types());
        let result = cmd_graph_resource_types(f.path(), false);
        assert!(result.is_ok());
    }

    #[test]
    fn test_resource_types_mixed_json() {
        let f = write_temp_config(&config_mixed_types());
        let result = cmd_graph_resource_types(f.path(), true);
        assert!(result.is_ok());
    }

    #[test]
    fn test_resource_types_no_deps_text() {
        let f = write_temp_config(&config_no_deps());
        let result = cmd_graph_resource_types(f.path(), false);
        assert!(result.is_ok());
    }

    #[test]
    fn test_resource_types_no_deps_json() {
        let f = write_temp_config(&config_no_deps());
        let result = cmd_graph_resource_types(f.path(), true);
        assert!(result.is_ok());
    }

    #[test]
    fn test_resource_types_multi_machine_text() {
        let f = write_temp_config(&config_multi_machine());
        let result = cmd_graph_resource_types(f.path(), false);
        assert!(result.is_ok());
    }

    #[test]
    fn test_resource_types_multi_machine_json() {
        let f = write_temp_config(&config_multi_machine());
        let result = cmd_graph_resource_types(f.path(), true);
        assert!(result.is_ok());
    }

    #[test]
    fn test_resource_types_single_text() {
        let f = write_temp_config(&config_single_resource());
        let result = cmd_graph_resource_types(f.path(), false);
        assert!(result.is_ok());
    }

    #[test]
    fn test_resource_types_single_json() {
        let f = write_temp_config(&config_single_resource());
        let result = cmd_graph_resource_types(f.path(), true);
        assert!(result.is_ok());
    }
}