chore(release): prepare public source release
This commit is contained in:
@@ -0,0 +1,247 @@
|
||||
//! Integration tests for the `cjson` command.
|
||||
|
||||
use std::{
|
||||
fs,
|
||||
path::PathBuf,
|
||||
sync::atomic::{AtomicU64, Ordering},
|
||||
};
|
||||
|
||||
use assert_cmd::Command;
|
||||
use predicates::prelude::*;
|
||||
use serde_json::Value;
|
||||
|
||||
fn cargo_command() -> Command {
|
||||
Command::cargo_bin("cjson").expect("binary")
|
||||
}
|
||||
|
||||
fn cargo_binary() -> PathBuf {
|
||||
assert_cmd::cargo::cargo_bin("cjson")
|
||||
}
|
||||
|
||||
fn powershell_command(script: String) -> Command {
|
||||
let mut command = Command::new("pwsh");
|
||||
command.args(["-NoProfile", "-Command"]).arg(script);
|
||||
command
|
||||
}
|
||||
|
||||
fn ps_quote(value: impl std::fmt::Display) -> String {
|
||||
format!("'{}'", value.to_string().replace('\'', "''"))
|
||||
}
|
||||
|
||||
fn workspace_root() -> PathBuf {
|
||||
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
|
||||
.join("..")
|
||||
.join("..")
|
||||
}
|
||||
|
||||
fn fixture(path: &str) -> PathBuf {
|
||||
let fixture = workspace_root().join("fixtures").join(path);
|
||||
assert!(
|
||||
fixture.exists(),
|
||||
"missing fixture `{path}` at {}",
|
||||
fixture.display()
|
||||
);
|
||||
fixture
|
||||
}
|
||||
|
||||
fn json_stdout(output: &[u8]) -> Value {
|
||||
serde_json::from_slice(output).unwrap_or_else(|error| {
|
||||
panic!(
|
||||
"stdout should be valid JSON: {error}\n{}",
|
||||
String::from_utf8_lossy(output)
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
struct TempTestDir {
|
||||
path: PathBuf,
|
||||
}
|
||||
|
||||
impl TempTestDir {
|
||||
fn path(&self) -> &std::path::Path {
|
||||
&self.path
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for TempTestDir {
|
||||
fn drop(&mut self) {
|
||||
let _ = fs::remove_dir_all(&self.path);
|
||||
}
|
||||
}
|
||||
|
||||
fn temp_test_dir(name: &str) -> TempTestDir {
|
||||
static NEXT_ID: AtomicU64 = AtomicU64::new(0);
|
||||
|
||||
loop {
|
||||
let unique = NEXT_ID.fetch_add(1, Ordering::Relaxed);
|
||||
let path =
|
||||
std::env::temp_dir().join(format!("cjson-{}-{name}-{unique}", std::process::id()));
|
||||
match fs::create_dir(&path) {
|
||||
Ok(()) => return TempTestDir { path },
|
||||
Err(error) if error.kind() == std::io::ErrorKind::AlreadyExists => {}
|
||||
Err(error) => panic!("temp test dir: {error}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compacts_json_file_in_text_mode() {
|
||||
let output = cargo_command()
|
||||
.arg(fixture("cjson/sample.json"))
|
||||
.assert()
|
||||
.success()
|
||||
.get_output()
|
||||
.stdout
|
||||
.clone();
|
||||
|
||||
let compacted: Value = json_stdout(&output);
|
||||
assert_eq!(
|
||||
compacted["name"],
|
||||
"Ada",
|
||||
"stdout={}",
|
||||
String::from_utf8_lossy(&output)
|
||||
);
|
||||
assert_eq!(
|
||||
compacted["a"]["x"],
|
||||
1,
|
||||
"stdout={}",
|
||||
String::from_utf8_lossy(&output)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sort_keys_reorders_objects_recursively() {
|
||||
cargo_command()
|
||||
.arg("--sort-keys")
|
||||
.write_stdin(
|
||||
"{\"z\":3,\"a\":{\"y\":2,\"x\":1},\"items\":[{\"b\":2,\"a\":1}],\"name\":\"Ada\"}",
|
||||
)
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(
|
||||
"{\"a\":{\"x\":1,\"y\":2},\"items\":[{\"a\":1,\"b\":2}],\"name\":\"Ada\",\"z\":3}\n",
|
||||
);
|
||||
}
|
||||
#[test]
|
||||
fn explicit_path_wins_over_piped_stdin_noise() {
|
||||
cargo_command()
|
||||
.arg(fixture("cjson/sample.json"))
|
||||
.write_stdin("not json from upstream pipeline")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(predicate::str::contains("\"name\":\"Ada\""));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn json_wrapper_reports_jsonl_documents() {
|
||||
let output = cargo_command()
|
||||
.arg("--input-format")
|
||||
.arg("jsonl")
|
||||
.arg("--sort-keys")
|
||||
.arg("--json")
|
||||
.arg(fixture("cjson/records.jsonl"))
|
||||
.assert()
|
||||
.success()
|
||||
.get_output()
|
||||
.stdout
|
||||
.clone();
|
||||
|
||||
let payload = json_stdout(&output);
|
||||
assert_eq!(
|
||||
payload["format"],
|
||||
"jsonl",
|
||||
"stdout={}",
|
||||
String::from_utf8_lossy(&output)
|
||||
);
|
||||
assert_eq!(
|
||||
payload["documents"],
|
||||
2,
|
||||
"stdout={}",
|
||||
String::from_utf8_lossy(&output)
|
||||
);
|
||||
assert!(
|
||||
payload["text"]
|
||||
.as_str()
|
||||
.is_some_and(|text| text.contains("\"event\":\"login\",\"ok\":true")),
|
||||
"stdout={}",
|
||||
String::from_utf8_lossy(&output)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn auto_mode_treats_explicit_jsonl_and_ndjson_paths_as_line_streams() {
|
||||
let temp = temp_test_dir("auto-jsonl-paths");
|
||||
let jsonl = temp.path().join("single.jsonl");
|
||||
let ndjson = temp.path().join("single.ndjson");
|
||||
fs::write(&jsonl, "{\"ok\":true}\n").expect("jsonl fixture");
|
||||
fs::write(&ndjson, "{\"ok\":true}\n").expect("ndjson fixture");
|
||||
|
||||
for path in [&jsonl, &ndjson] {
|
||||
let mut command = cargo_command();
|
||||
command
|
||||
.arg("--json")
|
||||
.arg(path)
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(predicate::str::contains("\"format\":\"jsonl\""))
|
||||
.stdout(predicate::str::contains("\"documents\":1"));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn supports_powershell_pipeline() {
|
||||
let binary = cargo_binary();
|
||||
let input = fixture("cjson/records.jsonl");
|
||||
let script = format!(
|
||||
"[System.IO.File]::ReadLines({}) | & {} --input-format jsonl --sort-keys",
|
||||
ps_quote(input.display()),
|
||||
ps_quote(binary.display())
|
||||
);
|
||||
|
||||
powershell_command(script)
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(predicate::str::contains(
|
||||
"{\"event\":\"login\",\"ok\":true}",
|
||||
))
|
||||
.stdout(predicate::str::contains(
|
||||
"{\"event\":\"logout\",\"ok\":false}",
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn accepts_single_stdin_path_stream_in_lines_mode() {
|
||||
cargo_command()
|
||||
.args(["--input-format", "lines"])
|
||||
.write_stdin(format!("{}\n", fixture("cjson/sample.json").display()))
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(predicate::str::contains("\"name\":\"Ada\""));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lines_mode_accepts_windows_paths_with_quotes_and_spaces() {
|
||||
let temp = temp_test_dir("quoted path");
|
||||
let path = temp.path().join("Ada's sample.json");
|
||||
fs::write(&path, "{\"name\":\"Ada\",\"ok\":true}\n").expect("quoted path fixture");
|
||||
|
||||
cargo_command()
|
||||
.args(["--input-format", "lines"])
|
||||
.write_stdin(format!("{}\n", path.display()))
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(predicate::str::contains("\"name\":\"Ada\""));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn help_includes_examples_and_sort_keys_flag() {
|
||||
cargo_command()
|
||||
.arg("--help")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(predicate::str::contains("--sort-keys"))
|
||||
.stdout(predicate::str::contains(
|
||||
"bat --style=plain --paging=never .\\fixtures\\cjson\\records.jsonl",
|
||||
))
|
||||
.stdout(predicate::str::contains("ConvertFrom-Json"));
|
||||
}
|
||||
Reference in New Issue
Block a user