#![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_roundtrip(error in arb_quantum_shield_error()) {
let json: String = serde_json::to_string(&error)?;
prop_assert!(!json.is_empty());
let deserialized: LatticeArcError = serde_json::from_str(&json)?;
prop_assert_eq!(error.clone(), deserialized.clone());
prop_assert_eq!(format!("{}", error), format!("{}", deserialized));
}
}
#[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::HYBRID_KEM.is_empty());
assert!(!domains::CASCADE_OUTER.is_empty());
assert!(!domains::CASCADE_INNER.is_empty());
assert!(!domains::SIGNATURE_BIND.is_empty());
let domains = vec![
domains::HYBRID_KEM,
domains::CASCADE_OUTER,
domains::CASCADE_INNER,
domains::SIGNATURE_BIND,
];
for (i, &domain1) in domains.iter().enumerate() {
for (j, &domain2) in domains.iter().enumerate() {
if i != j {
assert_ne!(domain1, domain2, "Domain constants should be unique");
}
}
}
for &domain in &domains {
assert!(
domain.windows(12).any(|w| w == b"LatticeArc-v"),
"Domain should contain version identifier"
);
}
}
#[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()) {
#[allow(clippy::redundant_clone)]
let error: LatticeArcError = LatticeArcError::InvalidInput(msg.clone());
match error {
#[allow(clippy::redundant_clone)]
LatticeArcError::InvalidInput(s) => prop_assert_eq!(s, msg.clone()),
#[allow(clippy::wildcard_enum_match_arm)]
_ => prop_assert!(false, "Expected InvalidInput error"),
}
#[allow(clippy::redundant_clone)]
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)),
#[allow(clippy::wildcard_enum_match_arm)]
_ => 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)]
#[allow(clippy::unwrap_used)] 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::HYBRID_KEM.is_empty());
assert!(!domains::CASCADE_OUTER.is_empty());
assert!(!domains::CASCADE_INNER.is_empty());
assert!(!domains::SIGNATURE_BIND.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_serialization_fails() {
let error = LatticeArcError::InvalidInput("test".to_string());
let json = serde_json::to_string(&error).unwrap();
let deserialized: LatticeArcError = serde_json::from_str(&json).unwrap();
assert_eq!(error, deserialized);
}
#[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);
}
}