use std::fs;
use std::process::Command;
use tempfile::TempDir;
#[test]
fn test_cli_json_output_format() {
let temp_dir = TempDir::new().expect("Failed to create temp directory");
let test_file = temp_dir.path().join("test.bin");
fs::write(&test_file, b"Hello, World!").expect("Failed to write test file");
let magic_file = temp_dir.path().join("test.magic");
fs::write(&magic_file, "0 byte 72 Hello file\n").expect("Failed to write magic file");
let output = Command::new("cargo")
.args([
"run",
"--bin",
"rmagic",
"--",
test_file.to_str().unwrap(),
"--json",
"--magic-file",
magic_file.to_str().unwrap(),
])
.output()
.expect("Failed to execute command");
if !output.status.success() {
eprintln!(
"Command failed with stderr: {}",
String::from_utf8_lossy(&output.stderr)
);
panic!("Command failed with exit code: {:?}", output.status.code());
}
let stdout = String::from_utf8(output.stdout).expect("Invalid UTF-8 in stdout");
let json_value: serde_json::Value =
serde_json::from_str(&stdout).expect("Failed to parse JSON output");
assert!(json_value.is_object(), "Output should be a JSON object");
let json_obj = json_value.as_object().unwrap();
assert!(
json_obj.contains_key("matches"),
"JSON should contain 'matches' field"
);
let matches = json_obj["matches"]
.as_array()
.expect("'matches' should be an array");
if !matches.is_empty() {
let first_match = &matches[0];
assert!(first_match.is_object(), "Match should be a JSON object");
let match_obj = first_match.as_object().unwrap();
assert!(
match_obj.contains_key("text"),
"Match should contain 'text' field"
);
assert!(
match_obj.contains_key("offset"),
"Match should contain 'offset' field"
);
assert!(
match_obj.contains_key("value"),
"Match should contain 'value' field"
);
assert!(
match_obj.contains_key("tags"),
"Match should contain 'tags' field"
);
assert!(
match_obj.contains_key("score"),
"Match should contain 'score' field"
);
assert!(match_obj["text"].is_string(), "'text' should be a string");
assert!(
match_obj["offset"].is_number(),
"'offset' should be a number"
);
assert!(match_obj["value"].is_string(), "'value' should be a string");
assert!(match_obj["tags"].is_array(), "'tags' should be an array");
assert!(match_obj["score"].is_number(), "'score' should be a number");
}
}
#[test]
fn test_cli_json_output_no_matches() {
let temp_dir = TempDir::new().expect("Failed to create temp directory");
let test_file = temp_dir.path().join("test.bin");
fs::write(&test_file, b"Random binary data").expect("Failed to write test file");
let magic_file = temp_dir.path().join("test.magic");
fs::write(&magic_file, "0 byte 255 No match file\n").expect("Failed to write magic file");
let output = Command::new("cargo")
.args([
"run",
"--bin",
"rmagic",
"--",
test_file.to_str().unwrap(),
"--json",
"--magic-file",
magic_file.to_str().unwrap(),
])
.output()
.expect("Failed to execute command");
if !output.status.success() {
eprintln!(
"Command failed with stderr: {}",
String::from_utf8_lossy(&output.stderr)
);
panic!("Command failed with exit code: {:?}", output.status.code());
}
let stdout = String::from_utf8(output.stdout).expect("Invalid UTF-8 in stdout");
let json_value: serde_json::Value =
serde_json::from_str(&stdout).expect("Failed to parse JSON output");
assert!(json_value.is_object(), "Output should be a JSON object");
let json_obj = json_value.as_object().unwrap();
assert!(
json_obj.contains_key("matches"),
"JSON should contain 'matches' field"
);
let matches = json_obj["matches"]
.as_array()
.expect("'matches' should be an array");
if !matches.is_empty() {
assert_eq!(matches.len(), 1, "Should have exactly one fallback match");
let match_obj = matches[0].as_object().unwrap();
assert!(match_obj["text"].is_string(), "'text' should be a string");
}
}
#[test]
fn test_cli_json_output_validity() {
let temp_dir = TempDir::new().expect("Failed to create temp directory");
let test_file = temp_dir.path().join("test.txt");
fs::write(&test_file, "#!/bin/bash\necho 'Hello World'\n").expect("Failed to write test file");
let magic_file = temp_dir.path().join("test.magic");
fs::write(&magic_file, "0 byte 35 Bash script\n").expect("Failed to write magic file");
let output = Command::new("cargo")
.args([
"run",
"--bin",
"rmagic",
"--",
test_file.to_str().unwrap(),
"--json",
"--magic-file",
magic_file.to_str().unwrap(),
])
.output()
.expect("Failed to execute command");
if !output.status.success() {
eprintln!(
"Command failed with stderr: {}",
String::from_utf8_lossy(&output.stderr)
);
panic!("Command failed with exit code: {:?}", output.status.code());
}
let stdout = String::from_utf8(output.stdout).expect("Invalid UTF-8 in stdout");
let json_value: serde_json::Value =
serde_json::from_str(&stdout).expect("Failed to parse JSON output");
let serialized =
serde_json::to_string(&json_value).expect("Failed to serialize JSON back to string");
let _reparsed: serde_json::Value =
serde_json::from_str(&serialized).expect("Failed to reparse serialized JSON");
assert!(json_value.is_object(), "Root should be an object");
let root_obj = json_value.as_object().unwrap();
assert!(
root_obj.contains_key("matches"),
"Should contain matches array"
);
let matches = root_obj["matches"]
.as_array()
.expect("matches should be an array");
for match_item in matches {
assert!(match_item.is_object(), "Each match should be an object");
let match_obj = match_item.as_object().unwrap();
assert!(match_obj.contains_key("text") && match_obj["text"].is_string());
assert!(match_obj.contains_key("offset") && match_obj["offset"].is_number());
assert!(match_obj.contains_key("value") && match_obj["value"].is_string());
assert!(match_obj.contains_key("tags") && match_obj["tags"].is_array());
assert!(match_obj.contains_key("score") && match_obj["score"].is_number());
let score = match_obj["score"]
.as_u64()
.expect("score should be a number");
assert!(score <= 100, "Score should be <= 100, got {}", score);
}
}
#[test]
fn test_cli_json_vs_text_output() {
let temp_dir = TempDir::new().expect("Failed to create temp directory");
let test_file = temp_dir.path().join("test.bin");
fs::write(&test_file, b"Test content").expect("Failed to write test file");
let magic_file = temp_dir.path().join("test.magic");
fs::write(&magic_file, "0 byte 84 Test file\n").expect("Failed to write magic file");
let json_output = Command::new("cargo")
.args([
"run",
"--bin",
"rmagic",
"--",
test_file.to_str().unwrap(),
"--json",
"--magic-file",
magic_file.to_str().unwrap(),
])
.output()
.expect("Failed to execute JSON command");
let text_output = Command::new("cargo")
.args([
"run",
"--bin",
"rmagic",
"--",
test_file.to_str().unwrap(),
"--text",
"--magic-file",
magic_file.to_str().unwrap(),
])
.output()
.expect("Failed to execute text command");
assert!(json_output.status.success(), "JSON command should succeed");
assert!(text_output.status.success(), "Text command should succeed");
let json_stdout = String::from_utf8(json_output.stdout).expect("Invalid UTF-8 in JSON stdout");
let text_stdout = String::from_utf8(text_output.stdout).expect("Invalid UTF-8 in text stdout");
assert_ne!(
json_stdout, text_stdout,
"JSON and text outputs should be different"
);
let _json_value: serde_json::Value =
serde_json::from_str(&json_stdout).expect("JSON output should be valid JSON");
assert!(
serde_json::from_str::<serde_json::Value>(&text_stdout).is_err(),
"Text output should not be valid JSON"
);
assert!(
text_stdout.contains(test_file.file_name().unwrap().to_str().unwrap()),
"Text output should contain filename"
);
}