use serde::{Deserialize, Deserializer, Serialize};
use crate::error::DomainError;
use super::SystemRoleId;
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
pub struct IndependenceRule {
reviewer: SystemRoleId,
reviewed: SystemRoleId,
}
impl IndependenceRule {
pub fn new(reviewer: SystemRoleId, subject: SystemRoleId) -> Result<Self, DomainError> {
if reviewer == subject {
return Err(DomainError::InvariantViolated {
reason: "a role cannot be required to be independent of itself",
});
}
Ok(Self {
reviewer,
reviewed: subject,
})
}
#[must_use]
pub const fn reviewer(&self) -> &SystemRoleId {
&self.reviewer
}
#[must_use]
pub const fn reviewed(&self) -> &SystemRoleId {
&self.reviewed
}
}
impl<'de> Deserialize<'de> for IndependenceRule {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
#[derive(Deserialize)]
#[serde(deny_unknown_fields)]
struct Wire {
reviewer: SystemRoleId,
reviewed: SystemRoleId,
}
let wire = Wire::deserialize(deserializer)?;
Self::new(wire.reviewer, wire.reviewed).map_err(serde::de::Error::custom)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_stored_self_review_is_refused_on_the_way_in() {
assert!(
serde_json::from_str::<IndependenceRule>(r#"{"reviewer":"a","reviewed":"a"}"#).is_err()
);
assert!(
serde_json::from_str::<IndependenceRule>(r#"{"reviewer":"a","reviewed":"b"}"#).is_ok()
);
}
#[test]
fn a_role_cannot_review_itself_independently() {
let reviewer = SystemRoleId::new("reviewer").unwrap();
assert!(IndependenceRule::new(reviewer.clone(), reviewer).is_err());
assert!(IndependenceRule::new(
SystemRoleId::new("reviewer").unwrap(),
SystemRoleId::new("author").unwrap()
)
.is_ok());
}
}