use super::Span;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PolicyVerb {
Allow,
Deny,
Warn,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PolicyEntry {
pub verb: PolicyVerb,
pub code: String,
pub subjects: Vec<String>,
pub source_span: Option<Span>,
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct DiagnosticPolicy {
pub entries: Vec<PolicyEntry>,
}
impl DiagnosticPolicy {
pub fn verb_for(&self, code: &str, subject_id: Option<&str>) -> Option<&PolicyVerb> {
self.entries
.iter()
.rev()
.find(|e| e.matches(code, subject_id))
.map(|e| &e.verb)
}
}
impl PolicyEntry {
fn matches(&self, code: &str, subject_id: Option<&str>) -> bool {
if self.code != code {
return false;
}
if self.subjects.is_empty() {
return true;
}
match subject_id {
Some(actual) => self.subjects.iter().any(|expected| expected == actual),
None => false,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
fn entry(verb: PolicyVerb, code: &str) -> PolicyEntry {
PolicyEntry {
verb,
code: code.to_owned(),
subjects: Vec::new(),
source_span: None,
}
}
#[test]
fn default_policy_is_empty_and_inert() {
let p = DiagnosticPolicy::default();
assert!(p.entries.is_empty());
assert_eq!(p.verb_for("anything", None), None);
}
#[test]
fn verb_for_returns_the_governing_verb() {
let p = DiagnosticPolicy {
entries: vec![entry(PolicyVerb::Allow, "layout.off_canvas")],
};
assert_eq!(
p.verb_for("layout.off_canvas", Some("r.off")),
Some(&PolicyVerb::Allow)
);
assert_eq!(p.verb_for("token.unused", None), None);
}
#[test]
fn verb_for_is_last_wins() {
let p = DiagnosticPolicy {
entries: vec![
entry(PolicyVerb::Deny, "node.unknown_property"),
entry(PolicyVerb::Warn, "node.unknown_property"),
],
};
assert_eq!(
p.verb_for("node.unknown_property", None),
Some(&PolicyVerb::Warn)
);
}
#[test]
fn scoped_entry_matches_only_its_subjects() {
let p = DiagnosticPolicy {
entries: vec![PolicyEntry {
verb: PolicyVerb::Allow,
code: "layout.off_canvas".to_owned(),
subjects: vec!["bg.glow".to_owned(), "bg.rim".to_owned()],
source_span: None,
}],
};
assert_eq!(
p.verb_for("layout.off_canvas", Some("bg.glow")),
Some(&PolicyVerb::Allow)
);
assert_eq!(
p.verb_for("layout.off_canvas", Some("bg.rim")),
Some(&PolicyVerb::Allow)
);
assert_eq!(p.verb_for("layout.off_canvas", Some("shape.1")), None);
assert_eq!(p.verb_for("layout.off_canvas", None), None);
}
}