1 //! A test suite to parse everything in `parse-fail` and assert that it matches
2 //! the `*.err` file it generates.
3 //!
4 //! Use `BLESS=1` in the environment to auto-update `*.err` files. Be sure to
5 //! look at the diff!
6
7 use rayon::prelude::*;
8 use std::env;
9 use std::path::{Path, PathBuf};
10
main()11 fn main() {
12 let mut tests = Vec::new();
13 find_tests("tests/parse-fail".as_ref(), &mut tests);
14 let filter = std::env::args().nth(1);
15
16 let bless = env::var("BLESS").is_ok();
17 let tests = tests
18 .iter()
19 .filter(|test| {
20 if let Some(filter) = &filter {
21 if let Some(s) = test.file_name().and_then(|s| s.to_str()) {
22 if !s.contains(filter) {
23 return false;
24 }
25 }
26 }
27 true
28 })
29 .collect::<Vec<_>>();
30
31 println!("running {} tests\n", tests.len());
32
33 let errors = tests
34 .par_iter()
35 .filter_map(|test| run_test(test, bless).err())
36 .collect::<Vec<_>>();
37
38 if !errors.is_empty() {
39 for msg in errors.iter() {
40 eprintln!("{}", msg);
41 }
42
43 panic!("{} tests failed", errors.len())
44 }
45
46 println!("test result: ok. {} passed\n", tests.len());
47 }
48
run_test(test: &Path, bless: bool) -> anyhow::Result<()>49 fn run_test(test: &Path, bless: bool) -> anyhow::Result<()> {
50 let err = match wat::parse_file(test) {
51 Ok(_) => anyhow::bail!("{} parsed successfully", test.display()),
52 Err(e) => e.to_string() + "\n",
53 };
54 let assert = test.with_extension("wat.err");
55 if bless {
56 std::fs::write(assert, err.to_string())?;
57 return Ok(());
58 }
59
60 // Ignore CRLF line ending and force always `\n`
61 let assert = std::fs::read_to_string(assert)
62 .unwrap_or(String::new())
63 .replace("\r\n", "\n");
64
65 // Compare normalize verisons which handles weirdness like path differences
66 if normalize(&assert) == normalize(&err) {
67 return Ok(());
68 }
69
70 anyhow::bail!(
71 "errors did not match:\n\nexpected:\n\t{}\nactual:\n\t{}\n",
72 tab(&assert),
73 tab(&err),
74 );
75
76 fn normalize(s: &str) -> String {
77 s.replace("\\", "/")
78 }
79
80 fn tab(s: &str) -> String {
81 s.replace("\n", "\n\t")
82 }
83 }
84
85 fn find_tests(path: &Path, tests: &mut Vec<PathBuf>) {
86 for f in path.read_dir().unwrap() {
87 let f = f.unwrap();
88 if f.file_type().unwrap().is_dir() {
89 find_tests(&f.path(), tests);
90 continue;
91 }
92 match f.path().extension().and_then(|s| s.to_str()) {
93 Some("wat") => {}
94 _ => continue,
95 }
96 tests.push(f.path());
97 }
98 }
99