use serde_json::Value;
use crate::genome::schema::GenomeSchemaVersion;
pub mod v3;
pub use v3::V3Validator;
#[derive(Debug, Clone, Default)]
pub struct ValidationReport {
pub schema_version: Option<GenomeSchemaVersion>,
pub errors: Vec<String>,
pub warnings: Vec<String>,
}
impl ValidationReport {
pub fn new(schema_version: GenomeSchemaVersion) -> Self {
Self {
schema_version: Some(schema_version),
errors: Vec::new(),
warnings: Vec::new(),
}
}
pub fn add_error(&mut self, msg: impl Into<String>) {
self.errors.push(msg.into());
}
pub fn add_warning(&mut self, msg: impl Into<String>) {
self.warnings.push(msg.into());
}
pub fn has_errors(&self) -> bool {
!self.errors.is_empty()
}
pub fn is_clean(&self) -> bool {
self.errors.is_empty() && self.warnings.is_empty()
}
}
pub trait Validator: Send + Sync {
fn schema_version(&self) -> GenomeSchemaVersion;
fn validate(&self, genome: &Value) -> ValidationReport;
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn report_starts_clean() {
let r = ValidationReport::new(GenomeSchemaVersion(3));
assert!(r.is_clean());
assert!(!r.has_errors());
assert_eq!(r.schema_version, Some(GenomeSchemaVersion(3)));
}
#[test]
fn add_error_breaks_clean_and_blocks() {
let mut r = ValidationReport::new(GenomeSchemaVersion(3));
r.add_error("missing field");
assert!(r.has_errors());
assert!(!r.is_clean());
assert_eq!(r.errors, vec!["missing field".to_string()]);
}
#[test]
fn warning_is_advisory_only() {
let mut r = ValidationReport::new(GenomeSchemaVersion(3));
r.add_warning("nudge");
assert!(!r.has_errors());
assert!(!r.is_clean());
assert_eq!(r.warnings, vec!["nudge".to_string()]);
}
}