1//! A host's answers to the script, as text that two hosts can be compared on with `cmp`. 2 3use crate::host::{Host, Reply}; 4use crate::script::{Step, script}; 5 6/// One step's answer as a block: its name, the status, the content type, the body. 7pub fn block(step: &Step, reply: &Reply) -> String { 8 format!("### {}\n{} {}\n{}\n{}\n", step.name, reply.status, reply.content_type.as_deref().unwrap_or("-"), reply.body.len(), reply.body) 9} 10 11/// A step that could not be asked at all. 12pub fn failed(step: &Step, why: &str) -> String { 13 format!("### {}\nNO ANSWER {why}\n", step.name) 14} 15 16/// Runs the script against `host` in `household` and returns the transcript and the elapsed time of each step. 17pub fn run(host: &Host, household: &str) -> (String, Vec<(String, std::time::Duration)>) { 18 let mut text = String::new(); 19 let mut times = Vec::new(); 20 for step in script() { 21 let started = std::time::Instant::now(); 22 let answer = host.send(step.method, step.path, household, &step.body); 23 times.push((step.name.to_owned(), started.elapsed())); 24 text.push_str(&match answer { 25 Ok(reply) => block(&step, &reply), 26 Err(e) => failed(&step, &e), 27 }); 28 } 29 (text, times) 30} 31 32#[cfg(test)] 33mod tests { 34 use super::*; 35 36 #[test] 37 fn a_block_says_what_a_device_could_see() { 38 let step = Step { name: "n", method: "POST", path: "/p", body: String::new(), expect: 200 }; 39 let reply = Reply { status: 200, content_type: Some("application/json".into()), body: "{}".into() }; 40 assert_eq!(block(&step, &reply), "### n\n200 application/json\n2\n{}\n"); 41 let none = Reply { status: 405, content_type: None, body: String::new() }; 42 assert_eq!(block(&step, &none), "### n\n405 -\n0\n\n"); 43 } 44}