diff --git a/tests/common/dot_writer.rs b/tests/common/dot_writer.rs new file mode 100644 index 000000000..94ca980ea --- /dev/null +++ b/tests/common/dot_writer.rs @@ -0,0 +1,41 @@ +use std::io::{self, Write}; + +use cucumber::{cli, event, parser, Event}; + +pub struct CustomWriter; + +impl cucumber::Writer for CustomWriter { + type Cli = cli::Empty; // we provide no CLI options + + async fn handle_event(&mut self, ev: parser::Result>>, _: &Self::Cli) { + match ev { + Ok(Event { value, .. }) => match value { + event::Cucumber::Feature(_feature, ev) => match ev { + event::Feature::Started => { + print!(".") + } + event::Feature::Scenario(_scenario, ev) => match ev.event { + event::Scenario::Started => { + print!(".") + } + event::Scenario::Step(_step, ev) => match ev { + event::Step::Started => { + print!(".") + } + event::Step::Passed(..) => print!("."), + event::Step::Skipped => print!("-"), + event::Step::Failed(_, _, _, _err) => { + print!("x") + } + }, + _ => {} + }, + _ => {} + }, + _ => {} + }, + Err(e) => println!("Error: {e}"), + } + let _ = io::stdout().flush(); + } +} diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 79611fa75..1d1a29356 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -1,4 +1,5 @@ pub mod cli_arguments; +pub mod dot_writer; pub mod f64_utils; pub mod file_util; pub mod hash_util; diff --git a/tests/common/osrm_world.rs b/tests/common/osrm_world.rs index 7a230b56b..50581ba95 100644 --- a/tests/common/osrm_world.rs +++ b/tests/common/osrm_world.rs @@ -98,7 +98,7 @@ impl OSRMWorld { } pub fn get_location(&self, name: char) -> Point { - match name { + *match name { // TODO: move lookup to world '0'..='9' => self .known_locations @@ -110,7 +110,6 @@ impl OSRMWorld { .expect("test case specifies unknown osm node: {name}"), _ => unreachable!("nodes have to be name in [0-9][a-z]"), } - .clone() } pub fn add_location(&mut self, name: char, location: Point) { diff --git a/tests/cucumber.rs b/tests/cucumber.rs index f17740cf7..4e673c539 100644 --- a/tests/cucumber.rs +++ b/tests/cucumber.rs @@ -5,16 +5,19 @@ mod common; use cheap_ruler::CheapRuler; use clap::Parser; use common::{ - cli_arguments::Args, f64_utils::approx_equal, hash_util::md5_of_osrm_executables, - nearest_response::NearestResponse, osm::OSMWay, osrm_world::OSRMWorld, - task_starter::TaskStarter, + cli_arguments::Args, dot_writer::CustomWriter, f64_utils::approx_equal, hash_util::md5_of_osrm_executables, nearest_response::NearestResponse, osm::OSMWay, osrm_world::OSRMWorld, task_starter::TaskStarter }; use core::panic; -use cucumber::{self, gherkin::Step, given, when, World}; +use cucumber::{gherkin::Step, given, when, World, WriterExt}; use futures::{future, FutureExt}; use geo_types::{point, Point}; use log::debug; -use std::{collections::HashMap, fs::File, io::Write, time::Duration}; +use std::{ + collections::HashMap, + fs::File, + io::Write, + time::Duration, +}; use ureq::Agent; const DEFAULT_ORIGIN: [f64; 2] = [1., 1.]; // TODO: move to world? @@ -189,7 +192,7 @@ fn request_nearest(world: &mut OSRMWorld, step: &Step) { row.len() >= 2, "test case broken: row needs to have at least two entries. One for query input, one for expected result" ); - let query = row.get(0).unwrap(); + let query = row.first().unwrap(); let expected = row.get(1).unwrap(); assert_eq!(query.len(), 1); assert_eq!(expected.len(), 1); @@ -247,11 +250,6 @@ fn request_nearest(world: &mut OSRMWorld, step: &Step) { } } -pub fn approx_equal(a: f64, b: f64, dp: u8) -> bool { - let p = 10f64.powi(-(dp as i32)); - (a - b).abs() < p -} - fn main() { let args = Args::parse(); debug!("arguments: {:?}", args); @@ -268,6 +266,7 @@ fn main() { future::ready(()).boxed() }) - .run_and_exit("features/nearest/pick.feature"), + .with_writer(CustomWriter.normalized()) + .run("features/nearest/pick.feature"), ); } diff --git a/tests/osm.rs b/tests/osm.rs deleted file mode 100644 index fdc46e25a..000000000 --- a/tests/osm.rs +++ /dev/null @@ -1,264 +0,0 @@ -// TODO: consider trait for OSM entities -// TODO: better error handling in XML creation -// FIXME: today nodes are stored twice -// TODO: move node lookup by name to here -use std::collections::HashMap; - -use xml_builder::{XMLBuilder, XMLElement, XMLVersion}; - -static OSM_USER: &str = "osrm"; -static OSM_TIMESTAMP :&str = "2000-01-01T00:00:00Z"; -static OSM_UID: &str = "1"; - -#[derive(Clone, Debug, Default)] -pub struct OSMNode { - pub id: u64, - pub lat: f64, - pub lon: f64, - pub tags: HashMap, -} - -impl OSMNode { - pub fn add_tag(&mut self, key: &str, value: &str) { - self.tags.insert(key.into(), value.into()); - } - - // pub fn set_id_(&mut self, id: u64) { - // self.id = id; - // } - - // pub fn set_tags(&mut self, tags: HashMap) { - // self.tags = tags - // } - - pub fn to_xml(&self) -> XMLElement { - let mut node = XMLElement::new("node"); - node.add_attribute("id", &self.id.to_string()); - node.add_attribute("version", "1"); - node.add_attribute("uid", OSM_UID); - node.add_attribute("user", OSM_USER); - node.add_attribute("timestamp", OSM_TIMESTAMP); - node.add_attribute("lon", &format!("{:?}", self.lon)); - node.add_attribute("lat", &format!("{:?}", self.lat)); - - if !self.tags.is_empty() { - for (key, value) in &self.tags { - let mut tags = XMLElement::new("tag"); - tags.add_attribute("k", key); - tags.add_attribute("v", value); - node.add_child(tags).unwrap(); - } - } - - node - } -} - -#[derive(Clone, Debug, Default)] -pub struct OSMWay { - pub id: u64, - pub osm_user: String, - pub osm_time_stamp: String, - pub osm_uid: u64, - pub tags: HashMap, - pub nodes: Vec, - pub add_locations: bool, -} - -impl OSMWay { - pub fn add_node(&mut self, node: OSMNode) { - self.nodes.push(node); - } - - // pub fn set_tags(&mut self, tags: HashMap) { - // self.tags = tags; - // } - - pub fn to_xml(&self) -> XMLElement { - let mut way = XMLElement::new("way"); - way.add_attribute("id", &self.id.to_string()); - way.add_attribute("version", "1"); - way.add_attribute("uid", &self.osm_uid.to_string()); - way.add_attribute("user", &self.osm_user); - way.add_attribute("timestamp", &self.osm_time_stamp); - - assert!(self.nodes.len() >= 2); - - for node in &self.nodes { - let mut nd = XMLElement::new("nd"); - nd.add_attribute("ref", &node.id.to_string()); - if self.add_locations { - nd.add_attribute("lon", &format!("{:?}", node.lon)); - nd.add_attribute("lat", &format!("{:?}", node.lat)); - } - way.add_child(nd).unwrap(); - } - - if !self.tags.is_empty() { - for (key, value) in &self.tags { - let mut tags = XMLElement::new("tag"); - tags.add_attribute("k", key); - tags.add_attribute("v", value); - way.add_child(tags).unwrap(); - } - } - - way - } -} - -#[derive(Clone, Debug)] -pub struct Member { - pub id: u64, - pub member_type: String, - pub member_role: String, -} - -#[derive(Clone, Debug)] -pub struct OSMRelation { - pub id: u64, - pub osm_user: String, - pub osm_time_stamp: String, - pub osm_uid: String, - pub members: Vec, - pub tags: HashMap, -} - -// impl OSMRelation { -// pub fn add_member(&mut self, member_type: String, id: u64, member_role: String) { -// self.members.push(Member { -// id, -// member_type, -// member_role, -// }); -// } - -// pub fn add_tag(&mut self, key: &str, value: &str) { -// self.tags.insert(key.into(), value.into()); -// } -// } - -#[derive(Debug, Default)] -pub struct OSMDb { - nodes: Vec<(char, OSMNode)>, - ways: Vec, - relations: Vec, -} - -impl OSMDb { - pub fn add_node(&mut self, node: OSMNode) { - let name = node.tags.get("name").unwrap(); - assert!(name.len() == 1, "name needs to be of length 1, but was \"{name}\""); - self.nodes.push((name.chars().next().unwrap(), node)); - } - - pub fn find_node(&self, search_name: char) -> Option<&(char, OSMNode)> { - // TODO: this is a linear search. - self.nodes.iter().find(|(name, _node)| { - search_name == *name - }) - } - - pub fn add_way(&mut self, way: OSMWay) { - self.ways.push(way); - } - - // pub fn add_relation(&mut self, relation: OSMRelation) { - // self.relations.push(relation); - // } - - // pub fn clear(&mut self) { - // self.nodes.clear(); - // self.ways.clear(); - // self.relations.clear(); - // } - - pub fn to_xml(&self) -> String { - let mut xml = XMLBuilder::new() - .version(XMLVersion::XML1_0) - .encoding("UTF-8".into()) - .build(); - - let mut osm = XMLElement::new("osm"); - osm.add_attribute("generator", "osrm-test"); - osm.add_attribute("version", "0.6"); - - for (_, node) in &self.nodes { - osm.add_child(node.to_xml()).unwrap(); - } - - for way in &self.ways { - osm.add_child(way.to_xml()).unwrap(); - } - - xml.set_root_element(osm); - - let mut writer: Vec = Vec::new(); - xml.generate(&mut writer).unwrap(); - String::from_utf8(writer).unwrap() - } - - pub fn node_len(&self) -> usize { - self.nodes.len() - } - pub fn way_len(&self) -> usize { - self.ways.len() - } - pub fn relation_len(&self) -> usize { - self.relations.len() - } -} - -#[cfg(test)] -mod test { - use super::{OSMNode, OSMWay}; - - #[test] - fn empty_db_by_default() { - let osm_db = crate::OSMDb::default(); - assert_eq!(0, osm_db.node_len()); - assert_eq!(0, osm_db.way_len()); - assert_eq!(0, osm_db.relation_len()); - } - - #[test] - fn osm_db_with_single_node() { - let mut osm_db = crate::OSMDb::default(); - - let mut node1 = OSMNode { - id: 123, - lat: 50.1234, - lon: 8.9876, - ..Default::default() - }; - - let mut node2 = OSMNode { - id: 321, - lat: 50.1234, - lon: 8.9876, - ..Default::default() - }; - node1.add_tag("name", "a"); - node2.add_tag("name", "b"); - osm_db.add_node(node1.clone()); - osm_db.add_node(node2.clone()); - - let mut way = OSMWay { - id: 890, - osm_user: "osrm".into(), - osm_time_stamp: "2000-01-01T00:00:00Z".into(), - osm_uid: 1, - ..Default::default() - }; - way.nodes.push(node1); - way.nodes.push(node2); - - osm_db.add_way(way); - - let actual = osm_db.to_xml(); - let expected = "\n\n\t\n\t\t\n\t\n\t\n\t\t\n\t\n\t\n\t\t\n\t\t\n\t\n\n"; - - println!("{actual}"); - assert_eq!(actual, expected); - } -}