#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
fn build_clippy_message(passed: bool, stderr: &str) -> String {
if passed {
"✓ Clippy passed".to_string()
} else {
format!(
"✗ Clippy failed:\n{}",
stderr.lines().take(10).collect::<Vec<_>>().join("\n")
)
}
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
fn build_test_message(passed: bool, stdout: &str, stderr: &str) -> String {
if passed {
return "✓ Tests passed".to_string();
}
let failure_lines: Vec<&str> = stdout
.lines()
.filter(|line| {
line.contains("FAILED")
|| line.contains("panicked")
|| line.contains("error[")
|| line.starts_with("failures:")
|| line.starts_with(" ")
&& (line.contains("::") || line.trim().starts_with("thread"))
})
.take(15)
.collect();
if !failure_lines.is_empty() {
format!("✗ Tests failed:\n{}", failure_lines.join("\n"))
} else {
format!(
"✗ Tests failed:\n{}",
stderr.lines().take(10).collect::<Vec<_>>().join("\n")
)
}
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
fn build_coverage_decision(coverage: f64, min_coverage: f64) -> (bool, String) {
let passed = coverage >= min_coverage;
let message = if passed {
format!("✓ Coverage: {:.1}% (>= {:.1}%)", coverage, min_coverage)
} else {
format!("✗ Coverage: {:.1}% (< {:.1}%)", coverage, min_coverage)
};
(passed, message)
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "path_exists")]
pub fn execute_clippy(config: &GateConfig, project_dir: &Path) -> Result<GateResult> {
use std::time::Instant;
let start = Instant::now();
let mut cmd = Command::new("cargo");
cmd.arg("clippy")
.arg("--lib") .current_dir(project_dir);
if config.clippy_strict {
cmd.arg("--").arg("-D").arg("warnings");
}
let output = cmd.output()?;
let duration = start.elapsed();
let passed = output.status.success();
let stderr = String::from_utf8_lossy(&output.stderr);
let message = build_clippy_message(passed, &stderr);
Ok(GateResult {
name: "clippy".to_string(),
passed,
duration,
message,
})
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "path_exists")]
pub fn execute_tests(config: &GateConfig, project_dir: &Path) -> Result<GateResult> {
use std::time::Instant;
let start = Instant::now();
let output = Command::new("cargo")
.arg("test")
.arg("--lib")
.env("RUST_MIN_STACK", "33554432") .current_dir(project_dir)
.output()?;
let duration = start.elapsed();
if duration.as_secs() > config.test_timeout {
return Err(GateError::Timeout(config.test_timeout));
}
let passed = output.status.success();
let stdout = String::from_utf8_lossy(&output.stdout);
let stderr = String::from_utf8_lossy(&output.stderr);
let message = build_test_message(passed, &stdout, &stderr);
Ok(GateResult {
name: "tests".to_string(),
passed,
duration,
message,
})
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "path_exists")]
pub fn execute_coverage(config: &GateConfig, project_dir: &Path) -> Result<GateResult> {
use std::time::Instant;
let start = Instant::now();
let output = Command::new("cargo")
.arg("+nightly")
.arg("llvm-cov")
.arg("--lib")
.arg("--summary-only")
.env("RUST_MIN_STACK", "33554432") .current_dir(project_dir)
.output()?;
let duration = start.elapsed();
cleanup_coverage_artifacts(project_dir);
let stdout = String::from_utf8_lossy(&output.stdout);
let stderr = String::from_utf8_lossy(&output.stderr);
let coverage = parse_coverage_from_output(&stdout);
if coverage == 0.0 && !output.status.success() {
let err_snippet = stderr.lines().rev().take(3).collect::<Vec<_>>();
return Ok(GateResult {
name: "coverage".to_string(),
passed: false,
duration,
message: format!("✗ Coverage check failed to run: {}", err_snippet.join(" | ")),
});
}
let (passed, message) = build_coverage_decision(coverage, config.min_coverage);
Ok(GateResult {
name: "coverage".to_string(),
passed,
duration,
message,
})
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
fn cleanup_coverage_artifacts(project_dir: &Path) {
let llvm_cov_target = project_dir.join("target").join("llvm-cov-target");
if llvm_cov_target.exists() {
let _ = std::fs::remove_dir_all(&llvm_cov_target);
}
let zram_coverage = Path::new("/mnt/zram/coverage");
if zram_coverage.exists() {
clean_old_files(zram_coverage, 3600); }
let zram_targets = Path::new("/mnt/zram/targets");
if zram_targets.exists() {
clean_old_files(zram_targets, 3600); }
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
fn clean_old_files(dir: &Path, max_age_secs: u64) {
use std::time::{Duration, SystemTime};
let max_age = Duration::from_secs(max_age_secs);
let now = SystemTime::now();
if let Ok(entries) = std::fs::read_dir(dir) {
for entry in entries.flatten() {
if let Ok(metadata) = entry.metadata() {
let should_delete = metadata
.modified()
.ok()
.and_then(|mtime| now.duration_since(mtime).ok())
.is_some_and(|age| age > max_age);
if should_delete {
let path = entry.path();
if path.is_dir() {
let _ = std::fs::remove_dir_all(&path);
} else {
let _ = std::fs::remove_file(&path);
}
}
}
}
}
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
fn parse_coverage_from_output(output: &str) -> f64 {
for line in output.lines() {
if line.contains("TOTAL") {
if let Some(pct) = line
.split_whitespace()
.find(|s| s.ends_with('%'))
.and_then(|s| s.trim_end_matches('%').parse::<f64>().ok())
{
return pct;
}
}
}
0.0
}
#[derive(Debug, Default, PartialEq)]
pub struct ComplexityScan {
pub files_seen: usize,
pub files_measured: usize,
pub functions_measured: usize,
pub worst: Option<(String, String, u32)>,
}
struct GateComplexityVisitor {
functions: Vec<(String, u32)>,
}
impl<'ast> syn::visit::Visit<'ast> for GateComplexityVisitor {
fn visit_item_fn(&mut self, node: &'ast syn::ItemFn) {
let name = node.sig.ident.to_string();
let measured =
crate::services::accurate_complexity_analyzer::measure_block(&name, &node.block);
self.functions.push((name, measured.cyclomatic));
syn::visit::visit_item_fn(self, node);
}
fn visit_impl_item_fn(&mut self, node: &'ast syn::ImplItemFn) {
let name = node.sig.ident.to_string();
let measured =
crate::services::accurate_complexity_analyzer::measure_block(&name, &node.block);
self.functions.push((name, measured.cyclomatic));
syn::visit::visit_impl_item_fn(self, node);
}
}
fn scan_rust_complexity(project_dir: &Path) -> ComplexityScan {
use crate::services::file_discovery::{FileDiscoveryConfig, ProjectFileDiscovery};
use syn::visit::Visit;
let discovery_config = FileDiscoveryConfig {
respect_gitignore: true,
filter_external_repos: true,
..Default::default()
};
let discovery =
ProjectFileDiscovery::new(project_dir.to_path_buf()).with_config(discovery_config);
let files = discovery.discover_files().unwrap_or_default();
let mut scan = ComplexityScan::default();
for file in files {
if file.extension().and_then(|e| e.to_str()) != Some("rs") {
continue;
}
scan.files_seen += 1;
let Ok(content) = std::fs::read_to_string(&file) else {
continue;
};
let Ok(tree) = syn::parse_file(&content) else {
continue; };
let mut visitor = GateComplexityVisitor {
functions: Vec::new(),
};
visitor.visit_file(&tree);
scan.files_measured += 1;
scan.functions_measured += visitor.functions.len();
for (name, cyclomatic) in visitor.functions {
let worse = scan.worst.as_ref().is_none_or(|(_, _, w)| cyclomatic > *w);
if worse {
scan.worst = Some((file.display().to_string(), name, cyclomatic));
}
}
}
scan
}
fn build_complexity_decision(scan: &ComplexityScan, max_complexity: u32) -> (bool, String) {
let Some((file, function, worst)) = scan.worst.as_ref() else {
return (
false,
format!(
"✗ Complexity: not measured — 0 of {} Rust file(s) could be parsed",
scan.files_seen
),
);
};
if *worst > max_complexity {
return (
false,
format!(
"✗ Complexity: {} in {} has cyclomatic {} (> {}); measured {} function(s) in {} of {} file(s)",
function, file, worst, max_complexity,
scan.functions_measured, scan.files_measured, scan.files_seen
),
);
}
(
true,
format!(
"✓ Complexity: max cyclomatic {} (≤ {}); measured {} function(s) in {} of {} file(s)",
worst, max_complexity, scan.functions_measured, scan.files_measured, scan.files_seen
),
)
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "path_exists")]
pub fn execute_complexity(config: &GateConfig, project_dir: &Path) -> Result<GateResult> {
use std::time::Instant;
let start = Instant::now();
let scan = scan_rust_complexity(project_dir);
let duration = start.elapsed();
let (passed, message) = build_complexity_decision(&scan, config.max_complexity);
Ok(GateResult {
name: "complexity".to_string(),
passed,
duration,
message,
})
}
#[cfg(test)]
mod complexity_gate_tests {
use super::*;
fn scan_with_worst(cyclomatic: u32) -> ComplexityScan {
ComplexityScan {
files_seen: 1,
files_measured: 1,
functions_measured: 1,
worst: Some(("src/lib.rs".to_string(), "complex".to_string(), cyclomatic)),
}
}
#[test]
fn test_complexity_gate_fails_when_worst_exceeds_threshold() {
let (passed, message) = build_complexity_decision(&scan_with_worst(6), 0);
assert!(!passed, "cyclomatic 6 must not pass a threshold of 0");
assert!(message.contains("complex"), "message names the offender: {message}");
}
#[test]
fn test_complexity_gate_passes_when_under_threshold() {
let (passed, message) = build_complexity_decision(&scan_with_worst(6), 10);
assert!(passed);
assert!(message.contains("max cyclomatic 6"), "{message}");
}
#[test]
fn test_complexity_gate_refuses_to_pass_when_nothing_measured() {
let scan = ComplexityScan {
files_seen: 3,
..Default::default()
};
let (passed, message) = build_complexity_decision(&scan, 10);
assert!(!passed, "a gate that measured nothing has not passed");
assert!(message.contains("not measured"), "{message}");
}
#[test]
fn test_execute_complexity_measures_the_real_tree() {
let dir = tempfile::TempDir::new().unwrap();
std::fs::write(
dir.path().join("lib.rs"),
"pub fn complex(n: u32) -> u32 {\n let mut acc = 0;\n for i in 0..n {\n if i % 2 == 0 { acc += i; }\n else if i % 3 == 0 { acc += i * 2; }\n else if i % 5 == 0 { acc += i * 3; }\n else if i % 7 == 0 { acc += i * 4; }\n else { acc += 1; }\n }\n acc\n}\n",
)
.unwrap();
let config = GateConfig {
max_complexity: 0,
..Default::default()
};
let result = execute_complexity(&config, dir.path()).unwrap();
assert!(
!result.passed,
"every function exceeds max_complexity 0: {}",
result.message
);
assert!(result.message.contains("complex"), "{}", result.message);
let lenient = GateConfig {
max_complexity: 100,
..Default::default()
};
let result = execute_complexity(&lenient, dir.path()).unwrap();
assert!(result.passed, "{}", result.message);
}
#[test]
fn test_execute_complexity_does_not_pass_an_empty_tree() {
let dir = tempfile::TempDir::new().unwrap();
let result = execute_complexity(&GateConfig::default(), dir.path()).unwrap();
assert!(!result.passed);
assert!(result.message.contains("not measured"), "{}", result.message);
}
}