From 3f14453f5b3ae55fe584715f7653da25a5881771 Mon Sep 17 00:00:00 2001 From: Dennis Date: Thu, 30 May 2024 18:23:03 +0200 Subject: [PATCH] Add test case parsing for nearest and osrm-routed startup --- tests/common/osrm_world.rs | 15 ++++++-- tests/cucumber.rs | 77 ++++++++++++++++++++++++++++++++------ 2 files changed, 78 insertions(+), 14 deletions(-) diff --git a/tests/common/osrm_world.rs b/tests/common/osrm_world.rs index d32423dce..e74d3a1d0 100644 --- a/tests/common/osrm_world.rs +++ b/tests/common/osrm_world.rs @@ -13,7 +13,7 @@ pub struct OSRMWorld { pub osm_id: u64, pub profile: String, - pub known_osm_nodes: HashSet, + pub known_osm_nodes: HashMap, pub known_locations: HashMap, pub osm_db: OSMDb, @@ -37,7 +37,7 @@ impl OSRMWorld { } pub fn add_osm_node(&mut self, name: char, location: Point, id: Option) { - if self.known_osm_nodes.contains(&name) { + if self.known_osm_nodes.contains_key(&name) { panic!("duplicate node: {name}"); } let id = match id { @@ -51,10 +51,19 @@ impl OSRMWorld { tags: HashMap::from([("name".to_string(), name.to_string())]), }; - self.known_osm_nodes.insert(name); + self.known_osm_nodes.insert(name, location); self.osm_db.add_node(node); } + pub fn get_location(&self, name: char) -> Point { + match name { + // TODO: move lookup to world + '0'..='9' => self.known_locations.get(&name).expect("test case specifies unknown location: {name}"), + 'a'..='z' => self.known_osm_nodes.get(&name).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) { if self.known_locations.contains_key(&name) { panic!("duplicate location: {name}") diff --git a/tests/cucumber.rs b/tests/cucumber.rs index 1b53195c2..57e19f9dd 100644 --- a/tests/cucumber.rs +++ b/tests/cucumber.rs @@ -2,20 +2,21 @@ extern crate clap; mod common; -use core::panic; -use std::fmt::Display; -use std::fs::{create_dir_all, File}; -use std::io::{Read, Write}; -use std::path::PathBuf; -use std::{env, fs}; use crate::common::osrm_world::OSRMWorld; use cheap_ruler::CheapRuler; use clap::Parser; use common::lexicographic_file_walker::LexicographicFileWalker; use common::osm::OSMWay; +use core::panic; use cucumber::{self, gherkin::Step, given, when, World}; use futures::{future, FutureExt}; use geo_types::{point, Point}; +use std::fmt::Display; +use std::fs::{create_dir_all, File}; +use std::io::{Read, Write}; +use std::path::PathBuf; +use std::process::Command; +use std::{env, fs}; const DEFAULT_ORIGIN: [f64; 2] = [1., 1.]; // TODO: move to world? const DEFAULT_GRID_SIZE: f64 = 100.; // TODO: move to world? @@ -90,8 +91,8 @@ fn set_ways(world: &mut OSRMWorld, step: &Step) { ); way.tags.insert("name".into(), token.clone()); token.chars().for_each(|name| { - if !world.known_osm_nodes.contains(&name) { - // TODO: this check is probably not necessary since it is also checked below + if !world.known_osm_nodes.contains_key(&name) { + // TODO: this check is probably not necessary since it is also checked below implicitly panic!("referenced unknown node {name} in way {token}"); } if let Some((_, node)) = world.osm_db.find_node(name) { @@ -161,7 +162,61 @@ fn request_nearest(world: &mut OSRMWorld, step: &Step) { // parse table from Step and build query list // run queries (in parallel) and validate results - todo!("nearest {step:?}"); + + let routed_path = path.join("build").join("osrm-routed"); + if !routed_path.exists() { + panic!("osrm-routed binary not found"); + } + + // parse query data + let t = &step.table.as_ref().expect("no query table specified"); + let test_cases: Vec<_> = t.rows.iter().skip(1).map(|row|{ + assert_eq!(row.len(), 2, "test case broken: row needs to have two entries"); + let query = row.get(0).unwrap(); + let expected = row.get(1).unwrap(); + assert_eq!(query.len(), 1); + assert_eq!(expected.len(), 1); + (query.chars().next().unwrap(), expected.chars().next().unwrap()) + }).collect(); + + let data_path = cache_path.join(world.scenario_id.to_owned() + ".osrm"); + println!("{routed_path:?} {}", data_path.to_str().unwrap()); + // TODO: this should be a let statement to reduce nesting? + match Command::new(routed_path) + .arg(data_path.to_str().unwrap()) + .spawn() + { + Ok(mut child) => { + + for (query, expected) in test_cases { + let query_coord = world.get_location(query); + let expected_coord = world.get_location(expected); + + println!("{query_coord:?} => {expected_coord:?}"); + } + + if let Err(e) = child.kill() { + panic!("shutdown failed: {e}"); + } + }, + Err(e) => panic!("{e}"), + } + + // parse expected results + + // run queries + + // check results + + // match Command::new(routed_path) + // .arg(data_path.to_str().unwrap().spawn(); + // .output() + // { + // Ok(o) => println!("{o:?}"), + // Err(e) => panic!("{e}"), + // } + + // todo!("nearest {step:?}"); } // TODO: move to different file @@ -299,7 +354,7 @@ fn main() { futures::executor::block_on( OSRMWorld::cucumber() - .before(move |_feature, _rule, scenario, world| { + .before(move |feature, _rule, scenario, world| { // TODO: move to function call below // ports the following logic: // let name = scenario.getName().toLowerCase().replace(/[/\-'=,():*#]/g, '') @@ -324,7 +379,7 @@ fn main() { s.truncate(64); world.scenario_id = format!("{}_{}", scenario.position.line, s); - world.set_scenario_specific_paths_and_digests(_feature.path.clone()); + world.set_scenario_specific_paths_and_digests(feature.path.clone()); world.osrm_digest = md5.digest().to_hex_lowercase(); // TODO: clean up cache if needed