//! Integration tests for the `ison` command. //! //! The table block expectations track public examples on and //! . The v1 CLI tests a deterministic JSON-family //! subset that is stable enough for local conversion workflows. use std::fs; use std::path::{Path, PathBuf}; use assert_cmd::Command; use predicates::prelude::*; use tempfile::tempdir; fn cargo_command() -> Command { Command::cargo_bin("ison").expect("binary") } fn fixture_path(relative: &str) -> PathBuf { let fixture = Path::new(env!("CARGO_MANIFEST_DIR")) .parent() .and_then(Path::parent) .expect("workspace root") .join(relative); assert!( fixture.exists(), "missing fixture `{relative}` at {}", fixture.display() ); fixture } #[test] fn help_mentions_ison_examples_and_interop() { cargo_command() .arg("--help") .assert() .success() .stdout(predicate::str::contains("Convert between JSON and ISON")) .stdout(predicate::str::contains("ISON block syntax")) .stdout(predicate::str::contains("--from ")) .stdout(predicate::str::contains("--to ")); } #[test] fn json_path_encodes_to_ison_table_block() { cargo_command() .args(["--from", "json", "--to", "ison"]) .arg(fixture_path("fixtures/json-family/ison/users.json")) .assert() .success() .stdout(predicate::str::contains( "table.users\nid:int name:str active:bool\n1 Ada true\n2 Bob false\n", )); } #[test] fn ison_path_decodes_to_json() { cargo_command() .args(["--from", "ison", "--to", "json"]) .arg(fixture_path("fixtures/json-family/ison/users.ison")) .assert() .success() .stdout(predicate::str::contains("\"users\": [")) .stdout(predicate::str::contains("\"name\": \"Ada\"")) .stdout(predicate::str::contains("\"active\": false")); } #[test] fn stdin_json_auto_encodes_to_ison() { cargo_command() .write_stdin("{\"users\":[{\"id\":1,\"name\":\"Ada\",\"active\":true}]}") .assert() .success() .stdout(predicate::str::contains("table.users")) .stdout(predicate::str::contains("1 Ada true")); } #[test] fn format_toon_wraps_conversion_for_ai_pipelines() { cargo_command() .args(["--format", "toon", "--from", "json", "--to", "ison"]) .arg(fixture_path("fixtures/json-family/ison/users.json")) .assert() .success() .stdout(predicate::str::contains("format: ison")) .stdout(predicate::str::contains("text:")) .stdout(predicate::str::contains("table.users")); } #[test] fn invalid_ison_reports_line_number() { let temp = tempdir().expect("tempdir"); let path = temp.path().join("broken.ison"); fs::write(&path, "table.users\nid:int name:str\n1\n").expect("fixture"); cargo_command() .args(["--from", "ison", "--to", "json"]) .arg(&path) .assert() .failure() .code(2) .stderr(predicate::str::contains("line 3")) .stderr(predicate::str::contains("expected 2 values")); } #[test] fn json_path_with_spaces_encodes_to_ison() { let temp = tempdir().expect("tempdir"); let path = temp.path().join("users with spaces.json"); fs::write(&path, r#"{"users":[{"id":1,"name":"Ada","active":true}]}"#) .expect("spaced path fixture"); cargo_command() .args(["--from", "json", "--to", "ison"]) .arg(&path) .assert() .success() .stdout(predicate::str::contains("table.users")) .stdout(predicate::str::contains("1 Ada true")); }