use crate::dependencies::{RelatesKind, Severity};
use crate::KanbanResult;
use uuid::Uuid;
pub trait GraphOperations {
fn attach_children(&mut self, parent: Uuid, children: Vec<Uuid>) -> KanbanResult<()>;
fn detach_children(&mut self, parent: Uuid, children: Vec<Uuid>) -> KanbanResult<()>;
fn attach_child(&mut self, parent: Uuid, child: Uuid) -> KanbanResult<()> {
self.attach_children(parent, vec![child])
}
fn detach_child(&mut self, parent: Uuid, child: Uuid) -> KanbanResult<()> {
self.detach_children(parent, vec![child])
}
fn list_children_of(&self, parent: Uuid) -> KanbanResult<Vec<Uuid>>;
fn list_parents_of(&self, child: Uuid) -> KanbanResult<Vec<Uuid>>;
fn block(&mut self, blocker: Uuid, blocked: Uuid, severity: Severity) -> KanbanResult<()>;
fn unblock(&mut self, blocker: Uuid, blocked: Uuid) -> KanbanResult<()>;
fn list_blocked_by(&self, blocker: Uuid) -> KanbanResult<Vec<Uuid>>;
fn list_blockers_of(&self, blocked: Uuid) -> KanbanResult<Vec<Uuid>>;
fn relate(&mut self, a: Uuid, b: Uuid, kind: RelatesKind) -> KanbanResult<()>;
fn dissociate(&mut self, a: Uuid, b: Uuid) -> KanbanResult<()>;
fn list_related_to(&self, card: Uuid) -> KanbanResult<Vec<Uuid>>;
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn trait_is_object_safe() {
fn _accepts_dyn(_: &dyn GraphOperations) {}
}
#[test]
fn trait_does_not_require_kanban_operations_supertrait() {
struct GraphOnly;
impl GraphOperations for GraphOnly {
fn attach_children(&mut self, _: Uuid, _: Vec<Uuid>) -> KanbanResult<()> {
Ok(())
}
fn detach_children(&mut self, _: Uuid, _: Vec<Uuid>) -> KanbanResult<()> {
Ok(())
}
fn list_children_of(&self, _: Uuid) -> KanbanResult<Vec<Uuid>> {
Ok(Vec::new())
}
fn list_parents_of(&self, _: Uuid) -> KanbanResult<Vec<Uuid>> {
Ok(Vec::new())
}
fn block(&mut self, _: Uuid, _: Uuid, _: Severity) -> KanbanResult<()> {
Ok(())
}
fn unblock(&mut self, _: Uuid, _: Uuid) -> KanbanResult<()> {
Ok(())
}
fn list_blocked_by(&self, _: Uuid) -> KanbanResult<Vec<Uuid>> {
Ok(Vec::new())
}
fn list_blockers_of(&self, _: Uuid) -> KanbanResult<Vec<Uuid>> {
Ok(Vec::new())
}
fn relate(&mut self, _: Uuid, _: Uuid, _: RelatesKind) -> KanbanResult<()> {
Ok(())
}
fn dissociate(&mut self, _: Uuid, _: Uuid) -> KanbanResult<()> {
Ok(())
}
fn list_related_to(&self, _: Uuid) -> KanbanResult<Vec<Uuid>> {
Ok(Vec::new())
}
}
let mut g = GraphOnly;
let a = Uuid::new_v4();
let b = Uuid::new_v4();
g.attach_child(a, b).unwrap();
g.block(a, b, Severity::High).unwrap();
g.relate(a, b, RelatesKind::Duplicates).unwrap();
}
#[test]
fn test_attach_child_default_routes_through_attach_children() {
use std::cell::RefCell;
struct Recorder {
attach_calls: RefCell<Vec<(Uuid, Vec<Uuid>)>>,
detach_calls: RefCell<Vec<(Uuid, Vec<Uuid>)>>,
}
impl GraphOperations for Recorder {
fn attach_children(&mut self, parent: Uuid, children: Vec<Uuid>) -> KanbanResult<()> {
self.attach_calls.borrow_mut().push((parent, children));
Ok(())
}
fn detach_children(&mut self, parent: Uuid, children: Vec<Uuid>) -> KanbanResult<()> {
self.detach_calls.borrow_mut().push((parent, children));
Ok(())
}
fn list_children_of(&self, _: Uuid) -> KanbanResult<Vec<Uuid>> {
Ok(Vec::new())
}
fn list_parents_of(&self, _: Uuid) -> KanbanResult<Vec<Uuid>> {
Ok(Vec::new())
}
fn block(&mut self, _: Uuid, _: Uuid, _: Severity) -> KanbanResult<()> {
Ok(())
}
fn unblock(&mut self, _: Uuid, _: Uuid) -> KanbanResult<()> {
Ok(())
}
fn list_blocked_by(&self, _: Uuid) -> KanbanResult<Vec<Uuid>> {
Ok(Vec::new())
}
fn list_blockers_of(&self, _: Uuid) -> KanbanResult<Vec<Uuid>> {
Ok(Vec::new())
}
fn relate(&mut self, _: Uuid, _: Uuid, _: RelatesKind) -> KanbanResult<()> {
Ok(())
}
fn dissociate(&mut self, _: Uuid, _: Uuid) -> KanbanResult<()> {
Ok(())
}
fn list_related_to(&self, _: Uuid) -> KanbanResult<Vec<Uuid>> {
Ok(Vec::new())
}
}
let mut r = Recorder {
attach_calls: RefCell::new(Vec::new()),
detach_calls: RefCell::new(Vec::new()),
};
let parent = Uuid::new_v4();
let child = Uuid::new_v4();
r.attach_child(parent, child).unwrap();
r.detach_child(parent, child).unwrap();
assert_eq!(
r.attach_calls.borrow().as_slice(),
&[(parent, vec![child])],
"attach_child must route through attach_children with vec![child]"
);
assert_eq!(
r.detach_calls.borrow().as_slice(),
&[(parent, vec![child])],
"detach_child must route through detach_children with vec![child]"
);
}
}