use serde::Deserialize;
use skyway::SkywayError;
use skyway::filter::auto_parse_filter;
use std::path::{Path, PathBuf};
use std::sync::mpsc::Receiver;
use toml;
use skyway::{
FileFormatOptions, OsmFormat,
chunks::ElementChunk,
elements::{Element, Metadata},
filter::ElementFilter,
readers::Reader,
sort::SortStrategy,
};
#[cfg(feature = "json")]
use skyway::readers::JsonReader;
#[cfg(feature = "opl")]
use skyway::readers::OplReader;
#[cfg(feature = "pbf")]
use skyway::readers::PbfReader;
#[cfg(feature = "xml")]
use skyway::readers::XmlReader;
#[derive(Debug, Deserialize)]
pub struct ConversionConfig {
pub name: String,
pub description: String,
pub input: String,
pub filters: Option<Vec<String>>,
pub omit_references: Option<bool>,
pub preserve_generator: Option<bool>,
pub expected_output: String,
}
pub fn read_elements_and_metadata(
path: &Path,
filters: Vec<Box<dyn ElementFilter>>,
omit_references: bool,
preserve_generator: bool,
) -> Result<(Receiver<ElementChunk>, Receiver<Metadata>), SkywayError> {
let chunk_size = 8000;
let sort_strategy = SortStrategy::None;
match OsmFormat::parse(None, &Some(path.to_owned())) {
#[cfg(feature = "opl")]
Ok(OsmFormat::Opl) => OplReader {}.run_conversion(
Some(path.to_owned()),
chunk_size,
filters,
omit_references,
sort_strategy,
preserve_generator,
),
#[cfg(feature = "xml")]
Ok(OsmFormat::Xml) => XmlReader {}.run_conversion(
Some(path.to_owned()),
chunk_size,
filters,
omit_references,
sort_strategy,
preserve_generator,
),
#[cfg(feature = "json")]
Ok(OsmFormat::Json) | Ok(OsmFormat::Overpass) => JsonReader {}.run_conversion(
Some(path.to_owned()),
chunk_size,
filters,
omit_references,
sort_strategy,
preserve_generator,
),
#[cfg(feature = "pbf")]
Ok(OsmFormat::Pbf) => PbfReader {}.run_conversion(
Some(path.to_owned()),
chunk_size,
filters,
omit_references,
sort_strategy,
preserve_generator,
),
_ => Err(SkywayError::InvalidInputFile),
}
}
pub fn run_test(conversion_dir: &Path) {
let config_path = conversion_dir.join("config.toml");
let config_content = std::fs::read_to_string(config_path).unwrap();
let config: ConversionConfig = toml::from_str(&config_content).unwrap();
let input_path = conversion_dir.join(&config.input);
let expected_output_path = conversion_dir.join(&config.expected_output);
let omit_references = match config.omit_references {
Some(b) => b,
None => false,
};
let preserve_generator = match config.preserve_generator {
Some(p) => p,
None => false,
};
let mut parsed_filters = Vec::new();
if let Some(filters) = config.filters {
for filter_contents in filters {
let filter_path = conversion_dir.join(&filter_contents);
let actual_filter_content = std::fs::read_to_string(filter_path).unwrap();
let filter = auto_parse_filter(&actual_filter_content).unwrap();
parsed_filters.push(filter);
}
}
let (output_element_receiver, _) = read_elements_and_metadata(
&input_path,
parsed_filters,
omit_references,
preserve_generator,
)
.unwrap();
let output_chunks: Vec<ElementChunk> = output_element_receiver.iter().collect();
let mut output_elements: Vec<Element> = Vec::new();
for chunk in output_chunks {
output_elements.extend(chunk.into_iter());
}
let (expected_element_receiver, _) =
read_elements_and_metadata(&expected_output_path, Vec::new(), false, true).unwrap();
let expected_chunks: Vec<ElementChunk> = expected_element_receiver.iter().collect();
let mut expected_elements: Vec<Element> = Vec::new();
for chunk in expected_chunks {
expected_elements.extend(chunk.into_iter());
}
assert_eq!(output_elements.len(), expected_elements.len());
for (_, (actual, expected)) in output_elements
.iter()
.zip(expected_elements.iter())
.enumerate()
{
assert_eq!(actual, expected);
}
}
pub fn setup_test(path_dirs: &[&str], test_name: &str) {
let mut test_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests");
for dir in path_dirs {
test_dir = test_dir.join(dir);
}
test_dir = test_dir.join(test_name);
run_test(&test_dir);
}
#[macro_export]
macro_rules! define_test {
($test_name:ident) => {
#[test]
fn $test_name() {
$crate::utils::setup_test(CURRENT_DIR, stringify!($test_name));
}
};
}