config-forge 0.1.0

A CLI tool for converting, inspecting, and validating configuration files.
Documentation
use assert_cmd::Command;
use predicates::prelude::*;
use tempfile::tempdir;

#[test]
fn converts_json_to_yaml_file() {
    let dir = tempdir().unwrap();
    let input = dir.path().join("input.json");
    let output = dir.path().join("output.yaml");
    std::fs::write(
        &input,
        r#"{"server":{"host":"localhost","port":8080},"debug":true}"#,
    )
    .unwrap();

    Command::cargo_bin("config-forge")
        .unwrap()
        .args([
            "convert",
            input.to_str().unwrap(),
            "-o",
            output.to_str().unwrap(),
        ])
        .assert()
        .success();

    let rendered = std::fs::read_to_string(output).unwrap();
    assert!(rendered.contains("server:"));
    assert!(rendered.contains("host: localhost"));
    assert!(rendered.contains("port: 8080"));
    assert!(rendered.contains("debug: true"));
}

#[test]
fn converts_toml_to_json_stdout() {
    let dir = tempdir().unwrap();
    let input = dir.path().join("input.toml");
    std::fs::write(&input, "[server]\nhost = \"localhost\"\nport = 8080\n").unwrap();

    Command::cargo_bin("config-forge")
        .unwrap()
        .args(["convert", input.to_str().unwrap(), "--to", "json"])
        .assert()
        .success()
        .stdout(predicate::str::contains(r#""server""#))
        .stdout(predicate::str::contains(r#""host": "localhost""#))
        .stdout(predicate::str::contains(r#""port": 8080"#));
}

#[test]
fn converts_yaml_to_toml_file() {
    let dir = tempdir().unwrap();
    let input = dir.path().join("input.yaml");
    let output = dir.path().join("output.toml");
    std::fs::write(&input, "server:\n  host: localhost\n  port: 8080\n").unwrap();

    Command::cargo_bin("config-forge")
        .unwrap()
        .args([
            "convert",
            input.to_str().unwrap(),
            "-o",
            output.to_str().unwrap(),
        ])
        .assert()
        .success();

    let rendered = std::fs::read_to_string(output).unwrap();
    assert!(rendered.contains("[server]"));
    assert!(rendered.contains("host = \"localhost\""));
    assert!(rendered.contains("port = 8080"));
}

#[test]
fn inspect_reports_detected_format_and_root() {
    let dir = tempdir().unwrap();
    let input = dir.path().join("input.yaml");
    std::fs::write(&input, "items:\n  - one\n  - two\n").unwrap();

    Command::cargo_bin("config-forge")
        .unwrap()
        .args(["inspect", input.to_str().unwrap()])
        .assert()
        .success()
        .stdout(predicate::str::contains("format: yaml"))
        .stdout(predicate::str::contains("root: object"));
}

#[test]
fn stdout_conversion_requires_to_format() {
    let dir = tempdir().unwrap();
    let input = dir.path().join("input.json");
    std::fs::write(&input, r#"{"ok":true}"#).unwrap();

    Command::cargo_bin("config-forge")
        .unwrap()
        .args(["convert", input.to_str().unwrap()])
        .assert()
        .failure()
        .stderr(predicate::str::contains(
            "--to is required when --output is not provided",
        ));
}

#[test]
fn toml_output_requires_object_root() {
    let dir = tempdir().unwrap();
    let input = dir.path().join("input.json");
    let output = dir.path().join("output.toml");
    std::fs::write(&input, r#"[1,2,3]"#).unwrap();

    Command::cargo_bin("config-forge")
        .unwrap()
        .args([
            "convert",
            input.to_str().unwrap(),
            "-o",
            output.to_str().unwrap(),
        ])
        .assert()
        .failure()
        .stderr(predicate::str::contains(
            "TOML output requires an object at the document root",
        ));
}

#[test]
fn rejects_json_unsigned_integer_over_i64_range() {
    let dir = tempdir().unwrap();
    let input = dir.path().join("input.json");
    std::fs::write(&input, r#"{"too_large":18446744073709551615}"#).unwrap();

    Command::cargo_bin("config-forge")
        .unwrap()
        .args(["convert", input.to_str().unwrap(), "--to", "yaml"])
        .assert()
        .failure()
        .stderr(predicate::str::contains(
            "JSON unsigned integer exceeds the supported i64 range",
        ));
}