use serde_json::{self, Map, Value}; use std::fs::File; use super::responses::Responses; use super::outcome::Outcome; pub struct Phase { pub operation: Responses, pub outcome: Outcome, } impl Phase { fn from_json(object: &Map) -> Result { let operation = val_or_err!(object.get("responses"), Some(&Value::Array(ref array)) => try!(Responses::from_json(array)), "No `responses` array found."); let outcome = val_or_err!(object.get("outcome"), Some(&Value::Object(ref obj)) => try!(Outcome::from_json(obj)), "No `outcome` object found."); Ok(Phase { operation: operation, outcome: outcome, }) } } pub struct Suite { pub uri: String, pub phases: Vec, } fn get_phases(object: &Map) -> Result, String> { let array = val_or_err!(object.get("phases"), Some(&Value::Array(ref array)) => array.clone(), "No `phases` array found"); let mut phases = vec![]; for json in array { let obj = val_or_err!(json, Value::Object(ref obj) => obj.clone(), "`phases` array must only contain objects"); let phase = match Phase::from_json(&obj) { Ok(phase) => phase, Err(s) => return Err(s), }; phases.push(phase); } Ok(phases) } pub trait SuiteContainer: Sized { fn from_file(path: &str) -> Result; fn get_suite(&self) -> Result; } impl SuiteContainer for Value { fn from_file(path: &str) -> Result { let mut file = File::open(path).expect(&format!("Unable to open file: {}", path)); Ok(serde_json::from_reader(&mut file).expect( &format!("Invalid JSON file: {}", path), )) } fn get_suite(&self) -> Result { let object = val_or_err!(*self, Value::Object(ref object) => object.clone(), "`get_suite` requires a JSON object"); let uri = val_or_err!(object.get("uri"), Some(&Value::String(ref s)) => s.clone(), "`get_suite` requires a connection uri"); let phases = try!(get_phases(&object)); Ok(Suite { uri: uri, phases: phases, }) } }