sheeter-engine 0.4.0

A CLI tool for converting data files between formats. v0.1.0 supports CSV <-> JSON.
Documentation
use assert_cmd::Command;
use std::fs;
use tempfile::tempdir;

fn run(sub: &str, input: &str, in_ext: &str, out_ext: &str) -> Result<String, String> {
    let dir = tempdir().unwrap();
    let inp = dir.path().join(format!("in.{in_ext}"));
    let out = dir.path().join(format!("out.{out_ext}"));
    fs::write(&inp, input).unwrap();
    let result = Command::cargo_bin("sheeter")
        .unwrap()
        .args([sub, inp.to_str().unwrap(), out.to_str().unwrap()])
        .output()
        .unwrap();
    if !result.status.success() {
        return Err(String::from_utf8_lossy(&result.stderr).to_string());
    }
    Ok(fs::read_to_string(out).unwrap())
}

#[test]
fn xml_roundtrips_via_json() {
    let xml = "<r><a>1</a><a>2</a></r>";
    let json = run("xml-to-json", xml, "xml", "json").unwrap();
    assert_eq!(json, r#"{"r":{"a":["1","2"]}}"#);
}

#[test]
fn csv_to_xml_wraps_in_root() {
    let xml = run("csv-to-xml", "name\nAlice", "csv", "xml").unwrap();
    assert!(xml.contains("<root>"));
    assert!(xml.contains("<item>"));
    assert!(xml.contains("<name>Alice</name>"));
}

#[test]
fn xml_to_csv_extracts_tabular() {
    let xml = "<root><item><name>Alice</name><age>30</age></item></root>";
    let csv = run("xml-to-csv", xml, "xml", "csv").unwrap();
    assert_eq!(csv, "name,age\nAlice,30\n");
}

#[test]
fn yaml_to_xml_via_hub() {
    let yaml = "- name: Alice\n  age: 30\n";
    let xml = run("yaml-to-xml", yaml, "yaml", "xml").unwrap();
    assert!(xml.contains("<name>Alice</name>"));
}

#[test]
fn xml_attributes_preserved() {
    let xml = "<r><item id=\"1\">Alice</item></r>";
    let json = run("xml-to-json", xml, "xml", "json").unwrap();
    assert!(json.contains("\"@id\":\"1\""));
    assert!(json.contains("\"#text\":\"Alice\""));
}

#[test]
fn xml_to_csv_rejects_scalar_root() {
    let xml = "<r>just text</r>";
    let err = run("xml-to-csv", xml, "xml", "csv").unwrap_err();
    assert!(err.contains("tabular"), "unexpected: {err}");
}

#[test]
fn xml_nested_single_record_is_one_row() {
    let xml = "<r><a><b>1</b></a></r>";
    let csv = run("xml-to-csv", xml, "xml", "csv").unwrap();
    assert_eq!(
        csv,
        "b
1
"
    );
}