#![deny(unsafe_code)]
#![cfg_attr(test, allow(clippy::unwrap_used))]
#![cfg_attr(test, allow(clippy::expect_used))]
#![cfg_attr(test, allow(clippy::wildcard_enum_match_arm))]
#![cfg_attr(test, allow(clippy::redundant_clone))]
#[cfg(test)]
use proptest::prelude::*;
#[cfg(test)]
use crate::prelude::error::LatticeArcError;
#[cfg(test)]
fn arb_error_message() -> impl Strategy<Value = String> {
prop::string::string_regex("[a-zA-Z0-9 .,!?_-]{1,100}")
.expect("valid regex pattern for error messages")
}
#[cfg(test)]
fn arb_quantum_shield_error() -> impl Strategy<Value = LatticeArcError> {
arb_error_message().prop_map(LatticeArcError::InvalidInput)
}
#[cfg(test)]
proptest! {
#[test]
fn prop_error_display_consistent(error in arb_quantum_shield_error()) {
let display1 = format!("{error}");
let display2 = format!("{error}");
prop_assert_eq!(display1.clone(), display2);
prop_assert!(!display1.is_empty());
prop_assert!(display1.len() > 10);
}
}
#[cfg(test)]
proptest! {
#[test]
fn prop_error_serialization_well_formed(error in arb_quantum_shield_error()) {
let json: String = serde_json::to_string(&error)?;
prop_assert!(!json.is_empty());
let _value: serde_json::Value = serde_json::from_str(&json)?;
let display = format!("{error}");
prop_assert!(!display.is_empty());
}
}
#[cfg(test)]
#[test]
fn test_uuid_generation_valid_produces_v4_uuid_succeeds() {
let uuid = uuid::Uuid::new_v4();
assert!(!uuid.is_nil());
assert_eq!(uuid.get_version_num(), 4);
let uuid_str = uuid.to_string();
assert_eq!(uuid_str.len(), 36);
assert_eq!(uuid_str.chars().nth(8), Some('-'));
assert_eq!(uuid_str.chars().nth(13), Some('-'));
assert_eq!(uuid_str.chars().nth(18), Some('-'));
assert_eq!(uuid_str.chars().nth(23), Some('-'));
}
#[cfg(test)]
proptest! {
#[test]
fn prop_hex_roundtrip(data in prop::collection::vec(prop::num::u8::ANY, 0..=100)) {
let hex_string = hex::encode(&data);
let decoded = hex::decode(&hex_string)?;
prop_assert_eq!(data.clone(), decoded);
prop_assert_eq!(hex_string.len(), data.len().saturating_mul(2));
}
}
#[cfg(test)]
#[test]
fn test_domain_constants_valid_succeeds() {
use crate::types::domains;
assert!(!domains::CASCADE_OUTER.is_empty());
assert!(!domains::CASCADE_INNER.is_empty());
assert!(!domains::HYBRID_KEM_SS_INFO.is_empty());
let live_domains: Vec<&[u8]> =
vec![domains::CASCADE_OUTER, domains::CASCADE_INNER, domains::HYBRID_KEM_SS_INFO];
for (i, &domain1) in live_domains.iter().enumerate() {
for (j, &domain2) in live_domains.iter().enumerate() {
if i != j {
assert_ne!(domain1, domain2, "Domain constants should be unique");
}
}
}
for &domain in &live_domains {
assert!(
domain.windows(11).any(|w| w == b"LatticeArc-"),
"Domain should contain LatticeArc- prefix"
);
}
}
#[cfg(test)]
#[test]
fn test_version_constant_reasonable_is_nonzero_succeeds() {
const { assert!(crate::prelude::ENVELOPE_FORMAT_VERSION > 0) };
let version1 = crate::prelude::ENVELOPE_FORMAT_VERSION;
let version2 = crate::prelude::ENVELOPE_FORMAT_VERSION;
assert_eq!(version1, version2);
}
#[cfg(test)]
proptest! {
#[test]
fn prop_error_conversions_work(msg in arb_error_message()) {
let error: LatticeArcError = LatticeArcError::InvalidInput(msg.clone());
match error {
#[expect(
clippy::redundant_clone,
reason = "explicit clone for ownership clarity at this call site"
)]
LatticeArcError::InvalidInput(s) => prop_assert_eq!(s, msg.clone()),
_ => prop_assert!(false, "Expected InvalidInput error"),
}
let io_error = std::io::Error::new(std::io::ErrorKind::NotFound, msg.clone());
let converted: LatticeArcError = io_error.into();
match converted {
LatticeArcError::IoError(s) => prop_assert!(s.contains(&msg)),
_ => prop_assert!(false, "Expected IoError"),
}
}
}
#[cfg(test)]
pub fn run_all_property_tests() {
tracing::info!("Running prelude property-based tests");
tracing::info!("Prelude property-based tests completed");
}
#[cfg(test)]
#[derive(Debug, Clone)]
pub struct PropertyTestConfig {
pub test_cases: u32,
pub max_shrink_iters: u32,
pub timeout: std::time::Duration,
}
#[cfg(test)]
impl Default for PropertyTestConfig {
fn default() -> Self {
Self {
test_cases: 256,
max_shrink_iters: 10000,
timeout: std::time::Duration::from_secs(300), }
}
}
#[cfg(test)]
#[expect(clippy::unwrap_used, reason = "Tests use unwrap for simplicity")]
mod tests {
use super::*;
#[test]
fn test_property_test_runner_succeeds() {
run_all_property_tests();
}
#[test]
fn test_config_defaults_succeeds() {
let config = PropertyTestConfig::default();
assert_eq!(config.test_cases, 256);
assert_eq!(config.max_shrink_iters, 10000);
assert_eq!(config.timeout.as_secs(), 300);
}
#[test]
fn test_domain_constants_succeeds() {
use crate::types::domains;
assert!(!domains::CASCADE_OUTER.is_empty());
assert!(!domains::CASCADE_INNER.is_empty());
assert!(!domains::HYBRID_KEM_SS_INFO.is_empty());
}
#[test]
fn test_version_constant_is_nonzero_succeeds() {
const { assert!(crate::prelude::ENVELOPE_FORMAT_VERSION > 0) };
}
#[test]
fn test_error_display_fails() {
let error = LatticeArcError::InvalidInput("test message".to_string());
let display = format!("{error}");
assert!(display.contains("test message"));
assert!(display.contains("Invalid input"));
}
#[test]
fn test_error_serializes_to_well_formed_json() {
let error = LatticeArcError::InvalidInput("test".to_string());
let json = serde_json::to_string(&error).unwrap();
let value: serde_json::Value = serde_json::from_str(&json).unwrap();
assert!(json.contains("InvalidInput"));
assert!(json.contains("test"));
assert!(!value.is_null());
}
#[test]
fn test_uuid_generation_produces_v4_uuid_succeeds() {
let uuid = uuid::Uuid::new_v4();
assert!(!uuid.is_nil());
assert_eq!(uuid.get_version_num(), 4);
let uuid_str = uuid.to_string();
assert_eq!(uuid_str.len(), 36);
assert_eq!(uuid_str.chars().nth(8), Some('-'));
}
#[test]
fn test_hex_roundtrip() {
let data = vec![1, 2, 3, 255, 0];
let hex_string = hex::encode(&data);
let decoded = hex::decode(&hex_string).unwrap();
assert_eq!(data, decoded);
assert_eq!(hex_string.len(), data.len() * 2);
}
}