mirror of
https://git.proxmox.com/git/rustc
synced 2025-08-14 06:21:45 +00:00
188 lines
5.3 KiB
Rust
188 lines
5.3 KiB
Rust
fn main() {
|
|
generate_tests_from_spec()
|
|
}
|
|
|
|
// If the "gen-tests" feature is absent,
|
|
// this function will be compiled down to nothing
|
|
#[cfg(not(feature = "gen-tests"))]
|
|
fn generate_tests_from_spec() {}
|
|
|
|
// If the feature is present, generate tests
|
|
// from any .txt file present in the specs/ directory
|
|
//
|
|
// Test cases are present in the files in the
|
|
// following format:
|
|
//
|
|
// ```````````````````````````````` example
|
|
// markdown
|
|
// .
|
|
// expected html output
|
|
// ````````````````````````````````
|
|
#[cfg(feature = "gen-tests")]
|
|
fn generate_tests_from_spec() {
|
|
use std::fs::{self, File};
|
|
use std::io::{Read, Write};
|
|
use std::path::PathBuf;
|
|
|
|
// This is a hardcoded path to the CommonMark spec because it is not situated in
|
|
// the specs/ directory. It's in an array to easily chain it to the other iterator
|
|
// and make it easy to eventually add other hardcoded paths in the future if needed
|
|
let hardcoded = [
|
|
"./third_party/CommonMark/spec.txt",
|
|
"./third_party/GitHub/gfm_table.txt",
|
|
"./third_party/GitHub/gfm_strikethrough.txt",
|
|
"./third_party/GitHub/gfm_tasklist.txt",
|
|
];
|
|
let hardcoded_iter = hardcoded.into_iter().map(PathBuf::from);
|
|
|
|
// Create an iterator over the files in the specs/ directory that have a .txt extension
|
|
let spec_files = fs::read_dir("./specs")
|
|
.expect("Could not find the 'specs' directory")
|
|
.filter_map(Result::ok)
|
|
.map(|d| d.path())
|
|
.filter(|p| p.extension().map(|e| e.to_owned()).is_some())
|
|
.chain(hardcoded_iter)
|
|
.collect::<Vec<_>>();
|
|
|
|
for file_path in &spec_files {
|
|
let mut raw_spec = String::new();
|
|
|
|
File::open(&file_path)
|
|
.and_then(|mut f| f.read_to_string(&mut raw_spec))
|
|
.expect("Could not read the spec file");
|
|
|
|
let rs_test_file = PathBuf::from("./tests/suite/")
|
|
.join(file_path.file_name().expect("Invalid filename"))
|
|
.with_extension("rs");
|
|
|
|
let mut spec_rs =
|
|
File::create(&rs_test_file).expect(&format!("Could not create {:?}", rs_test_file));
|
|
|
|
let spec_name = file_path.file_stem().unwrap().to_str().unwrap();
|
|
|
|
let spec = Spec::new(&raw_spec);
|
|
let mut n_tests = 0;
|
|
|
|
spec_rs
|
|
.write(b"// This file is auto-generated by the build script\n")
|
|
.unwrap();
|
|
spec_rs
|
|
.write(b"// Please, do not modify it manually\n")
|
|
.unwrap();
|
|
spec_rs
|
|
.write(b"\nuse super::test_markdown_html;\n")
|
|
.unwrap();
|
|
|
|
for (i, testcase) in spec.enumerate() {
|
|
spec_rs
|
|
.write_fmt(format_args!(
|
|
r###"
|
|
#[test]
|
|
fn {}_test_{i}() {{
|
|
let original = r##"{original}"##;
|
|
let expected = r##"{expected}"##;
|
|
|
|
test_markdown_html(original, expected);
|
|
}}
|
|
"###,
|
|
spec_name,
|
|
i = i + 1,
|
|
original = testcase.original,
|
|
expected = testcase.expected
|
|
))
|
|
.unwrap();
|
|
|
|
n_tests += 1;
|
|
}
|
|
|
|
println!(
|
|
"cargo:warning=Generated {} tests in {:?}",
|
|
n_tests, rs_test_file
|
|
);
|
|
}
|
|
|
|
// write mods to suite/mod.rs
|
|
let suite_mod_file = PathBuf::from("./tests/suite/mod").with_extension("rs");
|
|
|
|
let mut mod_rs =
|
|
File::create(&suite_mod_file).expect(&format!("Could not create {:?}", &suite_mod_file));
|
|
|
|
mod_rs
|
|
.write(b"// This file is auto-generated by the build script\n")
|
|
.unwrap();
|
|
mod_rs
|
|
.write(b"// Please, do not modify it manually\n")
|
|
.unwrap();
|
|
mod_rs
|
|
.write(b"\npub use super::test_markdown_html;\n\n")
|
|
.unwrap();
|
|
|
|
for file_path in &spec_files {
|
|
let mod_name = file_path.file_stem().unwrap().to_str().unwrap();
|
|
mod_rs.write(b"mod ").unwrap();
|
|
mod_rs.write(mod_name.as_bytes()).unwrap();
|
|
mod_rs.write(b";\n").unwrap();
|
|
}
|
|
}
|
|
|
|
#[cfg(feature = "gen-tests")]
|
|
pub struct Spec<'a> {
|
|
spec: &'a str,
|
|
}
|
|
|
|
#[cfg(feature = "gen-tests")]
|
|
impl<'a> Spec<'a> {
|
|
pub fn new(spec: &'a str) -> Self {
|
|
Spec { spec: spec }
|
|
}
|
|
}
|
|
|
|
#[cfg(feature = "gen-tests")]
|
|
pub struct TestCase {
|
|
pub original: String,
|
|
pub expected: String,
|
|
}
|
|
|
|
#[cfg(feature = "gen-tests")]
|
|
impl<'a> Iterator for Spec<'a> {
|
|
type Item = TestCase;
|
|
|
|
fn next(&mut self) -> Option<TestCase> {
|
|
let spec = self.spec;
|
|
|
|
let i_start = match self
|
|
.spec
|
|
.find("```````````````````````````````` example\n")
|
|
.map(|pos| pos + 41)
|
|
{
|
|
Some(pos) => pos,
|
|
None => return None,
|
|
};
|
|
|
|
let i_end = match self.spec[i_start..]
|
|
.find("\n.\n")
|
|
.map(|pos| (pos + 1) + i_start)
|
|
{
|
|
Some(pos) => pos,
|
|
None => return None,
|
|
};
|
|
|
|
let e_end = match self.spec[i_end + 2..]
|
|
.find("````````````````````````````````\n")
|
|
.map(|pos| pos + i_end + 2)
|
|
{
|
|
Some(pos) => pos,
|
|
None => return None,
|
|
};
|
|
|
|
self.spec = &self.spec[e_end + 33..];
|
|
|
|
let test_case = TestCase {
|
|
original: spec[i_start..i_end].to_string().replace("→", "\t"),
|
|
expected: spec[i_end + 2..e_end].to_string().replace("→", "\t"),
|
|
};
|
|
|
|
Some(test_case)
|
|
}
|
|
}
|