#![cfg_attr(coverage_nightly, coverage(off))]
use super::{PropertyTypeFilter, VerificationMethodFilter};
use crate::models::unified_ast::{
ConfidenceLevel, Location, ProofAnnotation, PropertyType, VerificationMethod,
};
use crate::services::proof_annotator::ProofAnnotator;
use anyhow::Result;
use std::path::Path;
pub struct ProofAnnotationFilter {
pub high_confidence_only: bool,
pub property_type: Option<PropertyTypeFilter>,
pub verification_method: Option<VerificationMethodFilter>,
}
include!("proof_annotation_helpers_filter.rs");
include!("proof_annotation_helpers_format.rs");
include!("proof_annotation_helpers_report.rs");
#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod tests {
use super::*;
use crate::models::unified_ast::{
BytePos, ConfidenceLevel, EvidenceType, Location, ProofAnnotation, PropertyType, Span,
VerificationMethod,
};
use chrono::Utc;
use std::path::PathBuf;
use uuid::Uuid;
fn loc(path: &str, line: u32) -> Location {
Location {
file_path: PathBuf::from(path),
span: Span {
start: BytePos(line),
end: BytePos(line + 10),
},
}
}
fn ann(prop: PropertyType, conf: ConfidenceLevel) -> ProofAnnotation {
ProofAnnotation {
annotation_id: Uuid::new_v4(),
property_proven: prop,
specification_id: None,
method: VerificationMethod::BorrowChecker,
tool_name: "test-tool".to_string(),
tool_version: "1.0".to_string(),
confidence_level: conf,
assumptions: vec!["assumption-1".to_string(), "assumption-2".to_string()],
evidence_type: EvidenceType::ImplicitTypeSystemGuarantee,
evidence_location: None,
date_verified: Utc::now(),
}
}
#[test]
fn test_format_as_full_empty_emits_only_header() {
let r = format_as_full(&[], Path::new("/test"), false).unwrap();
assert!(r.contains("# Full Proof Annotations Report"));
assert!(r.contains("**Total proofs**: 0"));
assert!(!r.contains("## File:"));
}
#[test]
fn test_format_as_full_with_annotations_emits_file_sections() {
let annotations = vec![
(
loc("src/a.rs", 10),
ann(PropertyType::MemorySafety, ConfidenceLevel::High),
),
(
loc("src/a.rs", 20),
ann(PropertyType::ThreadSafety, ConfidenceLevel::Medium),
),
(
loc("src/b.rs", 5),
ann(PropertyType::Termination, ConfidenceLevel::Low),
),
];
let r = format_as_full(&annotations, Path::new("/test"), false).unwrap();
assert!(r.contains("**Total proofs**: 3"));
assert!(r.contains("## File: src/a.rs"));
assert!(r.contains("## File: src/b.rs"));
}
#[test]
fn test_format_as_full_include_evidence_renders_evidence_section() {
let annotations = vec![(
loc("src/a.rs", 1),
ann(PropertyType::MemorySafety, ConfidenceLevel::High),
)];
let with_evidence = format_as_full(&annotations, Path::new("/test"), true).unwrap();
let without = format_as_full(&annotations, Path::new("/test"), false).unwrap();
assert!(with_evidence.len() >= without.len());
}
#[test]
fn test_group_proofs_by_file_groups_by_path() {
let annotations = vec![
(
loc("src/a.rs", 1),
ann(PropertyType::MemorySafety, ConfidenceLevel::High),
),
(
loc("src/a.rs", 2),
ann(PropertyType::ThreadSafety, ConfidenceLevel::Medium),
),
(
loc("src/b.rs", 3),
ann(PropertyType::Termination, ConfidenceLevel::Low),
),
];
let grouped = group_proofs_by_file(&annotations);
assert_eq!(grouped.len(), 2);
assert_eq!(grouped.get(&PathBuf::from("src/a.rs")).unwrap().len(), 2);
assert_eq!(grouped.get(&PathBuf::from("src/b.rs")).unwrap().len(), 1);
}
#[test]
fn test_group_proofs_by_file_empty_returns_empty_map() {
let grouped = group_proofs_by_file(&[]);
assert!(grouped.is_empty());
}
#[test]
fn test_group_proofs_by_file_preserves_annotation_order_within_group() {
let annotations = vec![
(
loc("src/a.rs", 30),
ann(PropertyType::MemorySafety, ConfidenceLevel::High),
),
(
loc("src/a.rs", 10),
ann(PropertyType::ThreadSafety, ConfidenceLevel::Medium),
),
(
loc("src/a.rs", 20),
ann(PropertyType::Termination, ConfidenceLevel::Low),
),
];
let grouped = group_proofs_by_file(&annotations);
let group = grouped.get(&PathBuf::from("src/a.rs")).unwrap();
assert_eq!(group[0].0.span.start.0, 30);
assert_eq!(group[1].0.span.start.0, 10);
assert_eq!(group[2].0.span.start.0, 20);
}
#[test]
fn test_format_as_full_with_unique_line_markers_renders_each() {
let annotations = vec![
(
loc("src/x.rs", 12345),
ann(PropertyType::MemorySafety, ConfidenceLevel::High),
),
(
loc("src/x.rs", 67890),
ann(PropertyType::ThreadSafety, ConfidenceLevel::Medium),
),
];
let r = format_as_full(&annotations, Path::new("/test"), false).unwrap();
assert!(r.contains("12345"));
assert!(r.contains("67890"));
}
}
#[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);
}
}
}