use zeropod::{pod::PodBool, ZeroPod, ZeroPodCompact, ZeroPodFixed};
#[allow(dead_code)]
#[derive(ZeroPod)]
struct Validatable {
pub score: u64,
pub active: bool,
pub maybe: Option<u64>,
pub name: zeropod::String<8>,
pub items: zeropod::Vec<u8, 4>,
}
#[test]
fn validate_correct_size() {
assert_eq!(<Validatable as ZeroPodFixed>::SIZE, 33);
}
#[test]
fn validate_zeroed_buffer_ok() {
let buf = [0u8; 33];
assert!(Validatable::from_bytes(&buf).is_ok());
}
#[test]
fn validate_bad_bool() {
let mut buf = [0u8; 33];
buf[8] = 2; assert!(Validatable::from_bytes(&buf).is_err());
}
#[test]
fn validate_truncated_buffer() {
let buf = [0u8; 20]; assert!(Validatable::from_bytes(&buf).is_err());
}
#[test]
fn validate_bad_option_tag() {
let mut buf = [0u8; 33];
buf[9] = 3; assert!(Validatable::from_bytes(&buf).is_err());
}
#[test]
fn validate_overlength_string() {
let mut buf = [0u8; 33];
buf[18] = 9; assert!(Validatable::from_bytes(&buf).is_err());
}
#[test]
fn validate_overlength_vec() {
let mut buf = [0u8; 33];
buf[27] = 5; buf[28] = 0; assert!(Validatable::from_bytes(&buf).is_err());
}
#[test]
fn validate_rejects_invalid_utf8_in_string() {
let mut buf = [0u8; 33];
buf[18] = 2;
buf[19] = 0xFF;
buf[20] = 0xFE;
assert!(Validatable::from_bytes(&buf).is_err());
}
#[allow(dead_code)]
#[derive(ZeroPod)]
struct WithOptionBool {
pub flag: Option<bool>,
}
#[test]
fn validate_option_bool_none_ok() {
let buf = [0u8; 2]; assert!(WithOptionBool::from_bytes(&buf).is_ok());
}
#[test]
fn validate_option_bool_some_valid() {
let buf = [1u8, 1]; assert!(WithOptionBool::from_bytes(&buf).is_ok());
}
#[test]
fn validate_option_bool_some_invalid_inner() {
let buf = [1u8, 5]; assert!(WithOptionBool::from_bytes(&buf).is_err());
}
#[derive(ZeroPod, Debug, PartialEq)]
#[repr(u8)]
enum Color {
Red = 0,
Green = 1,
Blue = 2,
}
#[allow(dead_code)]
#[derive(ZeroPod)]
struct WithOptionEnum {
pub color: Option<Color>,
}
#[test]
fn validate_option_enum_none_ok() {
let buf = [0u8; 2]; assert!(WithOptionEnum::from_bytes(&buf).is_ok());
}
#[test]
fn validate_option_enum_some_valid() {
let buf = [1u8, 2]; assert!(WithOptionEnum::from_bytes(&buf).is_ok());
}
#[test]
fn validate_option_enum_some_invalid_inner() {
let buf = [1u8, 99]; assert!(WithOptionEnum::from_bytes(&buf).is_err());
}
#[allow(dead_code)]
#[derive(ZeroPod)]
#[zeropod(compact)]
struct CompactVal {
pub authority: [u8; 32],
pub bio: zeropod::String<16>,
}
#[test]
fn compact_validate_overlength_tail_string() {
let mut buf = vec![0u8; 100];
buf[32] = 17; assert!(CompactVal::validate(&buf).is_err());
}
#[test]
fn compact_validate_tail_exceeds_buffer() {
let mut buf = vec![0u8; 40]; buf[32] = 10; assert!(CompactVal::validate(&buf).is_err());
}
#[test]
fn compact_validate_rejects_invalid_utf8_in_tail_string() {
let mut buf = vec![0u8; 100];
buf[32] = 3; buf[33] = 0xFF; buf[34] = 0xFE;
buf[35] = 0xFD;
assert!(CompactVal::validate(&buf).is_err());
}
#[allow(dead_code)]
#[derive(ZeroPod)]
#[zeropod(compact)]
struct CompactWithBool {
pub active: bool,
pub bio: zeropod::String<8>,
}
#[test]
fn compact_validate_inline_bad_bool() {
let mut buf = vec![0u8; 20];
buf[0] = 5; assert!(CompactWithBool::validate(&buf).is_err());
}
#[test]
fn validate_vec_bool_all_valid() {
let mut buf = [0u8; 7];
buf[0] = 3;
buf[1] = 0;
buf[2] = 0;
buf[3] = 1;
buf[4] = 0;
let v = unsafe { &*(buf.as_ptr() as *const zeropod::pod::PodVec<PodBool, 5>) };
assert!(zeropod::ZcValidate::validate_ref(v).is_ok());
}
#[test]
fn validate_vec_bool_rejects_invalid_element() {
let mut buf = [0u8; 7];
buf[0] = 3;
buf[1] = 0;
buf[2] = 0;
buf[3] = 1;
buf[4] = 5;
let v = unsafe { &*(buf.as_ptr() as *const zeropod::pod::PodVec<PodBool, 5>) };
assert!(zeropod::ZcValidate::validate_ref(v).is_err());
}
#[test]
fn podstring_truncate_snaps_to_char_boundary() {
use zeropod::pod::PodString;
let mut s = PodString::<32>::default();
let _ = s.set("h\u{00e9}llo"); assert_eq!(s.len(), 6);
s.truncate(2);
assert_eq!(s.len(), 1);
assert_eq!(s.as_str(), "h");
assert!(core::str::from_utf8(s.as_bytes()).is_ok());
}
#[test]
fn podstring_truncate_at_boundary_is_exact() {
use zeropod::pod::PodString;
let mut s = PodString::<32>::default();
let _ = s.set("h\u{00e9}llo");
s.truncate(3);
assert_eq!(s.len(), 3);
assert_eq!(s.as_str(), "h\u{00e9}");
}
#[test]
fn error_invalid_bool_variant() {
let buf = [2u8]; let val = unsafe { &*(buf.as_ptr() as *const zeropod::pod::PodBool) };
let err = <zeropod::pod::PodBool as zeropod::ZcValidate>::validate_ref(val);
assert_eq!(err, Err(zeropod::ZeroPodError::InvalidBool));
}
#[test]
fn error_invalid_tag_variant() {
let buf = [5u8, 0u8]; let val = unsafe { &*(buf.as_ptr() as *const zeropod::pod::PodOption<u8>) };
let err = <zeropod::pod::PodOption<u8> as zeropod::ZcValidate>::validate_ref(val);
assert_eq!(err, Err(zeropod::ZeroPodError::InvalidTag));
}
#[test]
fn pod_option_invalid_tag_is_not_some() {
let buf = [0xFFu8, 42u8]; let opt = unsafe { &*(buf.as_ptr() as *const zeropod::pod::PodOption<u8>) };
assert!(
!opt.is_some(),
"invalid tag 0xFF must not be treated as Some"
);
assert!(opt.is_none(), "invalid tag 0xFF must be treated as None");
assert_eq!(opt.get(), None);
}
#[cfg(feature = "wincode")]
mod wincode_option_validation {
use zeropod::pod::{PodBool, PodOption};
#[test]
fn wincode_read_rejects_option_with_invalid_inner() {
let bytes: [u8; 2] = [1, 5];
let result = wincode::deserialize::<PodOption<PodBool>>(&bytes);
assert!(
result.is_err(),
"wincode SchemaRead must reject PodOption<PodBool> with invalid inner byte"
);
}
#[test]
fn wincode_read_accepts_valid_option_some() {
let bytes: [u8; 2] = [1, 1]; let result = wincode::deserialize::<PodOption<PodBool>>(&bytes);
assert!(result.is_ok());
}
#[test]
fn wincode_read_accepts_valid_option_none() {
let bytes: [u8; 2] = [0, 0]; let result = wincode::deserialize::<PodOption<PodBool>>(&bytes);
assert!(result.is_ok());
}
}
#[allow(dead_code)]
#[derive(ZeroPod)]
#[zeropod(compact)]
struct CompactWithVecBool {
pub score: u64,
pub flags: zeropod::Vec<PodBool, 4>,
}
#[test]
fn compact_validate_rejects_invalid_vec_bool_element() {
let mut buf = vec![0u8; 13]; buf[8] = 3; buf[9] = 0;
buf[10] = 0; buf[11] = 1; buf[12] = 5;
assert!(
CompactWithVecBool::validate(&buf).is_err(),
"compact validate must reject Vec tail with invalid PodBool element"
);
}
#[test]
fn compact_validate_accepts_valid_vec_bool_elements() {
let mut buf = vec![0u8; 12]; buf[8] = 2; buf[9] = 0;
buf[10] = 0; buf[11] = 1;
assert!(CompactWithVecBool::validate(&buf).is_ok());
}