1mod processors;
9
10pub use crate::processors::wast_processor;
11use anyhow::Context;
12use std::fmt::Write;
13use std::path::{Path, PathBuf};
14
15pub struct Testsuite {
16 pub buffer: String,
17 pub path: Vec<String>,
18}
19
20#[derive(PartialEq, Eq, PartialOrd, Ord)]
21pub struct Test {
22 pub name: String,
23 pub body: String,
24}
25
26pub fn test_directory_module(
27 out: &mut Testsuite,
28 path: impl AsRef<Path>,
29 processor: impl Fn(&mut Testsuite, PathBuf) -> Option<Test>,
30) -> anyhow::Result<()> {
31 let path = path.as_ref();
32 let testsuite = &extract_name(path);
33 with_test_module(out, testsuite, |out| test_directory(out, path, processor))
34}
35
36fn write_test(out: &mut Testsuite, testname: &str, body: &str) -> anyhow::Result<()> {
37 writeln!(
38 out.buffer,
39 "#[compiler_test({})]",
40 out.path[..out.path.len() - 1].join("::")
41 )?;
42 writeln!(
43 out.buffer,
44 "fn r#{testname}(config: crate::Config) -> anyhow::Result<()> {{",
45 )?;
46 writeln!(out.buffer, "{body}")?;
47 writeln!(out.buffer, "}}")?;
48 writeln!(out.buffer)?;
49 Ok(())
50}
51
52pub fn test_directory(
53 out: &mut Testsuite,
54 path: impl AsRef<Path>,
55 processor: impl Fn(&mut Testsuite, PathBuf) -> Option<Test>,
56) -> anyhow::Result<()> {
57 let path = path.as_ref();
58 let mut dir_entries: Vec<_> = path
59 .read_dir()
60 .context(format!("failed to read {path:?}"))?
61 .map(|r| r.expect("reading testsuite directory entry"))
62 .filter_map(|dir_entry| processor(out, dir_entry.path()))
63 .collect();
64
65 dir_entries.sort();
66
67 for Test {
68 name: testname,
69 body,
70 } in dir_entries.iter()
71 {
72 out.path.push(testname.to_string());
73 write_test(out, testname, body).unwrap();
74 out.path.pop().unwrap();
75 }
76
77 Ok(())
78}
79
80pub fn extract_name(path: impl AsRef<Path>) -> String {
82 path.as_ref()
83 .file_stem()
84 .expect("filename should have a stem")
85 .to_str()
86 .expect("filename should be representable as a string")
87 .replace(['-', '/'], "_")
88}
89
90pub fn with_test_module(
91 out: &mut Testsuite,
92 testsuite: &str,
93 f: impl FnOnce(&mut Testsuite) -> anyhow::Result<()>,
94) -> anyhow::Result<()> {
95 out.path.push(testsuite.to_string());
96 out.buffer.push_str("mod ");
97 out.buffer.push_str(testsuite);
98 out.buffer.push_str(" {\n");
99
100 f(out)?;
101
102 out.buffer.push_str("}\n");
103 out.path.pop().unwrap();
104 Ok(())
105}