atomr-config 0.3.1

Layered HOCON-style configuration for atomr — `include`, `${path}` substitution, `${?ENV}`, dotted keys, arrays.
Documentation
//! Phase 2 — HOCON config end-to-end.
//!
//! Verifies that a HOCON document with dotted keys, nested objects,
//! includes, comments, and substitutions feeds into `Config` and
//! that all the get_* accessors work as expected.

use atomr_config::Config;
use std::fs;

#[test]
fn config_from_hocon_str_with_substitution_and_arrays() {
    let src = r#"
        # akka-style HOCON
        akka {
          actor.provider = "local"
          actor.dispatchers = ["default", "io"]
          remote.host = "10.0.0.1"
          remote.port = 7355
          remote.tcp = "akka.tcp://"${akka.remote.host}":"${akka.remote.port}
        }
    "#;
    // The remote.tcp line uses string concat which our subset doesn't
    // support yet — check just the subbed scalar form below.
    let simpler = r#"
        akka.actor.provider = "local"
        akka.actor.dispatchers = ["default", "io"]
        akka.remote.host = "10.0.0.1"
        akka.remote.port = 7355
        akka.remote.host_alias = ${akka.remote.host}
    "#;
    let _ = src;

    let cfg = Config::from_hocon_str(simpler).expect("parse hocon");
    assert_eq!(cfg.get_string("akka.actor.provider").unwrap(), "local");
    assert_eq!(cfg.get_int("akka.remote.port").unwrap(), 7355);
    assert_eq!(cfg.get_string("akka.remote.host_alias").unwrap(), "10.0.0.1");
}

#[test]
fn config_from_hocon_file_resolves_includes() {
    let dir = tempdir();
    let inc_path = dir.join("inc.conf");
    fs::write(&inc_path, "akka.actor.provider = \"remote\"").unwrap();
    let main_path = dir.join("main.conf");
    fs::write(&main_path, format!("include \"{}\"\nakka.actor.dispatcher = \"io\"\n", "inc.conf")).unwrap();

    let cfg = Config::from_hocon_file(&main_path).expect("parse main + include");
    assert_eq!(cfg.get_string("akka.actor.provider").unwrap(), "remote");
    assert_eq!(cfg.get_string("akka.actor.dispatcher").unwrap(), "io");
}

#[test]
fn missing_substitution_propagates_via_config_error() {
    let r = Config::from_hocon_str("a = ${nope}");
    assert!(matches!(r, Err(atomr_config::ConfigError::Hocon(_))));
}

fn tempdir() -> std::path::PathBuf {
    let mut p = std::env::temp_dir();
    let suffix = format!(
        "atomr-hocon-{}",
        std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_nanos()
    );
    p.push(suffix);
    fs::create_dir_all(&p).unwrap();
    p
}