1use crate::{AgentError, Result};
7use std::process::Command;
8
9#[derive(Clone, Default)]
13pub struct Verifier {}
14
15impl Verifier {
16 pub fn new() -> Self {
18 Self::default()
19 }
20
21 pub async fn compile_check(&self, working_dir: &std::path::Path) -> Result<Vec<Diagnostic>> {
27 let output = Command::new("cargo")
28 .args(["check", "--message-format=short"])
29 .current_dir(working_dir)
30 .output()
31 .map_err(|e| AgentError::VerificationFailed(format!("Cargo check failed: {}", e)))?;
32
33 let stdout = String::from_utf8_lossy(&output.stdout);
34 let stderr = String::from_utf8_lossy(&output.stderr);
35
36 let mut diagnostics = Vec::new();
37 for line in stdout.lines().chain(stderr.lines()) {
38 if line.contains("error:") {
39 diagnostics.push(Diagnostic {
40 level: DiagnosticLevel::Error,
41 message: line.trim().to_string(),
42 });
43 } else if line.contains("warning:") {
44 diagnostics.push(Diagnostic {
45 level: DiagnosticLevel::Warning,
46 message: line.trim().to_string(),
47 });
48 }
49 }
50
51 Ok(diagnostics)
52 }
53
54 pub async fn test_check(&self, working_dir: &std::path::Path) -> Result<Vec<Diagnostic>> {
60 let output = Command::new("cargo")
61 .args(["test", "--message-format=short"])
62 .current_dir(working_dir)
63 .output()
64 .map_err(|e| AgentError::VerificationFailed(format!("Cargo test failed: {}", e)))?;
65
66 let stdout = String::from_utf8_lossy(&output.stdout);
67 let stderr = String::from_utf8_lossy(&output.stderr);
68
69 let mut diagnostics = Vec::new();
70
71 for line in stdout.lines().chain(stderr.lines()) {
73 if line.contains("test result:") && line.contains("FAILED") {
74 diagnostics.push(Diagnostic {
75 level: DiagnosticLevel::Error,
76 message: line.trim().to_string(),
77 });
78 } else if line.contains("test result:") && line.contains("ok") {
79 }
81 }
82
83 Ok(diagnostics)
84 }
85
86 pub async fn graph_check(&self, _working_dir: &std::path::Path) -> Result<Vec<Diagnostic>> {
90 let mut diagnostics = Vec::new();
91
92 diagnostics.push(Diagnostic {
97 level: DiagnosticLevel::Info,
98 message: "Graph consistency check: skipped (not yet implemented)".to_string(),
99 });
100
101 Ok(diagnostics)
102 }
103
104 pub async fn verify(&self, working_dir: &std::path::Path) -> Result<VerificationReport> {
110 let mut all_diagnostics = Vec::new();
111
112 let compile_diags = self.compile_check(working_dir).await?;
114 all_diagnostics.extend(compile_diags);
115
116 let test_diags = self.test_check(working_dir).await?;
118 all_diagnostics.extend(test_diags);
119
120 let graph_diags = self.graph_check(working_dir).await?;
122 all_diagnostics.extend(graph_diags);
123
124 let errors = all_diagnostics
125 .iter()
126 .filter(|d| d.level == DiagnosticLevel::Error)
127 .count();
128
129 let passed = errors == 0;
130
131 Ok(VerificationReport {
132 passed,
133 diagnostics: all_diagnostics,
134 })
135 }
136}
137
138#[derive(Clone, Debug)]
140pub struct VerificationReport {
141 pub passed: bool,
143 pub diagnostics: Vec<Diagnostic>,
145}
146
147#[derive(Clone, Debug)]
149pub struct Diagnostic {
150 pub level: DiagnosticLevel,
152 pub message: String,
154}
155
156#[derive(Clone, Debug, PartialEq, Eq)]
158pub enum DiagnosticLevel {
159 Info,
161 Warning,
163 Error,
165}
166
167#[cfg(test)]
168mod tests {
169 use super::*;
170
171 #[tokio::test]
172 async fn test_verifier_creation() {
173 let _verifier = Verifier::new();
174
175 assert!(true);
177 }
178
179 #[test]
180 fn test_diagnostic_level_equality() {
181 assert_eq!(DiagnosticLevel::Error, DiagnosticLevel::Error);
182 assert_ne!(DiagnosticLevel::Error, DiagnosticLevel::Warning);
183 }
184}