use clock_hash::{clockhash256, ClockHasher};
#[test]
fn cross_architecture_simd_consistency() {
use proptest::prelude::*;
let config = ProptestConfig::with_cases(500);
proptest!(config, |(input: Vec<u8>)| {
let scalar_hash = clockhash256_scalar(&input);
#[cfg(feature = "simd")]
let avx2_hash = clockhash256_avx2(&input);
#[cfg(all(feature = "simd", target_arch = "x86_64"))]
let avx512_hash = clockhash256_avx512(&input);
#[cfg(feature = "simd")]
prop_assert_eq!(scalar_hash, avx2_hash,
"Scalar and AVX2 implementations should produce identical results");
#[cfg(all(feature = "simd", target_arch = "x86_64"))]
{
prop_assert_eq!(scalar_hash, avx512_hash,
"Scalar and AVX-512 implementations should produce identical results");
prop_assert_eq!(avx2_hash, avx512_hash,
"AVX2 and AVX-512 implementations should produce identical results");
}
prop_assert_eq!(scalar_hash.len(), 32, "Scalar hash should be 32 bytes");
#[cfg(feature = "simd")]
prop_assert_eq!(avx2_hash.len(), 32, "AVX2 hash should be 32 bytes");
#[cfg(all(feature = "simd", target_arch = "x86_64"))]
prop_assert_eq!(avx512_hash.len(), 32, "AVX-512 hash should be 32 bytes");
});
}
#[test]
#[cfg(feature = "simd")]
fn cross_architecture_dispatch_logic() {
use proptest::prelude::*;
let config = ProptestConfig::with_cases(200);
proptest!(config, |(input: Vec<u8>)| {
let dispatched_hash = clockhash256(&input);
let scalar_hash = clockhash256_scalar(&input);
prop_assert_eq!(dispatched_hash, scalar_hash,
"Dispatched hash should match scalar fallback");
prop_assert_eq!(dispatched_hash.len(), 32, "Dispatched hash should be 32 bytes");
});
}
#[test]
#[cfg(feature = "simd")]
fn cross_architecture_graceful_degradation() {
let original_avx2_available = is_avx2_available();
let test_data = vec![
vec![],
vec![0u8],
vec![0u8; 64],
vec![0xFFu8; 128],
vec![0xAAu8; 1024],
];
for input in test_data {
let hash = clockhash256(&input);
assert_eq!(hash.len(), 32, "Hash should always be 32 bytes");
let mut hasher = ClockHasher::new();
hasher.update(&input);
let incremental_hash = hasher.finalize();
assert_eq!(hash, incremental_hash, "Incremental should match one-shot");
}
}
#[test]
fn cross_architecture_memory_alignment() {
use proptest::prelude::*;
let config = ProptestConfig::with_cases(300);
proptest!(config, |(input: Vec<u8>)| {
prop_assume!(!input.is_empty());
let hash1 = clockhash256(&input);
prop_assert_eq!(hash1.len(), 32, "First hash should be 32 bytes");
let mut hasher = ClockHasher::new();
hasher.update(&input);
let incremental_hash = hasher.finalize();
prop_assert_eq!(hash1, incremental_hash, "Incremental should match one-shot");
prop_assert_eq!(incremental_hash.len(), 32, "Incremental hash should be 32 bytes");
if input.len() > 1 {
let misaligned_input = &input[1..];
let hash2 = clockhash256(misaligned_input);
prop_assert_ne!(hash1, hash2, "Different inputs should produce different hashes");
prop_assert_eq!(hash2.len(), 32, "Misaligned hash should be 32 bytes");
let mut hasher2 = ClockHasher::new();
hasher2.update(misaligned_input);
let incremental_hash2 = hasher2.finalize();
prop_assert_eq!(hash2, incremental_hash2,
"Incremental hash should match one-shot for misaligned data");
}
});
}
#[test]
fn cross_architecture_endianness_handling() {
let test_values = [
0x123456789ABCDEF0u64,
0xFEDCBA9876543210u64,
0xAAAAAAAAAAAAAAAAu64,
0x5555555555555555u64,
0x0000000000000000u64,
0xFFFFFFFFFFFFFFFFu64,
];
for &value in &test_values {
let little_endian_bytes = value.to_le_bytes();
let big_endian_bytes = value.to_be_bytes();
let hash_le = clockhash256(&little_endian_bytes);
let hash_be = clockhash256(&big_endian_bytes);
if little_endian_bytes != big_endian_bytes {
assert_ne!(hash_le, hash_be, "Different byte orders should produce different hashes");
}
assert_eq!(hash_le.len(), 32, "Little endian hash should be 32 bytes");
assert_eq!(hash_be.len(), 32, "Big endian hash should be 32 bytes");
assert_eq!(clockhash256(&little_endian_bytes), hash_le, "Should be deterministic");
assert_eq!(clockhash256(&big_endian_bytes), hash_be, "Should be deterministic");
}
}
#[test]
#[cfg(all(feature = "simd", any(target_arch = "x86_64", target_arch = "x86")))]
fn cross_architecture_instruction_set_detection() {
let avx2_1 = is_avx2_available();
let avx2_2 = is_avx2_available();
assert_eq!(avx2_1, avx2_2, "AVX2 detection should be consistent");
let avx512_1 = is_avx512_available();
let avx512_2 = is_avx512_available();
assert_eq!(avx512_1, avx512_2, "AVX-512 detection should be consistent");
if avx512_1 {
assert!(avx2_1, "AVX-512 availability should imply AVX2 availability");
}
for _ in 0..10 {
let _ = is_avx2_available();
let _ = is_avx512_available();
}
}
#[test]
fn cross_architecture_optimization_validation() {
let test_inputs = vec![
vec![],
vec![0u8],
vec![0u8; 32],
vec![0u8; 64],
vec![0xFFu8; 128],
vec![0xAAu8; 1024],
vec![0x55u8; 2048],
];
for input in test_inputs {
let scalar_hash = clockhash256_scalar(&input);
let simd_hash = clockhash256(&input);
assert_eq!(scalar_hash, simd_hash,
"SIMD and scalar implementations should produce identical results");
assert_eq!(scalar_hash.len(), 32, "Scalar hash should be 32 bytes");
assert_eq!(simd_hash.len(), 32, "SIMD hash should be 32 bytes");
let mut scalar_hasher = ClockHasher::new();
scalar_hasher.update(&input);
let scalar_incremental = scalar_hasher.finalize();
let mut simd_hasher = ClockHasher::new();
simd_hasher.update(&input);
let simd_incremental = simd_hasher.finalize();
assert_eq!(scalar_incremental, simd_incremental,
"SIMD and scalar incremental hashing should match");
assert_eq!(scalar_hash, scalar_incremental,
"One-shot and incremental should match for scalar");
assert_eq!(simd_hash, simd_incremental,
"One-shot and incremental should match for SIMD");
}
}
#[test]
fn cross_architecture_domain_separation() {
use proptest::prelude::*;
let config = ProptestConfig::with_cases(200);
proptest!(config, |(domain: Vec<u8>, data: Vec<u8>)| {
use clock_hash::clockhash256_domain;
let domain_hash = clockhash256_domain(&domain, &data);
let plain_hash = clockhash256(&data);
prop_assert_ne!(domain_hash, plain_hash,
"Domain-separated hash should differ from plain hash");
prop_assert_eq!(domain_hash.len(), 32, "Domain hash should be 32 bytes");
prop_assert_eq!(plain_hash.len(), 32, "Plain hash should be 32 bytes");
let domain_hash2 = clockhash256_domain(&domain, &data);
let plain_hash2 = clockhash256(&data);
prop_assert_eq!(domain_hash, domain_hash2, "Domain hash should be deterministic");
prop_assert_eq!(plain_hash, plain_hash2, "Plain hash should be deterministic");
});
}
#[test]
#[cfg(feature = "std")]
fn cross_architecture_performance_characteristics() {
use std::time::{Duration, Instant};
let test_sizes = [64, 1024, 8192, 65536];
let iterations = 100;
for &size in &test_sizes {
let input = vec![0xAAu8; size];
let start = Instant::now();
for _ in 0..iterations {
let _hash = clockhash256(&input);
}
let elapsed = start.elapsed();
assert!(elapsed < Duration::from_secs(30),
"Hashing {} bytes {} times should complete in less than 30 seconds, took {:?}",
size, iterations, elapsed);
let hash = clockhash256(&input);
assert_eq!(hash.len(), 32, "Hash should be 32 bytes");
assert!(!hash.iter().all(|&b| b == 0), "Hash should not be all zeros");
}
}
#[test]
fn cross_architecture_fallback_mechanisms() {
let test_inputs = vec![
vec![],
vec![0u8],
vec![0u8; 64],
vec![0xFFu8; 64],
vec![0xAAu8; 64],
vec![0x55u8; 64],
(0..64).map(|i| i as u8).collect(),
(0..64).map(|i| (i ^ 0xFF) as u8).collect(),
];
for input in test_inputs {
let hash = clockhash256(&input);
assert_eq!(hash.len(), 32, "Hash should be 32 bytes");
let mut hasher = ClockHasher::new();
hasher.update(&input);
let incremental_hash = hasher.finalize();
assert_eq!(hash, incremental_hash, "Incremental should match one-shot");
assert!(!hash.iter().all(|&b| b == 0), "Hash should not be all zeros");
}
}
fn clockhash256_scalar(input: &[u8]) -> [u8; 32] {
clockhash256(input)
}
#[cfg(feature = "simd")]
fn clockhash256_avx2(input: &[u8]) -> [u8; 32] {
clockhash256(input)
}
#[cfg(all(feature = "simd", target_arch = "x86_64"))]
fn clockhash256_avx512(input: &[u8]) -> [u8; 32] {
clockhash256(input)
}