use shapely::Shapely;
use shapely_core::{Field, FieldFlags, Innards, Shape, ShapeDesc};
use shapely_pretty::{PrettyPrinter, ShapelyPretty};
use std::{alloc::Layout, fmt::Write};
#[derive(Debug, Shapely)]
struct Person {
name: String,
age: u32,
address: Address,
}
#[derive(Debug, Shapely)]
struct Address {
street: String,
city: String,
country: String,
}
#[derive(Debug)]
struct TestSecrets {
#[allow(dead_code)]
normal_field: String,
#[allow(dead_code)]
sensitive_field: String,
}
impl Shapely for TestSecrets {
fn shape() -> Shape {
Shape {
name: |f, _opts| write!(f, "TestSecrets"),
typeid: std::any::TypeId::of::<Self>(),
layout: Layout::new::<Self>(),
innards: Innards::Struct {
fields: &[
Field {
name: "normal_field",
shape: ShapeDesc(String::shape),
offset: 0,
flags: FieldFlags::EMPTY,
},
Field {
name: "sensitive_field",
shape: ShapeDesc(String::shape),
offset: std::mem::size_of::<String>(),
flags: FieldFlags::SENSITIVE,
},
],
},
set_to_default: None,
drop_in_place: Some(|ptr| unsafe { std::ptr::drop_in_place(ptr as *mut Self) }),
}
}
}
#[test]
fn test_pretty_print() {
let address = Address {
street: "123 Main St".to_string(),
city: "Wonderland".to_string(),
country: "Imagination".to_string(),
};
let person = Person {
name: "Alice".to_string(),
age: 30,
address,
};
let printer = PrettyPrinter::new();
let output = printer.format(&person);
eprintln!("{}", output);
assert!(output.contains("name"));
assert!(output.contains("age"));
assert!(output.contains("address"));
assert!(output.contains("street"));
assert!(output.contains("city"));
assert!(output.contains("country"));
let mut buffer = String::new();
write!(buffer, "{}", person.pretty()).unwrap();
eprintln!("{}", buffer);
assert!(buffer.contains("name"));
assert!(buffer.contains("age"));
assert!(buffer.contains("address"));
assert!(buffer.contains("street"));
assert!(buffer.contains("city"));
assert!(buffer.contains("country"));
let custom_printer = PrettyPrinter::new()
.with_indent_size(4)
.with_max_depth(3)
.with_colors(false);
let custom_output = custom_printer.format(&person);
assert!(custom_output.contains("name"));
assert!(custom_output.contains("age"));
assert!(custom_output.contains("address"));
let mut custom_buffer = String::new();
write!(custom_buffer, "{}", person.pretty_with(custom_printer)).unwrap();
assert!(custom_buffer.contains("name"));
assert!(custom_buffer.contains("age"));
assert!(custom_buffer.contains("address"));
}
#[test]
fn test_sensitive_fields() {
let test_data = TestSecrets {
normal_field: "This is visible".to_string(),
sensitive_field: "TOP SECRET PASSWORD".to_string(),
};
let printer = PrettyPrinter::new();
let output = printer.format(&test_data);
eprintln!("{}", output);
assert!(output.contains("normal_field"));
assert!(output.contains("This is visible"));
assert!(output.contains("sensitive_field"));
assert!(output.contains("[REDACTED]"));
assert!(!output.contains("TOP SECRET PASSWORD"));
let mut buffer = String::new();
write!(buffer, "{}", test_data.pretty()).unwrap();
eprintln!("{}", buffer);
assert!(buffer.contains("normal_field"));
assert!(buffer.contains("This is visible"));
assert!(buffer.contains("sensitive_field"));
assert!(buffer.contains("[REDACTED]"));
assert!(!buffer.contains("TOP SECRET PASSWORD"));
}