use super::errors::ValidationError; pub(crate) fn validate_range( value: T, range: R, message: impl Fn() -> String, ) -> Result<(), ValidationError> where T: PartialOrd, R: std::ops::RangeBounds, { if !range.contains(&value) { return Err(ValidationError::value(message())); } Ok(()) } pub(crate) fn validate_ascii_padded( value: &[u8], length: usize, padding: u8, field: &str, ) -> Result<(), ValidationError> { if value.len() != length { return Err(ValidationError::value(format!( "{} must be exactly {} bytes", field, length ))); } for &byte in value { if !((0x20..=0x7E).contains(&byte) || byte == padding) { return Err(ValidationError::value(format!( "Invalid ASCII character: {:#04x}", byte ))); } } Ok(()) } pub(crate) fn validate_bitmask( value: u8, allowed_bits: u8, message: impl Fn() -> String, ) -> Result<(), ValidationError> { if value & !allowed_bits != 0 { return Err(ValidationError::value(message())); } Ok(()) } #[cfg(test)] mod tests { use super::*; #[test] fn validate_range_accepts_bounds() { assert!(validate_range(0u8, 0..=10, || "".into()).is_ok()); assert!(validate_range(10u8, 0..=10, || "".into()).is_ok()); assert!(validate_range(5u8, 0..=10, || "".into()).is_ok()); } #[test] fn validate_range_rejects_out_of_range() { let err = validate_range(11u8, 0..=10, || "bad value".into()).unwrap_err(); assert!(err.to_string().contains("bad value")); } #[test] fn validate_ascii_padded_accepts_ascii_and_padding() { assert!(validate_ascii_padded(b"ABC ", 4, b' ', "name",).is_ok()); assert!(validate_ascii_padded(&[b'A', 0, 0, 0], 4, 0, "password",).is_ok()); } #[test] fn validate_ascii_padded_rejects_wrong_length() { assert!(validate_ascii_padded(b"ABC", 4, b' ', "name",).is_err()); } #[test] fn validate_ascii_padded_rejects_non_ascii() { assert!(validate_ascii_padded(&[0xFF, b'A', b'B', b'C'], 4, b' ', "name",).is_err()); } #[test] fn validate_bitmask_accepts_valid_bits() { assert!(validate_bitmask(0b0101, 0b1111, || "".into(),).is_ok()); assert!(validate_bitmask(0, 0b1111, || "".into(),).is_ok()); } #[test] fn validate_bitmask_rejects_invalid_bits() { let err = validate_bitmask(0b10000, 0b01111, || "invalid mask".into()).unwrap_err(); assert!(err.to_string().contains("invalid mask")); } }