1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
|
//! You can run this test suite with:
//!
//! cargo test --test all
//!
//! An argument can be passed as well to filter, based on filename, which test
//! to run
//!
//! cargo test --test all foo.wit
use anyhow::{bail, Context, Result};
use libtest_mimic::{Arguments, Trial};
use pretty_assertions::StrComparison;
use std::env;
use std::ffi::OsStr;
use std::fs;
use std::io;
use std::path::{Path, PathBuf};
use std::str;
use wit_parser::*;
fn main() {
env_logger::init();
let tests = find_tests();
let mut trials = Vec::new();
for test in tests {
let trial = Trial::test(format!("{test:?}"), move || {
Runner {}
.run(&test)
.context(format!("test {:?} failed", test))
.map_err(|e| format!("{e:?}").into())
});
trials.push(trial);
}
let mut args = Arguments::from_args();
if cfg!(target_family = "wasm") && !cfg!(target_feature = "atomics") {
args.test_threads = Some(1);
}
libtest_mimic::run(&args, trials).exit();
}
/// Recursively finds all tests in a whitelisted set of directories which we
/// then load up and test in parallel.
fn find_tests() -> Vec<PathBuf> {
let mut tests = Vec::new();
find_tests("tests/ui".as_ref(), &mut tests);
find_tests("tests/ui/parse-fail".as_ref(), &mut tests);
tests.sort();
return tests;
fn find_tests(path: &Path, tests: &mut Vec<PathBuf>) {
for f in path.read_dir().unwrap() {
let f = f.unwrap();
let path = f.path();
if path.file_name().unwrap().to_str().unwrap() == "parse-fail" {
continue;
}
if f.file_type().unwrap().is_dir() {
tests.push(path);
continue;
}
match path.extension().and_then(|s| s.to_str()) {
Some("md") | Some("wit") | Some("wat") | Some("wasm") => {}
_ => continue,
}
tests.push(path);
}
}
}
struct Runner {}
impl Runner {
fn run(&mut self, test: &Path) -> Result<()> {
let mut resolve = Resolve::new();
resolve.features.insert("active".to_string());
let result = resolve.push_path(test);
let result = if test.iter().any(|s| s == "parse-fail") {
match result {
Ok(_) => bail!("expected test to not parse but it did"),
Err(mut e) => {
if let Some(err) = e.downcast_mut::<io::Error>() {
*err = io::Error::new(
io::ErrorKind::Other,
"some generic platform-agnostic error message",
);
}
format!("{:#}", e)
}
}
} else {
result?;
// format json string to human readable
let json_result = serde_json::to_string_pretty(&resolve)?;
// "foo.wit" => "foo.wit.json"
self.read_or_write_to_file(test, &json_result, "json")?;
return Ok(());
};
// "foo.wit" => "foo.wit.result"
// "foo.wit.md" => "foo.wit.md.result"
self.read_or_write_to_file(test, &result, "result")?;
return Ok(());
}
fn read_or_write_to_file(
&mut self,
test: &Path,
result: &str,
extension: &str,
) -> Result<(), anyhow::Error> {
let result_file = if test.extension() == Some(OsStr::new("md"))
&& test
.file_stem()
.and_then(|path| Path::new(path).extension())
== Some(OsStr::new("wit"))
{
test.with_extension(format!("md.{extension}"))
} else {
test.with_extension(format!("wit.{extension}"))
};
if env::var_os("BLESS").is_some() {
let normalized = normalize(&result, extension);
fs::write(&result_file, normalized)?;
} else {
let expected = fs::read_to_string(&result_file).context(format!(
"failed to read test expectation file {:?}\nthis can be fixed with BLESS=1",
result_file
))?;
let expected = normalize(&expected, extension);
let result = normalize(&result, extension);
if expected != result {
bail!(
"failed test: result is not as expected:{}",
StrComparison::new(&expected, &result),
);
}
}
Ok(())
}
}
fn normalize(s: &str, extension: &str) -> String {
let s = s.trim();
match extension {
// .result files have error messages with paths, so normalize Windows \ separators to /
"result" => s.replace("\\", "/").replace("\r\n", "\n"),
// .json files escape strings with \, so leave them alone
_ => s.replace("\r\n", "\n"),
}
}
|