1mod processors;
9
10pub use crate::processors::{wasi_processor, 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<usize> {
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#{}(config: crate::Config) -> anyhow::Result<()> {{",
45 &testname
46 )?;
47 writeln!(out.buffer, "{body}")?;
48 writeln!(out.buffer, "}}")?;
49 writeln!(out.buffer)?;
50 Ok(())
51}
52
53pub fn test_directory(
54 out: &mut Testsuite,
55 path: impl AsRef<Path>,
56 processor: impl Fn(&mut Testsuite, PathBuf) -> Option<Test>,
57) -> anyhow::Result<usize> {
58 let path = path.as_ref();
59 let mut dir_entries: Vec<_> = path
60 .read_dir()
61 .context(format!("failed to read {path:?}"))?
62 .map(|r| r.expect("reading testsuite directory entry"))
63 .filter_map(|dir_entry| processor(out, dir_entry.path()))
64 .collect();
65
66 dir_entries.sort();
67
68 for Test {
69 name: testname,
70 body,
71 } in dir_entries.iter()
72 {
73 out.path.push(testname.to_string());
74 write_test(out, testname, body).unwrap();
75 out.path.pop().unwrap();
76 }
77
78 Ok(dir_entries.len())
79}
80
81pub fn extract_name(path: impl AsRef<Path>) -> String {
83 path.as_ref()
84 .file_stem()
85 .expect("filename should have a stem")
86 .to_str()
87 .expect("filename should be representable as a string")
88 .replace(['-', '/'], "_")
89}
90
91pub fn with_test_module<T>(
92 out: &mut Testsuite,
93 testsuite: &str,
94 f: impl FnOnce(&mut Testsuite) -> anyhow::Result<T>,
95) -> anyhow::Result<T> {
96 out.path.push(testsuite.to_string());
97 out.buffer.push_str("mod ");
98 out.buffer.push_str(testsuite);
99 out.buffer.push_str(" {\n");
100
101 let result = f(out)?;
102
103 out.buffer.push_str("}\n");
104 out.path.pop().unwrap();
105 Ok(result)
106}