use crate::common::CheckLogger;
use crate::common::error::ArchUnitError;
use crate::common::fluentapi::CheckOptions;
use crate::violation::Violation;
pub type CheckResult = Result<Vec<Violation>, ArchUnitError>;
pub(crate) fn execute_logged_check<Operation>(
rule_name: &'static str,
options: &CheckOptions,
operation: Operation,
) -> CheckResult
where
Operation: FnOnce(&CheckLogger<'_>) -> CheckResult,
{
let logger = CheckLogger::new(options.logging());
logger.validate()?;
logger.start_check(rule_name)?;
let result = operation(&logger);
match result {
Ok(violations) => {
for violation in &violations {
logger.log_violation(violation.kind().as_str())?;
}
logger.end_check(rule_name, violations.len())?;
Ok(violations)
}
Err(error) => {
let _ = logger.error(format!("{rule_name}: {error}"));
Err(error)
}
}
}
pub trait Checkable {
fn check(&self) -> CheckResult {
self.check_with(&CheckOptions::default())
}
fn check_with(&self, options: &CheckOptions) -> CheckResult;
}
impl<T> Checkable for &T
where
T: Checkable + ?Sized,
{
fn check_with(&self, options: &CheckOptions) -> CheckResult {
(**self).check_with(options)
}
}
#[cfg(test)]
mod tests {
use super::{CheckResult, Checkable};
use crate::common::{ArchUnitError, CheckOptions, TechnicalError};
struct OptionEchoRule;
impl Checkable for OptionEchoRule {
fn check_with(&self, options: &CheckOptions) -> CheckResult {
if options.clears_cache() {
Err(ArchUnitError::from(TechnicalError::new(
"fixture cache clear failed",
)))
} else {
Ok(Vec::new())
}
}
}
fn run_default(rule: &dyn Checkable) -> CheckResult {
rule.check()
}
#[test]
fn default_check_uses_defaults_through_an_object_safe_contract() {
let result = run_default(&OptionEchoRule);
assert!(matches!(result, Ok(violations) if violations.is_empty()));
}
#[test]
fn explicit_options_reach_the_terminal_by_shared_reference() {
let options = CheckOptions::new().with_clear_cache(true);
let result = OptionEchoRule.check_with(&options);
assert!(matches!(result, Err(ArchUnitError::Technical(_))));
assert!(options.clears_cache());
}
#[test]
fn borrowed_rules_preserve_the_terminal_contract() {
fn require_checkable<T: Checkable>(_: T) {}
require_checkable(&OptionEchoRule);
assert!(OptionEchoRule.check().is_ok());
}
}