use crate::cli::proof_annotation_helpers::{
collect_and_filter_annotations, format_as_full, format_as_json, format_as_markdown,
format_as_sarif, format_as_summary, setup_proof_annotator, ProofAnnotationFilter,
};
use crate::cli::{ProofAnnotationOutputFormat, PropertyTypeFilter, VerificationMethodFilter};
use crate::models::unified_ast::{Location, ProofAnnotation};
use crate::services::proof_annotator::ProofAnnotator;
use anyhow::Result;
use std::path::{Path, PathBuf};
use std::time::Instant;
#[allow(clippy::too_many_arguments)]
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "path_exists")]
pub async fn handle_analyze_proof_annotations(
project_path: PathBuf,
format: ProofAnnotationOutputFormat,
high_confidence_only: bool,
include_evidence: bool,
property_type: Option<PropertyTypeFilter>,
verification_method: Option<VerificationMethodFilter>,
output: Option<PathBuf>,
_perf: bool,
clear_cache: bool,
) -> Result<()> {
eprintln!("🔍 Collecting proof annotations from project...");
let start = Instant::now();
let annotator = setup_proof_annotator(clear_cache);
let filter = ProofAnnotationFilter {
high_confidence_only,
property_type,
verification_method,
};
let annotations = collect_and_filter_annotations(&annotator, &project_path, &filter).await;
let elapsed = start.elapsed();
eprintln!("✅ Found {} matching proof annotations", annotations.len());
let content = format_proof_annotations(
format,
&annotations,
elapsed,
&annotator,
&project_path,
include_evidence,
)?;
if let Some(output_path) = output {
tokio::fs::write(&output_path, &content).await?;
eprintln!("✅ Proof annotations written to: {}", output_path.display());
} else {
println!("{content}");
}
Ok(())
}
fn format_proof_annotations(
format: ProofAnnotationOutputFormat,
annotations: &[(Location, ProofAnnotation)],
elapsed: std::time::Duration,
annotator: &ProofAnnotator,
project_path: &Path,
include_evidence: bool,
) -> Result<String> {
match format {
ProofAnnotationOutputFormat::Json => format_as_json(annotations, elapsed, annotator),
ProofAnnotationOutputFormat::Summary => format_as_summary(annotations, elapsed),
ProofAnnotationOutputFormat::Full => {
format_as_full(annotations, project_path, include_evidence)
}
ProofAnnotationOutputFormat::Markdown => {
format_as_markdown(annotations, project_path, include_evidence)
}
ProofAnnotationOutputFormat::Sarif => format_as_sarif(annotations, project_path),
}
}
#[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);
}
}
}
#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod active_tests {
use super::*;
use tempfile::TempDir;
#[tokio::test]
async fn test_handle_analyze_proof_annotations_empty_dir() {
let temp_dir = TempDir::new().expect("Failed to create temp dir");
let result = handle_analyze_proof_annotations(
temp_dir.path().to_path_buf(),
ProofAnnotationOutputFormat::Summary,
false,
false,
None,
None,
None,
false,
false,
)
.await;
assert!(result.is_ok());
}
#[tokio::test]
async fn test_handle_analyze_proof_annotations_json_format() {
let temp_dir = TempDir::new().expect("Failed to create temp dir");
std::fs::write(temp_dir.path().join("lib.rs"), "fn test() {}").expect("write");
let result = handle_analyze_proof_annotations(
temp_dir.path().to_path_buf(),
ProofAnnotationOutputFormat::Json,
false,
true,
None,
None,
None,
false,
false,
)
.await;
assert!(result.is_ok());
}
#[tokio::test]
async fn test_handle_analyze_proof_annotations_with_filters() {
let temp_dir = TempDir::new().expect("Failed to create temp dir");
std::fs::write(temp_dir.path().join("lib.rs"), "fn test() {}").expect("write");
let result = handle_analyze_proof_annotations(
temp_dir.path().to_path_buf(),
ProofAnnotationOutputFormat::Summary,
true, false,
Some(PropertyTypeFilter::MemorySafety),
Some(VerificationMethodFilter::BorrowChecker),
None,
false,
true, )
.await;
assert!(result.is_ok());
}
#[tokio::test]
async fn test_handle_analyze_proof_annotations_with_output_file() {
let temp_dir = TempDir::new().expect("Failed to create temp dir");
let output_path = temp_dir.path().join("output.json");
std::fs::write(temp_dir.path().join("lib.rs"), "fn test() {}").expect("write");
let result = handle_analyze_proof_annotations(
temp_dir.path().to_path_buf(),
ProofAnnotationOutputFormat::Json,
false,
false,
None,
None,
Some(output_path.clone()),
false,
false,
)
.await;
assert!(result.is_ok());
assert!(output_path.exists());
}
#[tokio::test]
async fn test_format_proof_annotations_summary() {
let temp_dir = TempDir::new().expect("Failed to create temp dir");
std::fs::write(temp_dir.path().join("lib.rs"), "pub fn exported() {}").expect("write");
let result = handle_analyze_proof_annotations(
temp_dir.path().to_path_buf(),
ProofAnnotationOutputFormat::Summary,
false,
false,
None,
None,
None,
false,
false,
)
.await;
assert!(result.is_ok());
}
#[tokio::test]
async fn test_format_proof_annotations_full() {
let temp_dir = TempDir::new().expect("Failed to create temp dir");
std::fs::write(temp_dir.path().join("main.rs"), "fn main() {}").expect("write");
let result = handle_analyze_proof_annotations(
temp_dir.path().to_path_buf(),
ProofAnnotationOutputFormat::Full,
false,
true,
None,
None,
None,
false,
false,
)
.await;
assert!(result.is_ok());
}
#[tokio::test]
async fn test_format_proof_annotations_markdown() {
let temp_dir = TempDir::new().expect("Failed to create temp dir");
std::fs::write(temp_dir.path().join("lib.rs"), "fn test() {}").expect("write");
let result = handle_analyze_proof_annotations(
temp_dir.path().to_path_buf(),
ProofAnnotationOutputFormat::Markdown,
false,
false,
None,
None,
None,
false,
false,
)
.await;
assert!(result.is_ok());
}
#[tokio::test]
async fn test_format_proof_annotations_sarif() {
let temp_dir = TempDir::new().expect("Failed to create temp dir");
std::fs::write(temp_dir.path().join("lib.rs"), "unsafe fn danger() {}").expect("write");
let result = handle_analyze_proof_annotations(
temp_dir.path().to_path_buf(),
ProofAnnotationOutputFormat::Sarif,
false,
true,
None,
None,
None,
false,
false,
)
.await;
assert!(result.is_ok());
}
}
#[cfg(all(test, feature = "broken-tests"))]
mod coverage_tests {
include!("proof_annotations_coverage_tests.rs");
include!("proof_annotations_coverage_tests_part2.rs");
include!("proof_annotations_coverage_tests_part3.rs");
}