#![allow(clippy::unwrap_used)]
use std::process::Command;
use sha2::{Digest, Sha256};
fn cli() -> Command {
Command::new(env!("CARGO_BIN_EXE_fraiseql-cli"))
}
fn fixture(name: &str) -> String {
format!("{}/tests/fixtures/{name}", env!("CARGO_MANIFEST_DIR"))
}
fn write_manifest(dir: &tempfile::TempDir, content: &serde_json::Value) -> String {
let path = dir.path().join("manifest.json");
std::fs::write(&path, serde_json::to_string(content).unwrap()).unwrap();
path.to_str().unwrap().to_string()
}
fn sha256_key(query: &str) -> String {
let hash = format!("{:x}", Sha256::digest(query.as_bytes()));
format!("sha256:{hash}")
}
#[test]
fn validate_documents_valid_manifest_exits_zero() {
let out = cli()
.args(["validate-documents", &fixture("valid_manifest.json")])
.output()
.unwrap();
assert!(
out.status.success(),
"valid manifest must exit 0; stderr: {}",
String::from_utf8_lossy(&out.stderr)
);
}
#[test]
fn validate_documents_prints_document_count() {
let out = cli()
.args(["validate-documents", &fixture("valid_manifest.json")])
.output()
.unwrap();
let combined = format!(
"{}{}",
String::from_utf8_lossy(&out.stdout),
String::from_utf8_lossy(&out.stderr)
);
assert!(
combined.contains('1') || combined.contains("valid"),
"output must mention count or validity; got: {combined}"
);
}
#[test]
fn validate_documents_missing_file_exits_nonzero() {
let out = cli().args(["validate-documents", "does_not_exist.json"]).output().unwrap();
assert!(!out.status.success(), "missing manifest must exit non-zero");
}
#[test]
fn validate_documents_mismatched_hash_exits_nonzero() {
let dir = tempfile::tempdir().unwrap();
let manifest = serde_json::json!({
"version": 1,
"documents": {
"sha256:0000000000000000000000000000000000000000000000000000000000000000":
"query { users { id } }"
}
});
let path = write_manifest(&dir, &manifest);
let out = cli().args(["validate-documents", &path]).output().unwrap();
assert!(!out.status.success(), "mismatched hash must exit non-zero");
}
#[test]
fn validate_documents_invalid_hash_format_exits_nonzero() {
let dir = tempfile::tempdir().unwrap();
let manifest = serde_json::json!({
"version": 1,
"documents": {
"sha256:short": "query { users { id } }"
}
});
let path = write_manifest(&dir, &manifest);
let out = cli().args(["validate-documents", &path]).output().unwrap();
assert!(!out.status.success(), "invalid hash format must exit non-zero");
}
#[test]
fn validate_documents_multiple_valid_entries_exits_zero() {
let dir = tempfile::tempdir().unwrap();
let q1 = "query GetUsers { users { id email } }";
let q2 = "mutation CreateUser($email: String!) { createUser(email: $email) { id } }";
let manifest = serde_json::json!({
"version": 1,
"documents": {
sha256_key(q1): q1,
sha256_key(q2): q2
}
});
let path = write_manifest(&dir, &manifest);
let out = cli().args(["validate-documents", &path]).output().unwrap();
assert!(
out.status.success(),
"manifest with multiple correct hashes must exit 0; stderr: {}",
String::from_utf8_lossy(&out.stderr)
);
}
#[test]
fn validate_documents_partial_mismatch_exits_nonzero() {
let dir = tempfile::tempdir().unwrap();
let good_query = "query { users { id } }";
let manifest = serde_json::json!({
"version": 1,
"documents": {
sha256_key(good_query): good_query,
"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa":
"query { differentQuery { name } }"
}
});
let path = write_manifest(&dir, &manifest);
let out = cli().args(["validate-documents", &path]).output().unwrap();
assert!(!out.status.success(), "partial hash mismatch must exit non-zero");
}
#[test]
fn validate_documents_hash_without_prefix_is_accepted() {
let dir = tempfile::tempdir().unwrap();
let query = "query GetOrders { orders { id status } }";
let hash = format!("{:x}", Sha256::digest(query.as_bytes()));
let manifest = serde_json::json!({
"version": 1,
"documents": {
hash: query
}
});
let path = write_manifest(&dir, &manifest);
let out = cli().args(["validate-documents", &path]).output().unwrap();
assert!(
out.status.success(),
"manifest with unprefixed hash must exit 0; stderr: {}",
String::from_utf8_lossy(&out.stderr)
);
}