diff --git a/src/symbols/hook.rs b/src/symbols/hook.rs new file mode 100644 index 0000000..30a8ed8 --- /dev/null +++ b/src/symbols/hook.rs @@ -0,0 +1,103 @@ +use std::error::Error; +use std::fmt; + +use symbols::Symbol; + +pub struct Hook where A: Symbol, B: Symbol { + a: A, + b: B +} + +impl Hook where A: Symbol, B: Symbol { + pub fn new(a: A, b: B) -> Self { + Hook { a: a, b: b } + } +} + +impl Symbol for Hook where A: Symbol, B: Symbol { + fn target_reached(&self) -> Result> { + self.a.target_reached().and_then(|reached| if reached { self.b.target_reached() } else { Ok(reached) }) + } + + fn execute(&self) -> Result<(), Box> { + try!(self.a.execute()); + self.b.execute() + } +} + +impl fmt::Display for Hook where A: Symbol, B: Symbol { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error>{ + write!(f, "Hook {} and then {}", self.a, self.b) + } +} + +#[cfg(test)] +mod test { + use std::error::Error; + use std::fmt; + + use symbols::Symbol; + use symbols::hook::Hook; + + struct ErrSymbol(String); + impl Symbol for ErrSymbol { + fn target_reached(&self) -> Result> { Err(self.0.clone().into()) } + fn execute(&self) -> Result<(), Box> { Err(self.0.clone().into()) } + } + impl fmt::Display for ErrSymbol { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error>{ write!(f, "") } } + + struct OkSymbol(bool); + impl Symbol for OkSymbol { + fn target_reached(&self) -> Result> { Ok(self.0) } + fn execute(&self) -> Result<(), Box> { Ok(()) } + } + impl fmt::Display for OkSymbol { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error>{ write!(f, "") } } + + #[test] + fn first_target_reached_fails() { + let res = Hook::new(ErrSymbol("first".into()), ErrSymbol("second".into())).target_reached(); + assert_eq!(res.unwrap_err().description(), "first"); + } + + #[test] + fn first_target_not_reached() { + let res = Hook::new(OkSymbol(false), ErrSymbol("second".into())).target_reached(); + assert_eq!(res.unwrap(), false); + } + + #[test] + fn second_target_reached_fails() { + let res = Hook::new(OkSymbol(true), ErrSymbol("second".into())).target_reached(); + assert_eq!(res.unwrap_err().description(), "second"); + } + + #[test] + fn second_target_not_reached() { + let res = Hook::new(OkSymbol(true), OkSymbol(false)).target_reached(); + assert_eq!(res.unwrap(), false); + } + + #[test] + fn everything_reached() { + let res = Hook::new(OkSymbol(true), OkSymbol(true)).target_reached(); + assert_eq!(res.unwrap(), true); + } + + #[test] + fn first_execute_fails() { + let res = Hook::new(ErrSymbol("first".into()), ErrSymbol("second".into())).execute(); + assert_eq!(res.unwrap_err().description(), "first"); + } + + #[test] + fn second_execute_fails() { + let res = Hook::new(OkSymbol(true), ErrSymbol("second".into())).execute(); + assert_eq!(res.unwrap_err().description(), "second"); + } + + #[test] + fn everything_executes() { + let res = Hook::new(OkSymbol(true), OkSymbol(true)).execute(); + assert_eq!(res.unwrap(), ()); + } +} diff --git a/src/symbols/mod.rs b/src/symbols/mod.rs index bc58be4..0f5f66b 100644 --- a/src/symbols/mod.rs +++ b/src/symbols/mod.rs @@ -18,3 +18,4 @@ pub mod npm; pub mod user; pub mod systemd; pub mod nginx; +pub mod hook;