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