#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod tests {
use super::*;
use std::path::PathBuf;
use tempfile::TempDir;
#[tokio::test]
async fn test_proof_annotator_basic() {
let symbol_table = Arc::new(SymbolTable::new());
let mut annotator = ProofAnnotator::new(symbol_table);
annotator.add_source(MockProofSource::new("test".to_string(), 10, 2));
let project_root = PathBuf::from(".");
let proof_map = annotator.collect_proofs(&project_root).await;
assert_eq!(proof_map.len(), 2);
}
#[tokio::test]
#[ignore = "Flaky timing assertion fails in coverage builds"]
async fn test_proof_annotator_parallel_sources() {
let symbol_table = Arc::new(SymbolTable::new());
let mut annotator = ProofAnnotator::new(symbol_table);
annotator.add_source(MockProofSource::new("source1".to_string(), 50, 1));
annotator.add_source(MockProofSource::new("source2".to_string(), 30, 1));
annotator.add_source(MockProofSource::new("source3".to_string(), 20, 1));
let start = Instant::now();
let project_root = PathBuf::from(".");
let proof_map = annotator.collect_proofs(&project_root).await;
let elapsed = start.elapsed();
assert!(elapsed.as_millis() < 100);
assert_eq!(proof_map.len(), 3, "Should have 3 unique annotations");
}
#[tokio::test]
async fn test_proof_cache() {
let mut cache = ProofCache::new();
let annotations = vec![ProofAnnotation {
annotation_id: uuid::Uuid::new_v4(),
property_proven: PropertyType::MemorySafety,
specification_id: None,
method: VerificationMethod::BorrowChecker,
tool_name: "test".to_string(),
tool_version: "1.0.0".to_string(),
confidence_level: ConfidenceLevel::High,
assumptions: vec![],
evidence_type: crate::models::unified_ast::EvidenceType::ImplicitTypeSystemGuarantee,
evidence_location: None,
date_verified: chrono::Utc::now(),
}];
cache.insert("test_key".to_string(), annotations.clone());
assert_eq!(cache.get("test_key"), Some(&annotations));
assert_eq!(cache.size(), 1);
cache.clear();
assert_eq!(cache.size(), 0);
}
#[test]
fn test_proof_cache_new_is_empty() {
let cache = ProofCache::new();
assert_eq!(cache.size(), 0);
assert!(cache.file_times.is_empty());
}
#[test]
fn test_proof_cache_get_missing() {
let cache = ProofCache::new();
assert!(cache.get("nonexistent").is_none());
}
#[test]
fn test_proof_cache_is_file_cached_nonexistent() {
let cache = ProofCache::new();
assert!(!cache.is_file_cached(Path::new("/nonexistent/file.rs")));
}
#[test]
fn test_proof_cache_is_file_cached_real_file() {
let temp_dir = TempDir::new().unwrap();
let file_path = temp_dir.path().join("test.rs");
std::fs::write(&file_path, "fn main() {}").unwrap();
let mut cache = ProofCache::new();
assert!(!cache.is_file_cached(&file_path));
cache.update_file_time(file_path.clone());
assert!(cache.is_file_cached(&file_path));
}
#[test]
fn test_proof_cache_update_file_time_nonexistent() {
let mut cache = ProofCache::new();
cache.update_file_time(PathBuf::from("/nonexistent/file.rs"));
assert!(cache.file_times.is_empty());
}
#[test]
fn test_collection_metrics_default() {
let metrics = CollectionMetrics::default();
assert_eq!(metrics.files_processed, 0);
assert_eq!(metrics.annotations_found, 0);
assert_eq!(metrics.cache_hits, 0);
assert_eq!(metrics.duration_ms, 0);
}
#[test]
fn test_mock_proof_source_new() {
let source = MockProofSource::new("test".to_string(), 100, 5);
assert_eq!(source.name, "test");
assert_eq!(source.delay_ms, 100);
assert_eq!(source.annotation_count, 5);
}
#[test]
fn test_mock_proof_source_clone() {
let source = MockProofSource::new("test".to_string(), 50, 3);
let cloned = source.clone();
assert_eq!(cloned.name, source.name);
assert_eq!(cloned.delay_ms, source.delay_ms);
assert_eq!(cloned.annotation_count, source.annotation_count);
}
#[test]
fn test_mock_proof_source_clone_box() {
let source = MockProofSource::new("boxtest".to_string(), 10, 2);
let _boxed = source.clone_box();
}
#[test]
fn test_proof_annotator_new() {
let symbol_table = Arc::new(SymbolTable::new());
let annotator = ProofAnnotator::new(symbol_table);
assert_eq!(annotator.sources.len(), 0);
assert_eq!(annotator.cache_stats().size, 0);
}
#[test]
fn test_proof_annotator_add_source() {
let symbol_table = Arc::new(SymbolTable::new());
let mut annotator = ProofAnnotator::new(symbol_table);
assert_eq!(annotator.sources.len(), 0);
annotator.add_source(MockProofSource::new("s1".to_string(), 0, 0));
assert_eq!(annotator.sources.len(), 1);
annotator.add_source(MockProofSource::new("s2".to_string(), 0, 0));
assert_eq!(annotator.sources.len(), 2);
}
#[test]
fn test_proof_annotator_cache_stats() {
let symbol_table = Arc::new(SymbolTable::new());
let annotator = ProofAnnotator::new(symbol_table);
let stats = annotator.cache_stats();
assert_eq!(stats.size, 0);
assert_eq!(stats.files_tracked, 0);
}
#[test]
fn test_proof_annotator_clear_cache() {
let symbol_table = Arc::new(SymbolTable::new());
let annotator = ProofAnnotator::new(symbol_table);
annotator.cache.write().insert("key".to_string(), vec![]);
assert_eq!(annotator.cache_stats().size, 1);
annotator.clear_cache();
assert_eq!(annotator.cache_stats().size, 0);
}
#[test]
fn test_proof_annotator_debug() {
let symbol_table = Arc::new(SymbolTable::new());
let annotator = ProofAnnotator::new(symbol_table);
let debug_str = format!("{:?}", annotator);
assert!(debug_str.contains("ProofAnnotator"));
assert!(debug_str.contains("sources_count"));
}
#[test]
fn test_cache_stats_debug() {
let stats = CacheStats {
size: 10,
files_tracked: 5,
};
let debug_str = format!("{:?}", stats);
assert!(debug_str.contains("CacheStats"));
assert!(debug_str.contains("10"));
assert!(debug_str.contains("5"));
}
#[test]
fn test_proof_collection_result_debug() {
let result = ProofCollectionResult {
annotations: vec![],
errors: vec![],
metrics: CollectionMetrics::default(),
};
let debug_str = format!("{:?}", result);
assert!(debug_str.contains("ProofCollectionResult"));
}
#[test]
fn test_proof_collection_error_io() {
let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "file not found");
let err: ProofCollectionError = io_err.into();
assert!(err.to_string().contains("IO error"));
}
#[test]
fn test_proof_collection_error_parse() {
let err = ProofCollectionError::Parse {
path: PathBuf::from("test.rs"),
message: "syntax error".to_string(),
};
assert!(err.to_string().contains("Parse error"));
assert!(err.to_string().contains("test.rs"));
}
#[test]
fn test_proof_collection_error_invalid_metadata() {
let err = ProofCollectionError::InvalidMetadata("bad data".to_string());
assert!(err.to_string().contains("Invalid metadata"));
}
#[test]
fn test_proof_collection_error_proof_source() {
let err = ProofCollectionError::ProofSource("source failed".to_string());
assert!(err.to_string().contains("Proof source error"));
}
#[tokio::test]
async fn test_proof_annotator_no_sources() {
let symbol_table = Arc::new(SymbolTable::new());
let annotator = ProofAnnotator::new(symbol_table);
let proof_map = annotator.collect_proofs(Path::new(".")).await;
assert!(proof_map.is_empty());
}
#[tokio::test]
async fn test_mock_proof_source_collect() {
let source = MockProofSource::new("collect_test".to_string(), 1, 3);
let cache = Arc::new(RwLock::new(ProofCache::new()));
let symbol_table = Arc::new(SymbolTable::new());
let result = source
.collect(Path::new("."), &cache, &symbol_table)
.await
.unwrap();
assert_eq!(result.annotations.len(), 3);
assert_eq!(result.metrics.annotations_found, 3);
assert!(result.errors.is_empty());
}
}
#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod property_tests {
use proptest::prelude::*;
proptest! {
#[test]
fn basic_property_stability(_input in ".*") {
prop_assert!(true);
}
#[test]
fn module_consistency_check(_x in 0u32..1000) {
prop_assert!(_x < 1001);
}
}
}