#![cfg(test)]
use clock_hash::{clockhash256, clockhash256_domain, ClockHasher, DomainTag, clockhash256_with_domain};
#[test]
fn test_very_large_input() {
let large_input = vec![0x42u8; 1024 * 1024]; let hash = clockhash256(&large_input);
assert_eq!(hash.len(), 32);
let hash2 = clockhash256(&large_input);
assert_eq!(hash, hash2);
}
#[test]
fn test_incremental_hasher_large_input() {
let chunk_size = 64 * 1024; let total_size = 512 * 1024; let mut hasher = ClockHasher::new();
for i in 0..(total_size / chunk_size) {
let chunk: Vec<u8> = (0..chunk_size).map(|j| ((i * chunk_size + j) % 256) as u8).collect();
hasher.update(&chunk);
}
let hash = hasher.finalize();
assert_eq!(hash.len(), 32);
let full_data: Vec<u8> = (0..total_size).map(|i| (i % 256) as u8).collect();
let one_shot_hash = clockhash256(&full_data);
assert_eq!(hash, one_shot_hash);
}
#[test]
fn test_block_boundary_conditions() {
let block_sizes = [
127, 128, 129, 255, 256, 257, 383, 384, 385, 511, 512, 513, ];
for &size in &block_sizes {
let data: Vec<u8> = (0..size).map(|i| (i % 256) as u8).collect();
let hash = clockhash256(&data);
assert_eq!(hash.len(), 32, "Hash should be 32 bytes for size {}", size);
let hash2 = clockhash256(&data);
assert_eq!(hash, hash2, "Hash should be deterministic for size {}", size);
}
}
#[test]
fn test_unusual_byte_patterns() {
let small_patterns: Vec<(&str, Vec<u8>)> = vec![
("empty", vec![]),
("single_zero", vec![0x00]),
("single_one", vec![0x01]),
("single_ff", vec![0xFF]),
];
let mut small_hashes = Vec::new();
for (name, pattern) in &small_patterns {
let hash = clockhash256(pattern);
small_hashes.push((name.to_string(), hash));
}
for i in 0..small_hashes.len() {
for j in (i + 1)..small_hashes.len() {
assert_ne!(small_hashes[i].1, small_hashes[j].1,
"Small patterns {} and {} should produce different hashes",
small_hashes[i].0, small_hashes[j].0);
}
}
let large_patterns: Vec<(&str, Vec<u8>)> = vec![
("zeros_10", vec![0x00; 10]),
("ones_10", vec![0xFF; 10]),
("alternating_10", vec![0xAA; 10]),
];
let mut large_hashes = Vec::new();
for (name, pattern) in &large_patterns {
let hash = clockhash256(pattern);
large_hashes.push((name.to_string(), hash));
}
for i in 0..large_hashes.len() {
for j in (i + 1)..large_hashes.len() {
if large_patterns[i].0 != large_patterns[j].0 {
let hash_i = &large_hashes[i].1;
let hash_j = &large_hashes[j].1;
if large_patterns[i].0 == "zeros_10" && large_patterns[j].0 == "ones_10" {
assert_ne!(hash_i, hash_j,
"Zeros and ones patterns should produce different hashes");
}
}
}
}
}
#[test]
fn test_domain_separation_edge_cases() {
let data = b"test data";
let empty_domain_hash = clockhash256_domain(b"", data);
let regular_hash = clockhash256(data);
assert_ne!(empty_domain_hash, regular_hash, "Empty domain should differ from no domain");
let long_domain = vec![0x42; 1000];
let long_domain_hash = clockhash256_domain(&long_domain, data);
assert_ne!(long_domain_hash, regular_hash, "Long domain should differ from no domain");
let null_domain = b"domain\x00with\x00nulls";
let null_domain_hash = clockhash256_domain(null_domain, data);
assert_ne!(null_domain_hash, regular_hash, "Domain with nulls should differ from no domain");
let data_as_domain_hash = clockhash256_domain(data, data);
assert_ne!(data_as_domain_hash, regular_hash, "Data as domain should differ from no domain");
}
#[test]
fn test_incremental_hasher_edge_cases() {
let mut hasher = ClockHasher::new();
hasher.update(b"");
hasher.update(b"");
hasher.update(b"data");
hasher.update(b"");
let hash1 = hasher.finalize();
let mut hasher2 = ClockHasher::new();
hasher2.update(b"data");
let hash2 = hasher2.finalize();
assert_eq!(hash1, hash2, "Empty updates should not affect result");
let data = b"hello world";
let mut hasher3 = ClockHasher::new();
for &byte in data.iter() {
hasher3.update(&[byte]);
}
let hash3 = hasher3.finalize();
let one_shot_hash = clockhash256(data);
assert_eq!(hash3, one_shot_hash, "Byte-by-byte updates should match one-shot");
}
#[test]
fn test_maximum_reasonable_input() {
let size = 1024 * 1024; let data: Vec<u8> = (0..size).map(|i| ((i * 7 + 13) % 256) as u8).collect();
let hash = clockhash256(&data);
assert_eq!(hash.len(), 32);
let mut modified_data = data.clone();
modified_data[0] ^= 1; let modified_hash = clockhash256(&modified_data);
assert_ne!(hash, modified_hash, "Changing one byte should change the hash");
let hash2 = clockhash256(&data);
assert_eq!(hash, hash2, "Hash should be deterministic");
}
#[test]
fn test_chunking_consistency() {
let data = vec![0x42; 10000];
let chunk_sizes = [1, 7, 13, 31, 47, 64, 97, 128, 256, 512, 1024];
let reference_hash = clockhash256(&data);
for &chunk_size in &chunk_sizes {
let mut hasher = ClockHasher::new();
for chunk in data.chunks(chunk_size) {
hasher.update(chunk);
}
let chunked_hash = hasher.finalize();
assert_eq!(chunked_hash, reference_hash,
"Chunking with size {} should produce same hash", chunk_size);
}
}
#[test]
fn test_all_domain_tags_unique() {
let data = b"test data for domain uniqueness";
let domains = vec![
DomainTag::Block,
DomainTag::Transaction,
DomainTag::Merkle,
DomainTag::Nonce,
DomainTag::Rng,
];
let mut hashes = Vec::new();
for &domain in &domains {
let hash = clockhash256_with_domain(domain, data);
hashes.push(hash);
}
for i in 0..hashes.len() {
for j in (i + 1)..hashes.len() {
assert_ne!(hashes[i], hashes[j],
"Domain tags {:?} and {:?} should produce different hashes",
domains[i], domains[j]);
}
}
let plain_hash = clockhash256(data);
for (i, hash) in hashes.iter().enumerate() {
assert_ne!(*hash, plain_hash,
"Domain tag {:?} should differ from plain hash", domains[i]);
}
}
#[test]
fn test_repeated_patterns() {
let patterns = vec![
"a".repeat(1000),
"ab".repeat(500),
"abc".repeat(333),
"abcd".repeat(250),
"abcde".repeat(200),
];
let mut hashes = Vec::new();
for pattern in patterns {
let hash = clockhash256(pattern.as_bytes());
hashes.push(hash);
let hash2 = clockhash256(pattern.as_bytes());
assert_eq!(hash, hash2);
}
for i in 0..hashes.len() {
for j in (i + 1)..hashes.len() {
assert_ne!(hashes[i], hashes[j],
"Repeated patterns {} and {} should produce different hashes", i, j);
}
}
}
#[test]
fn test_multiple_hasher_instances() {
let data1 = b"first data";
let data2 = b"second data";
let mut hasher1 = ClockHasher::new();
hasher1.update(data1);
let hash1 = hasher1.finalize();
let mut hasher2 = ClockHasher::new();
hasher2.update(data2);
let hash2 = hasher2.finalize();
let hash1_again = clockhash256(data1);
let hash2_again = clockhash256(data2);
assert_eq!(hash1, hash1_again);
assert_eq!(hash2, hash2_again);
assert_ne!(hash1, hash2);
}
#[test]
fn test_domain_boundary_conditions() {
let data = b"test";
let domain_lengths = [0, 1, 15, 16, 31, 32, 63, 64, 127, 128];
let mut hashes = Vec::new();
for &len in &domain_lengths {
let domain: Vec<u8> = (0..len).map(|i| (i % 256) as u8).collect();
let hash = clockhash256_domain(&domain, data);
hashes.push(hash);
}
for i in 0..hashes.len() {
for j in (i + 1)..hashes.len() {
assert_ne!(hashes[i], hashes[j],
"Domain lengths {} and {} should produce different hashes",
domain_lengths[i], domain_lengths[j]);
}
}
}