use std::path::{Path, PathBuf};
use apimock_routing::RuleSet;
use crate::view::{
Diagnostic, NodeValidation, Severity, ValidationIssue, ValidationReport,
};
use super::Workspace;
use super::id_index::NodeAddress;
impl Workspace {
pub(super) fn collect_diagnostics(&self) -> Vec<Diagnostic> {
let mut out: Vec<Diagnostic> = Vec::new();
for (rs_idx, rule_set) in self.config.service.rule_sets.iter().enumerate() {
for (rule_idx, rule) in rule_set.rules.iter().enumerate() {
let nv = respond_node_validation(&rule.respond, rule_set, rule_idx, rs_idx);
if nv.ok {
continue;
}
let resp_id = self.ids.id_for(NodeAddress::Respond {
rule_set: rs_idx,
rule: rule_idx,
});
for issue in nv.issues {
out.push(Diagnostic {
node_id: resp_id,
file: Some(PathBuf::from(rule_set.file_path.as_str())),
severity: issue.severity,
message: issue.message,
});
}
}
}
if !Path::new(self.config.service.fallback_respond_dir.as_str()).exists() {
out.push(Diagnostic {
node_id: self.ids.id_for(NodeAddress::FallbackRespondDir),
file: Some(self.root_path.clone()),
severity: Severity::Error,
message: format!(
"fallback_respond_dir does not exist: {}",
self.config.service.fallback_respond_dir
),
});
}
out
}
pub fn validate(&self) -> ValidationReport {
let diagnostics = self.collect_diagnostics();
let is_valid = !diagnostics
.iter()
.any(|d| matches!(d.severity, Severity::Error));
ValidationReport {
diagnostics,
is_valid,
}
}
}
pub(super) fn respond_node_validation(
respond: &apimock_routing::Respond,
rule_set: &RuleSet,
rule_idx: usize,
rs_idx: usize,
) -> NodeValidation {
let mut issues: Vec<ValidationIssue> = Vec::new();
let any = respond.file_path.is_some() || respond.text.is_some() || respond.status.is_some();
if !any {
issues.push(ValidationIssue {
severity: Severity::Error,
message: "response requires at least one of file_path, text, or status".to_owned(),
});
}
if respond.file_path.is_some() && respond.text.is_some() {
issues.push(ValidationIssue {
severity: Severity::Error,
message: "file_path and text cannot both be set".to_owned(),
});
}
if respond.file_path.is_some() && respond.status.is_some() {
issues.push(ValidationIssue {
severity: Severity::Error,
message: "status cannot be combined with file_path (only with text)".to_owned(),
});
}
if let Some(file_path) = respond.file_path.as_ref() {
let dir_prefix = rule_set.dir_prefix();
let p = Path::new(dir_prefix.as_str()).join(file_path);
if !p.exists() {
issues.push(ValidationIssue {
severity: Severity::Error,
message: format!(
"file not found: {} (rule #{} in rule set #{})",
p.to_string_lossy(),
rule_idx + 1,
rs_idx + 1,
),
});
}
}
NodeValidation {
ok: issues.is_empty(),
issues,
}
}