|
| 1 | +fn main() { |
| 2 | + generate_tests_markdown_tests().unwrap() |
| 3 | +} |
| 4 | + |
| 5 | +#[cfg(not(feature = "gen-tests"))] |
| 6 | +fn generate_tests_markdown_tests() -> std::io::Result<()> { |
| 7 | + Ok(()) |
| 8 | +} |
| 9 | + |
| 10 | +#[cfg(feature = "gen-tests")] |
| 11 | +fn generate_tests_markdown_tests() -> std::io::Result<()> { |
| 12 | + use std::fs::File; |
| 13 | + use std::io::BufWriter; |
| 14 | + use std::path::PathBuf; |
| 15 | + |
| 16 | + let spec_folder = "./tests/spec/"; |
| 17 | + let test_folder = "./tests/"; |
| 18 | + |
| 19 | + let spec_files = [ |
| 20 | + ( |
| 21 | + "", |
| 22 | + "commonmark_v0_30_spec.json", |
| 23 | + "https://spec.commonmark.org/0.30/", |
| 24 | + ), |
| 25 | + ("gfm_", "gfm_spec.json", "https://github.github.com/gfm/"), |
| 26 | + ]; |
| 27 | + |
| 28 | + for (prefix, spec, url) in spec_files { |
| 29 | + let input_file = format!("{spec_folder}{spec}"); |
| 30 | + let mut output_file = PathBuf::from(format!("{test_folder}{spec}")); |
| 31 | + output_file.set_extension("rs"); |
| 32 | + |
| 33 | + let test_cases: Vec<TestCase<'_>> = serde_json::from_reader(File::open(&input_file)?)?; |
| 34 | + let mut output = BufWriter::new(File::create(&output_file)?); |
| 35 | + |
| 36 | + write_test_cases(&mut output, prefix, test_cases, url) |
| 37 | + .expect("generated test case successfully"); |
| 38 | + } |
| 39 | + |
| 40 | + Ok(()) |
| 41 | +} |
| 42 | + |
| 43 | +#[cfg(feature = "gen-tests")] |
| 44 | +#[derive(Debug, serde::Deserialize)] |
| 45 | +struct TestCase<'a> { |
| 46 | + #[serde(rename(deserialize = "markdown"))] |
| 47 | + input: std::borrow::Cow<'a, str>, |
| 48 | + #[serde(rename(deserialize = "formattedMarkdown"))] |
| 49 | + output: Option<std::borrow::Cow<'a, str>>, |
| 50 | + #[serde(rename(deserialize = "example"))] |
| 51 | + id: usize, |
| 52 | + section: std::borrow::Cow<'a, str>, |
| 53 | + #[serde(default)] |
| 54 | + skip: bool, |
| 55 | + #[serde(default = "default_test", rename(deserialize = "testMacro"))] |
| 56 | + test_macro: std::borrow::Cow<'a, str>, |
| 57 | + comment: Option<std::borrow::Cow<'a, str>>, |
| 58 | +} |
| 59 | + |
| 60 | +#[cfg(feature = "gen-tests")] |
| 61 | +fn default_test() -> std::borrow::Cow<'static, str> { |
| 62 | + // Name of the test macro to use |
| 63 | + "test_identical_markdown_events".into() |
| 64 | +} |
| 65 | + |
| 66 | +#[cfg(feature = "gen-tests")] |
| 67 | +fn write_test_cases<W>( |
| 68 | + writer: &mut W, |
| 69 | + prefix: &str, |
| 70 | + test_cases: Vec<TestCase<'_>>, |
| 71 | + url: &str, |
| 72 | +) -> std::io::Result<()> |
| 73 | +where |
| 74 | + W: std::io::Write, |
| 75 | +{ |
| 76 | + write!(writer, "// @generated\n")?; |
| 77 | + write!(writer, "// generated running `cargo build -F gen-tests`\n")?; |
| 78 | + write!( |
| 79 | + writer, |
| 80 | + "// test macros are defined in tests/common/mod.rs\n" |
| 81 | + )?; |
| 82 | + write!(writer, "mod common;\n")?; |
| 83 | + |
| 84 | + for test_case in test_cases.into_iter() { |
| 85 | + write_test_case(writer, prefix, test_case, url)?; |
| 86 | + } |
| 87 | + Ok(()) |
| 88 | +} |
| 89 | + |
| 90 | +#[cfg(feature = "gen-tests")] |
| 91 | +fn write_test_case<W: std::io::Write>( |
| 92 | + writer: &mut W, |
| 93 | + prefix: &str, |
| 94 | + test_case: TestCase<'_>, |
| 95 | + url: &str, |
| 96 | +) -> std::io::Result<()> { |
| 97 | + let url = if url.ends_with("/") { |
| 98 | + format!("{}#example-{}", url, test_case.id) |
| 99 | + } else { |
| 100 | + format!("{}/#example-1{}", url, test_case.id) |
| 101 | + }; |
| 102 | + |
| 103 | + let replace_tab_chars = test_case.input.replace('→', "\t"); |
| 104 | + let input = replace_tab_chars.trim_end_matches('\n'); |
| 105 | + |
| 106 | + if let Some(comment) = test_case.comment { |
| 107 | + write!(writer, "\n// {comment}")?; |
| 108 | + } |
| 109 | + |
| 110 | + if test_case.skip { |
| 111 | + write!(writer, "\n#[ignore]")?; |
| 112 | + } |
| 113 | + |
| 114 | + write!( |
| 115 | + writer, |
| 116 | + r##" |
| 117 | +#[test] |
| 118 | +fn {}markdown_{}_{}() {{ |
| 119 | + // {} |
| 120 | + {}!("##, |
| 121 | + prefix, |
| 122 | + test_case |
| 123 | + .section |
| 124 | + .to_lowercase() |
| 125 | + .replace(char::is_whitespace, "_") |
| 126 | + .replace("(", "") |
| 127 | + .replace(")", ""), |
| 128 | + test_case.id, |
| 129 | + url, |
| 130 | + test_case.test_macro, |
| 131 | + )?; |
| 132 | + |
| 133 | + let has_trailing_whitespace = input.lines().any(|l| l.ends_with(char::is_whitespace)); |
| 134 | + if has_trailing_whitespace { |
| 135 | + write!(writer, "{:?}", input)?; |
| 136 | + } else { |
| 137 | + write!(writer, "r##\"{}\"##", input)?; |
| 138 | + } |
| 139 | + if let Some(expected_output) = test_case.output { |
| 140 | + let has_trailing_whitespace = expected_output |
| 141 | + .lines() |
| 142 | + .any(|l| l.ends_with(char::is_whitespace)); |
| 143 | + if has_trailing_whitespace { |
| 144 | + write!(writer, ",{:?}", expected_output)?; |
| 145 | + } else { |
| 146 | + write!(writer, ",r##\"{}\"##", expected_output)?; |
| 147 | + } |
| 148 | + } |
| 149 | + write!(writer, ");")?; |
| 150 | + write!(writer, "\n}}\n")?; |
| 151 | + Ok(()) |
| 152 | +} |
0 commit comments