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<String, Value>) -> Result<Phase, String> {
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<Phase>,
}
fn get_phases(object: &Map<String, Value>) -> Result<Vec<Phase>, 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<Self, String>;
fn get_suite(&self) -> Result<Suite, String>;
}
impl SuiteContainer for Value {
fn from_file(path: &str) -> Result<Value, String> {
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<Suite, String> {
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,
})
}
}