forjar 1.4.2

Rust-native Infrastructure as Code — bare-metal first, BLAKE3 state, provenance tracing
Documentation
//! Tests: Show, explain, compare, template.

#![allow(unused_imports)]
use super::diff_cmd::*;
use super::helpers::*;
use super::helpers_state::*;
use super::helpers_time::*;
use super::observe::*;
use super::show::*;
use super::test_fixtures::*;
use crate::core::types::ProvenanceEvent;
use crate::core::{codegen, executor, migrate, parser, planner, resolver, secrets, state, types};
use crate::transport;
use crate::tripwire::{anomaly, drift, eventlog, tracer};
use std::collections::HashMap;
use std::path::{Path, PathBuf};

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

    #[test]
    fn test_fj017_show_full_config() {
        let dir = tempfile::tempdir().unwrap();
        let config = dir.path().join("forjar.yaml");
        std::fs::write(
            &config,
            r#"
version: "1.0"
name: show-test
params:
  env: staging
machines:
  m1:
    hostname: box
    addr: 1.2.3.4
resources:
  conf:
    type: file
    machine: m1
    path: /etc/{{params.env}}.conf
    content: "env={{params.env}}"
"#,
        )
        .unwrap();
        // Should resolve templates without error
        cmd_show(&config, None, false).unwrap();
    }

    #[test]
    fn test_fj017_show_specific_resource() {
        let dir = tempfile::tempdir().unwrap();
        let config = dir.path().join("forjar.yaml");
        std::fs::write(
            &config,
            r#"
version: "1.0"
name: show-test
machines:
  m1:
    hostname: box
    addr: 1.2.3.4
resources:
  pkg:
    type: package
    machine: m1
    provider: apt
    packages: [curl]
  conf:
    type: file
    machine: m1
    path: /etc/test
    content: hello
"#,
        )
        .unwrap();
        // Show specific resource
        cmd_show(&config, Some("conf"), false).unwrap();
    }

    #[test]
    fn test_fj017_show_missing_resource() {
        let dir = tempfile::tempdir().unwrap();
        let config = dir.path().join("forjar.yaml");
        std::fs::write(
            &config,
            r#"
version: "1.0"
name: show-test
machines:
  m1:
    hostname: box
    addr: 1.2.3.4
resources:
  pkg:
    type: package
    machine: m1
    provider: apt
    packages: [curl]
"#,
        )
        .unwrap();
        let result = cmd_show(&config, Some("nonexistent"), false);
        assert!(result.is_err());
        assert!(result.unwrap_err().contains("not found"));
    }

    #[test]
    fn test_fj054_policy_hooks_parsed() {
        let yaml = r#"
version: "1.0"
name: test
machines: {}
resources: {}
policy:
  failure: stop_on_first
  pre_apply: "echo before"
  post_apply: "echo after"
"#;
        let config: types::ForjarConfig = serde_yaml_ng::from_str(yaml).unwrap();
        assert_eq!(config.policy.pre_apply.as_deref(), Some("echo before"));
        assert_eq!(config.policy.post_apply.as_deref(), Some("echo after"));
    }

    // ── forjar diff tests ──────────────────────────────────────────

    #[test]
    fn test_fj017_show_json_output() {
        let dir = tempfile::tempdir().unwrap();
        let config = dir.path().join("forjar.yaml");
        std::fs::write(
            &config,
            r#"
version: "1.0"
name: json-show-test
machines:
  m1:
    hostname: box
    addr: 1.2.3.4
resources:
  pkg:
    type: package
    machine: m1
    provider: apt
    packages: [curl]
"#,
        )
        .unwrap();
        // JSON output should succeed
        cmd_show(&config, None, true).unwrap();
    }

    #[test]
    fn test_fj017_show_specific_resource_json() {
        let dir = tempfile::tempdir().unwrap();
        let config = dir.path().join("forjar.yaml");
        std::fs::write(
            &config,
            r#"
version: "1.0"
name: show-test
machines:
  m1:
    hostname: box
    addr: 1.2.3.4
resources:
  pkg:
    type: package
    machine: m1
    provider: apt
    packages: [curl]
"#,
        )
        .unwrap();
        cmd_show(&config, Some("pkg"), true).unwrap();
    }

    // ── Fmt edge cases ─────────────────────────────────────────

    #[test]
    fn test_fj131_cmd_diff_json_output() {
        let from_dir = tempfile::tempdir().unwrap();
        let to_dir = tempfile::tempdir().unwrap();

        // Both have web machine
        let from_lock = types::StateLock {
            schema: "1.0".to_string(),
            machine: "web".to_string(),
            hostname: "web-box".to_string(),
            generated_at: "2026-02-25T00:00:00Z".to_string(),
            generator: "forjar 0.1.0".to_string(),
            blake3_version: "1.8".to_string(),
            resources: indexmap::IndexMap::new(),
        };
        state::save_lock(from_dir.path(), &from_lock).unwrap();
        state::save_lock(to_dir.path(), &from_lock).unwrap();

        // JSON output should not error
        cmd_diff(from_dir.path(), to_dir.path(), None, None, true).unwrap();
    }

    #[test]
    fn test_fj131_cmd_anomaly_json_output() {
        let dir = tempfile::tempdir().unwrap();
        let machine_dir = dir.path().join("web");
        std::fs::create_dir_all(&machine_dir).unwrap();

        let events = [
            r#"{"ts":"2026-02-25T00:00:00Z","event":"resource_converged","machine":"web","resource":"pkg","duration_seconds":1.0,"hash":"blake3:abc"}"#,
            r#"{"ts":"2026-02-25T01:00:00Z","event":"resource_failed","machine":"web","resource":"pkg","error":"timeout"}"#,
        ];
        std::fs::write(machine_dir.join("events.jsonl"), events.join("\n")).unwrap();

        cmd_anomaly(dir.path(), None, 1, true).unwrap();
    }
}