#![cfg(all(feature = "derive", feature = "serde"))]
use qubit_redact::Redact;
use qubit_redact::RedactionPolicy;
use qubit_redact::Redactor;
use qubit_redact::domain::internal::RedactSerializeSource;
#[derive(Redact)]
#[redact(crate = qubit_redact, serde)]
struct Credential {
#[redact(level = "secret")]
password: String,
}
#[test]
fn test_optional_projection_without_scope_returns_a_value_free_error() {
let policy = RedactionPolicy::standard();
for value in [
None,
Some(Credential {
password: "raw-secret".into(),
}),
] {
let projection = value.redacted_fields(&policy);
let error = serde_json::to_string(&projection).expect_err("missing scope must return Err");
assert!(error.to_string().contains("active redaction scope"));
assert!(!error.to_string().contains("raw-secret"));
}
}
#[test]
fn test_vector_projection_without_scope_returns_a_value_free_error() {
let policy = RedactionPolicy::standard();
for value in [
Vec::new(),
vec![Credential {
password: "raw-secret".into(),
}],
] {
let projection = value.redacted_fields(&policy);
let error = serde_json::to_string(&projection).expect_err("missing scope must return Err");
assert!(error.to_string().contains("active redaction scope"));
assert!(!error.to_string().contains("raw-secret"));
}
}
#[test]
fn test_container_views_establish_the_required_scope() {
let redactor = Redactor::standard();
for value in [
None,
Some(Credential {
password: "raw-secret".into(),
}),
] {
let output = serde_json::to_value(redactor.redact_view(&value)).expect("scoped option");
if value.is_some() {
assert_eq!(output["password"], "<redacted>");
} else {
assert!(output.is_null());
}
}
for value in [
Vec::new(),
vec![Credential {
password: "raw-secret".into(),
}],
] {
let output = serde_json::to_value(redactor.redact_view(&value)).expect("scoped vector");
assert_eq!(output.as_array().expect("array shape").len(), value.len());
if !value.is_empty() {
assert_eq!(output[0]["password"], "<redacted>");
}
}
}