use std::{
fs::{create_dir_all, OpenOptions},
io::Write,
path::PathBuf,
};
pub fn get_mf_fixture_dir_for(path_name: &str) -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("../vendor/microformats-test/tests")
.join(path_name)
}
fn generate_parameterized_tests() {
if PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("../vendor")
.exists()
{
let suites = [
"microformats-v2/h-adr",
"microformats-v2/h-card",
"microformats-v2/h-entry",
"microformats-v2/h-event",
"microformats-v2/h-feed",
"microformats-v2/h-geo",
"microformats-v2/h-product",
"microformats-v2/h-recipe",
"microformats-v2/h-resume",
"microformats-v2/h-review",
"microformats-v2/h-review-aggregate",
"microformats-v2/rel",
];
let ignored_tests: Vec<_> =
include_str!("src/parse/test/suite/ignored_generated_tests.txt")
.split('\n')
.collect();
let test_files = suites
.iter()
.map(|suite| {
let fixtures = collect_fixtures_for(suite);
let (suite_dir, suite_name) = suite.split_once('/').unwrap();
let safe_suite_name = suite_name.replace('-', "_");
let suite_path = PathBuf::from(format!(
"{}/src/parse/test/suite/generated/{}",
env!("CARGO_MANIFEST_DIR"),
suite_dir.replace('-', "_")
));
if !suite_path.exists() {
create_dir_all(suite_path.clone()).unwrap_or_else(|_| {
panic!(
"failed to create the recursive directory {:?} for the test suite {:?}",
suite_path, suite_name
)
});
}
let test_file_location = suite_path.join(format!("{}.rs", safe_suite_name));
let mut f = OpenOptions::new()
.create(true)
.truncate(true)
.write(true)
.open(&test_file_location)
.unwrap_or_else(|_| {
panic!(
"Could not create the file for the test {} at {:?}.",
safe_suite_name, test_file_location
)
});
let test_header = format!(
"// Tests for {suite_name}
#![allow(non_snake_case, unused_imports)]
use crate::parse::test::suite::check_fixture_for_parser;
",
suite_name = suite
)
.to_string();
let test_contents = fixtures
.into_iter()
.filter(|test_case| !ignored_tests.contains(&test_case.as_str()))
.map(|test_name| {
let safe_test_name = test_name
.replace((suite.to_string() + "/").as_str(), "")
.replace('/', "__")
.replace('-', "_");
format!(
r#"
#[tracing_test::traced_test]
#[test]
fn {name}() {{
check_fixture_for_parser("{fixture_name}");
}}"#,
name = safe_test_name,
fixture_name = test_name
)
})
.collect::<Vec<_>>()
.join("\n")
.trim()
.to_string();
write!(f, "{}{}", test_header, test_contents).expect("Failed to write test file.");
test_file_location
})
.collect::<Vec<_>>();
let generated_test_module_file = PathBuf::from(format!(
"{}/src/parse/test/suite/generated/mod.rs",
env!("CARGO_MANIFEST_DIR")
));
let version_mods = test_files
.into_iter()
.filter_map(|test_file_path| {
let file_name = test_file_path
.file_name()
.and_then(|os| os.to_str())
.map(|t| t.to_string());
let dir_name = test_file_path
.parent()
.and_then(|p| p.file_name())
.and_then(|os| os.to_str())
.map(|s| s.to_string());
file_name.and_then(|fin| dir_name.map(|dn| (dn, fin)))
})
.map(|(dir_name, file_name)| {
(dir_name, file_name.replace('-', "_").replace(".rs", ";"))
})
.map(|(version_name, suite_name)| {
let version_mod_file = format!(
"{}/src/parse/test/suite/generated/{}/mod.rs",
env!("CARGO_MANIFEST_DIR"),
version_name
);
if !PathBuf::from(version_mod_file.clone()).exists() {
std::fs::write(&version_mod_file, "").expect("cannot create mod file");
}
if !String::from_utf8_lossy(&std::fs::read(version_mod_file.clone()).unwrap())
.contains(&suite_name)
{
let mut f = OpenOptions::new()
.create(true)
.append(true)
.open(version_mod_file.clone())
.unwrap();
writeln!(f, "mod {}", suite_name)
.expect("Failed to add suite into version folder");
}
version_name
})
.fold(vec![], |mut acc, value| {
let mod_line = format!("mod {};", value);
if !acc.contains(&mod_line) {
acc.push(mod_line);
}
acc
})
.join("\n");
std::fs::write(generated_test_module_file.clone(), version_mods).unwrap_or_else(|_| {
panic!(
"failed to write out the module at {:?}",
generated_test_module_file
)
});
}
}
fn main() {
generate_parameterized_tests();
}
fn collect_fixtures_for(suite: &str) -> Vec<String> {
get_mf_fixture_dir_for(suite)
.read_dir()
.unwrap_or_else(|_| panic!("Couldn't find fixtures for testing '{}' support.", suite))
.filter_map(|file_path| file_path.ok())
.filter_map(|file_path| {
file_path
.path()
.extension()
.and_then(|s| s.to_str())
.map(|s| s.to_string())
.and_then(|f| {
if f == *"json" {
Some(file_path.path().to_owned())
} else {
None
}
})
})
.map(|whole_path| {
let file_name = whole_path
.clone()
.file_stem()
.and_then(|s| s.to_str())
.map(|s| s.to_string())
.unwrap_or_default();
let test_name = format!("{}/{}", suite, file_name);
test_name
})
.collect()
}