use crate::config::definition::AuditDefinition;
use crate::diff::entry::{DiffEntry, DiffType};
use super::result::{AuditResult, AuditStatus, FileAuditResult};
use super::strategy;
pub struct AuditEngine;
impl AuditEngine {
pub fn evaluate(diffs: &[DiffEntry], definition: &AuditDefinition) -> AuditResult {
let mut results = Vec::new();
for diff in diffs {
let result = judge(diff, definition);
results.push(result);
}
AuditResult::new(results)
}
}
fn judge(diff: &DiffEntry, definition: &AuditDefinition) -> FileAuditResult {
if diff.diff_type.is_error() {
return FileAuditResult {
diff: diff.clone(),
entry: None,
status: AuditStatus::Error,
detail: diff.error_detail.clone().or_else(|| {
Some("File could not be read or compared.".into())
}),
};
}
if diff.diff_type == DiffType::Unchanged {
return FileAuditResult {
diff: diff.clone(),
entry: definition.find_entry(&diff.path).cloned(),
status: AuditStatus::Ok,
detail: None,
};
}
let entry = match definition.find_entry(&diff.path) {
Some(e) => e,
None => {
return FileAuditResult {
diff: diff.clone(),
entry: None,
status: AuditStatus::Pending,
detail: Some("No audit rule defined for this path.".into()),
};
}
};
if !entry.enabled {
return FileAuditResult {
diff: diff.clone(),
entry: Some(entry.clone()),
status: AuditStatus::Ignored,
detail: Some("Entry is disabled.".into()),
};
}
if entry.diff_type != diff.diff_type {
return FileAuditResult {
diff: diff.clone(),
entry: Some(entry.clone()),
status: AuditStatus::Failed,
detail: Some(format!(
"Expected diff type {:?} but found {:?}.",
entry.diff_type, diff.diff_type
)),
};
}
match strategy::evaluate(&entry.strategy, diff) {
Ok(()) => FileAuditResult {
diff: diff.clone(),
entry: Some(entry.clone()),
status: AuditStatus::Ok,
detail: None,
},
Err(msg) => FileAuditResult {
diff: diff.clone(),
entry: Some(entry.clone()),
status: AuditStatus::Failed,
detail: Some(msg),
},
}
}