archunit/metrics/fluentapi/
metric_zone_condition.rsuse std::path::Path;
use crate::checkable::execute_logged_check;
use crate::{
checkable::{CheckResult, Checkable},
common::{CheckOptions, ProjectLocator, gather_empty_test_violations},
metrics::{ArchitecturalZone, gather_metric_zone_violations},
violation::Violation,
};
use super::{MetricsBuilder, logging::log_measurements};
#[derive(Debug, Clone)]
#[must_use = "an architecture rule has no effect until it is checked"]
pub struct MetricZoneCondition {
query: MetricsBuilder,
zone: ArchitecturalZone,
}
impl MetricZoneCondition {
pub(super) const fn new(query: MetricsBuilder, zone: ArchitecturalZone) -> Self {
Self { query, zone }
}
#[must_use]
pub const fn zone(&self) -> ArchitecturalZone {
self.zone
}
#[must_use]
pub fn project_path(&self) -> Option<&Path> {
self.query.project_path()
}
#[must_use]
pub fn project_locator(&self) -> ProjectLocator {
self.query
.project_path()
.map_or_else(ProjectLocator::auto_detect, ProjectLocator::from_path)
}
}
impl Checkable for MetricZoneCondition {
fn check_with(&self, options: &CheckOptions) -> CheckResult {
execute_logged_check("metrics.zone", options, |logger| {
logger.log_progress("calculating component distance values")?;
let infos = self.query.distance_infos_with(options)?;
logger.log_progress(format!("metric components={}", infos.len()))?;
let empty = gather_empty_test_violations(
&infos,
"metric components",
self.query.filters(),
false,
options.allows_empty_tests(),
);
if let Some(violation) = empty.into_iter().next() {
return Ok(vec![Violation::from(violation)]);
}
let measurements = [
crate::metrics::DistanceMetric::Abstractness,
crate::metrics::DistanceMetric::Instability,
]
.into_iter()
.flat_map(|metric| metric.measurements(&infos))
.collect::<Vec<_>>();
log_measurements(logger, &measurements, None)?;
Ok(gather_metric_zone_violations(&infos, self.zone)
.into_iter()
.map(Violation::from)
.collect())
})
}
}