pub trait FieldCacheMixin {
fn get_cache_name(&self) -> String;
fn is_cached(&self) -> bool;
}
pub trait FieldValidationMixin {
fn validate(&self, value: &str) -> Result<(), String>;
fn run_validators(&self, value: &str) -> Vec<String> {
self.validate(value).err().into_iter().collect()
}
}
#[cfg(test)]
mod tests {
use super::{FieldCacheMixin, FieldValidationMixin};
#[derive(Debug, Clone, PartialEq, Eq)]
struct CachedField {
cache_name: String,
cached: bool,
}
impl FieldCacheMixin for CachedField {
fn get_cache_name(&self) -> String {
self.cache_name.clone()
}
fn is_cached(&self) -> bool {
self.cached
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
struct ValidatedField;
impl FieldValidationMixin for ValidatedField {
fn validate(&self, value: &str) -> Result<(), String> {
if value.contains("ok") {
Ok(())
} else {
Err("value must contain ok".to_string())
}
}
}
#[test]
fn field_cache_mixin_reports_cache_metadata() {
let field = CachedField {
cache_name: "slug_cache".to_string(),
cached: true,
};
assert_eq!(field.get_cache_name(), "slug_cache");
assert!(field.is_cached());
}
#[test]
fn field_validation_mixin_returns_validator_errors() {
let field = ValidatedField;
assert!(field.validate("ok-value").is_ok());
assert_eq!(field.run_validators("bad"), vec!["value must contain ok"]);
}
}