|
| 1 | +//! Helper program to generate files in `tests/cli/spec/*` which correspond to |
| 2 | +//! running spec tests in `tests/testsuite/*`. |
| 3 | +
|
| 4 | +use std::fs; |
| 5 | +use std::path::Path; |
| 6 | + |
| 7 | +fn main() { |
| 8 | + let _ = fs::remove_dir_all("./tests/cli/spec"); |
| 9 | + copy_tests("tests/testsuite".as_ref(), "tests/cli/spec".as_ref()); |
| 10 | +} |
| 11 | + |
| 12 | +/// Recursively visit `src` and, for all test files, create a file in `dst` to |
| 13 | +/// run the test. |
| 14 | +fn copy_tests(src: &Path, dst: &Path) { |
| 15 | + fs::create_dir(&dst).unwrap(); |
| 16 | + for entry in src.read_dir().unwrap() { |
| 17 | + let entry = entry.unwrap(); |
| 18 | + |
| 19 | + let src = entry.path(); |
| 20 | + let dst = dst.join(entry.file_name()); |
| 21 | + if entry.file_type().unwrap().is_dir() { |
| 22 | + copy_tests(&src, &dst); |
| 23 | + continue; |
| 24 | + } |
| 25 | + |
| 26 | + if src.extension().and_then(|s| s.to_str()) != Some("wast") { |
| 27 | + continue; |
| 28 | + } |
| 29 | + |
| 30 | + copy_test(&src, &dst); |
| 31 | + } |
| 32 | +} |
| 33 | + |
| 34 | +/// Creates `dst` as a file to run `src` as a test. |
| 35 | +fn copy_test(src: &Path, dst: &Path) { |
| 36 | + // The legacy exception-handling proposal is not currently supported because |
| 37 | + // it uses the folded form of s-expressions which are not implemented here. |
| 38 | + // Regardless just skip these spec tests. |
| 39 | + if src.iter().any(|p| p == "legacy") { |
| 40 | + return; |
| 41 | + } |
| 42 | + |
| 43 | + let mut contents = format!(";; RUN: wast \\\n"); |
| 44 | + contents.push_str(";; --assert default \\\n"); |
| 45 | + contents.push_str(";; --snapshot tests/snapshots \\\n"); |
| 46 | + |
| 47 | + // This test specifically tests various forms of unicode which are |
| 48 | + // default-disallowed, so explicitly allow it here. |
| 49 | + if src.ends_with("names.wast") { |
| 50 | + contents.push_str(";; --allow-confusing-unicode \\\n"); |
| 51 | + } |
| 52 | + |
| 53 | + // Historically wasm-tools tried to match the upstream error message. This |
| 54 | + // generally led to a large sequence of matches here which is not easy to |
| 55 | + // maintain and is particularly difficult when test suites and proposals |
| 56 | + // conflict with each other (e.g. one asserts one error message and another |
| 57 | + // asserts a different error message). Overall we didn't benefit a whole lot |
| 58 | + // from trying to match errors so just assume the error is roughly the same |
| 59 | + // and otherwise don't try to match it. |
| 60 | + contents.push_str(";; --ignore-error-messages \\\n"); |
| 61 | + |
| 62 | + // Push a `--features=..` flag for the spec tests. Spec tests often need a |
| 63 | + // precise set of features different from the defaults of `wasm-tools` so |
| 64 | + // it's always overridden here. |
| 65 | + let features = match find_proposal(src) { |
| 66 | + None => "wasm2", |
| 67 | + Some("annotations") => "wasm2", |
| 68 | + Some("threads") => "wasm1,threads", |
| 69 | + Some("function-references") => "wasm2,function-references,tail-call", |
| 70 | + Some("wasm-3.0") => "wasm3", |
| 71 | + Some("gc") => "wasm2,function-references,gc,tail-call", |
| 72 | + Some("multi-memory") => "wasm2,multi-memory", |
| 73 | + Some("extended-const") => "wasm2,extended-const", |
| 74 | + Some("exception-handling") => "wasm2,exceptions,tail-call", |
| 75 | + Some("custom-page-sizes") => "wasm3,custom-page-sizes", |
| 76 | + Some("wide-arithmetic") => "wasm2,wide-arithmetic", |
| 77 | + Some("tail-call") => "wasm2,tail-call", |
| 78 | + Some("relaxed-simd") => "wasm2,relaxed-simd", |
| 79 | + Some("memory64") => "wasm3", |
| 80 | + Some(proposal) => panic!("unsupported proposal: {}", proposal), |
| 81 | + }; |
| 82 | + contents.push_str(&format!(";; --features={features} \\\n")); |
| 83 | + |
| 84 | + // And finally push a path to the test itself. |
| 85 | + contents.push_str(&format!(";; {}\n", src.display())); |
| 86 | + |
| 87 | + fs::write(dst, contents).unwrap(); |
| 88 | +} |
| 89 | + |
| 90 | +/// Finds the wasm proposal, if present, within `src`. |
| 91 | +fn find_proposal(src: &Path) -> Option<&str> { |
| 92 | + // Look for `foo` in `.../proposals/foo/...` |
| 93 | + let mut parts = src.iter(); |
| 94 | + while let Some(next) = parts.next() { |
| 95 | + if next.to_str() == Some("proposals") { |
| 96 | + return parts.next()?.to_str(); |
| 97 | + } |
| 98 | + } |
| 99 | + None |
| 100 | +} |
0 commit comments