Skip to content

Commit a6f27ee

Browse files
authored
Move wast tests to their own test suite (bytecodealliance#8598)
* Move wast tests to their own test suite This commit moves testing of `*.wast` files out of the `all` test suite binary and into its own separate binary. The motivation for this is well-described in bytecodealliance#4861 with one of the chief reasons being that if the test suite is run and then a new file is added re-running the test suite won't see the file. The `libtest-mimic` crate provides an easy way of regaining most of the features of the `libtest` harness such as parallel test execution and filters, meaning that it's pretty easy to switch everything over. The only slightly-tricky bit was redoing the filter for whether a test is ignored or not, but most of the pieces were copied over from the previous `build.rs` logic. Closes bytecodealliance#4861 * Fix the `all` suite * Review comments
1 parent d74b34f commit a6f27ee

File tree

4 files changed

+184
-321
lines changed

4 files changed

+184
-321
lines changed

Cargo.toml

+4
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,10 @@ harness = false
411411
name = "disas"
412412
harness = false
413413

414+
[[test]]
415+
name = "wast"
416+
harness = false
417+
414418
[[example]]
415419
name = "tokio"
416420
required-features = ["wasi-common/tokio"]

build.rs

+2-313
Original file line numberDiff line numberDiff line change
@@ -1,322 +1,11 @@
1-
//! Build program to generate a program which runs all the testsuites.
2-
//!
3-
//! By generating a separate `#[test]` test for each file, we allow cargo test
4-
//! to automatically run the files in parallel.
5-
6-
use anyhow::Context;
71
use std::env;
8-
use std::fmt::Write;
9-
use std::fs;
10-
use std::path::{Path, PathBuf};
2+
use std::path::Path;
113
use std::process::Command;
124

13-
fn main() -> anyhow::Result<()> {
5+
fn main() {
146
println!("cargo:rerun-if-changed=build.rs");
157

168
set_commit_info_for_rustc();
17-
18-
let out_dir = PathBuf::from(
19-
env::var_os("OUT_DIR").expect("The OUT_DIR environment variable must be set"),
20-
);
21-
let mut out = String::new();
22-
23-
for strategy in &["Cranelift", "Winch"] {
24-
writeln!(out, "#[cfg(test)]")?;
25-
writeln!(out, "#[allow(non_snake_case)]")?;
26-
if *strategy == "Winch" {
27-
// We only test Winch on x86_64, for now.
28-
writeln!(out, "{}", "#[cfg(all(target_arch = \"x86_64\"))]")?;
29-
}
30-
writeln!(out, "mod {} {{", strategy)?;
31-
32-
with_test_module(&mut out, "misc", |out| {
33-
test_directory(out, "tests/misc_testsuite", strategy)?;
34-
test_directory_module(out, "tests/misc_testsuite/multi-memory", strategy)?;
35-
test_directory_module(out, "tests/misc_testsuite/simd", strategy)?;
36-
test_directory_module(out, "tests/misc_testsuite/tail-call", strategy)?;
37-
test_directory_module(out, "tests/misc_testsuite/threads", strategy)?;
38-
test_directory_module(out, "tests/misc_testsuite/memory64", strategy)?;
39-
test_directory_module(out, "tests/misc_testsuite/component-model", strategy)?;
40-
test_directory_module(out, "tests/misc_testsuite/function-references", strategy)?;
41-
test_directory_module(out, "tests/misc_testsuite/gc", strategy)?;
42-
// The testsuite of Winch is a subset of the official
43-
// WebAssembly test suite, until parity is reached. This
44-
// check is in place to prevent Cranelift from duplicating
45-
// tests.
46-
if *strategy == "Winch" {
47-
test_directory_module(out, "tests/misc_testsuite/winch", strategy)?;
48-
}
49-
Ok(())
50-
})?;
51-
52-
with_test_module(&mut out, "spec", |out| {
53-
let spec_tests = test_directory(out, "tests/spec_testsuite", strategy)?;
54-
// Skip running spec_testsuite tests if the submodule isn't checked
55-
// out.
56-
if spec_tests > 0 {
57-
test_directory_module(out, "tests/spec_testsuite/proposals/memory64", strategy)?;
58-
test_directory_module(
59-
out,
60-
"tests/spec_testsuite/proposals/function-references",
61-
strategy,
62-
)?;
63-
test_directory_module(out, "tests/spec_testsuite/proposals/gc", strategy)?;
64-
test_directory_module(
65-
out,
66-
"tests/spec_testsuite/proposals/multi-memory",
67-
strategy,
68-
)?;
69-
test_directory_module(out, "tests/spec_testsuite/proposals/threads", strategy)?;
70-
test_directory_module(
71-
out,
72-
"tests/spec_testsuite/proposals/relaxed-simd",
73-
strategy,
74-
)?;
75-
test_directory_module(out, "tests/spec_testsuite/proposals/tail-call", strategy)?;
76-
} else {
77-
println!(
78-
"cargo:warning=The spec testsuite is disabled. To enable, run `git submodule \
79-
update --remote`."
80-
);
81-
}
82-
Ok(())
83-
})?;
84-
85-
writeln!(out, "}}")?;
86-
}
87-
88-
// Write out our auto-generated tests and opportunistically format them with
89-
// `rustfmt` if it's installed.
90-
let output = out_dir.join("wast_testsuite_tests.rs");
91-
fs::write(&output, out)?;
92-
drop(Command::new("rustfmt").arg(&output).status());
93-
Ok(())
94-
}
95-
96-
fn test_directory_module(
97-
out: &mut String,
98-
path: impl AsRef<Path>,
99-
strategy: &str,
100-
) -> anyhow::Result<usize> {
101-
let path = path.as_ref();
102-
let testsuite = &extract_name(path);
103-
with_test_module(out, testsuite, |out| test_directory(out, path, strategy))
104-
}
105-
106-
fn test_directory(
107-
out: &mut String,
108-
path: impl AsRef<Path>,
109-
strategy: &str,
110-
) -> anyhow::Result<usize> {
111-
let path = path.as_ref();
112-
let mut dir_entries: Vec<_> = path
113-
.read_dir()
114-
.context(format!("failed to read {:?}", path))?
115-
.map(|r| r.expect("reading testsuite directory entry"))
116-
.filter_map(|dir_entry| {
117-
let p = dir_entry.path();
118-
let ext = p.extension()?;
119-
// Only look at wast files.
120-
if ext != "wast" {
121-
return None;
122-
}
123-
// Ignore files starting with `.`, which could be editor temporary files
124-
if p.file_stem()?.to_str()?.starts_with('.') {
125-
return None;
126-
}
127-
Some(p)
128-
})
129-
.collect();
130-
131-
dir_entries.sort();
132-
133-
let testsuite = &extract_name(path);
134-
for entry in dir_entries.iter() {
135-
write_testsuite_tests(out, entry, testsuite, strategy, false)?;
136-
write_testsuite_tests(out, entry, testsuite, strategy, true)?;
137-
}
138-
139-
Ok(dir_entries.len())
140-
}
141-
142-
/// Extract a valid Rust identifier from the stem of a path.
143-
fn extract_name(path: impl AsRef<Path>) -> String {
144-
path.as_ref()
145-
.file_stem()
146-
.expect("filename should have a stem")
147-
.to_str()
148-
.expect("filename should be representable as a string")
149-
.replace(['-', '/'], "_")
150-
}
151-
152-
fn with_test_module<T>(
153-
out: &mut String,
154-
testsuite: &str,
155-
f: impl FnOnce(&mut String) -> anyhow::Result<T>,
156-
) -> anyhow::Result<T> {
157-
out.push_str("mod ");
158-
out.push_str(testsuite);
159-
out.push_str(" {\n");
160-
161-
let result = f(out)?;
162-
163-
out.push_str("}\n");
164-
Ok(result)
165-
}
166-
167-
fn write_testsuite_tests(
168-
out: &mut String,
169-
path: impl AsRef<Path>,
170-
testsuite: &str,
171-
strategy: &str,
172-
pooling: bool,
173-
) -> anyhow::Result<()> {
174-
let path = path.as_ref();
175-
let testname = extract_name(path);
176-
177-
writeln!(out, "#[test]")?;
178-
// Ignore when using QEMU for running tests (limited memory).
179-
if ignore(testsuite, &testname, strategy) {
180-
writeln!(out, "#[ignore]")?;
181-
} else {
182-
writeln!(out, "#[cfg_attr(miri, ignore)]")?;
183-
}
184-
185-
writeln!(
186-
out,
187-
"fn r#{}{}() {{",
188-
&testname,
189-
if pooling { "_pooling" } else { "" }
190-
)?;
191-
writeln!(out, " let _ = env_logger::try_init();")?;
192-
writeln!(
193-
out,
194-
" crate::wast::run_wast(r#\"{}\"#, crate::wast::Strategy::{}, {}).unwrap();",
195-
path.display(),
196-
strategy,
197-
pooling,
198-
)?;
199-
writeln!(out, "}}")?;
200-
writeln!(out)?;
201-
Ok(())
202-
}
203-
204-
/// Ignore tests that aren't supported yet.
205-
fn ignore(testsuite: &str, testname: &str, strategy: &str) -> bool {
206-
assert!(strategy == "Cranelift" || strategy == "Winch");
207-
208-
// Ignore some tests for when testing Winch.
209-
if strategy == "Winch" {
210-
if testsuite == "misc_testsuite" {
211-
let denylist = [
212-
"externref_id_function",
213-
"int_to_float_splat",
214-
"issue6562",
215-
"many_table_gets_lead_to_gc",
216-
"mutable_externref_globals",
217-
"no_mixup_stack_maps",
218-
"no_panic",
219-
"simple_ref_is_null",
220-
"table_grow_with_funcref",
221-
];
222-
return denylist.contains(&testname);
223-
}
224-
if testsuite == "spec_testsuite" {
225-
let denylist = [
226-
"br_table",
227-
"global",
228-
"table_fill",
229-
"table_get",
230-
"table_set",
231-
"table_grow",
232-
"table_size",
233-
"elem",
234-
"select",
235-
"unreached_invalid",
236-
"linking",
237-
]
238-
.contains(&testname);
239-
240-
let ref_types = testname.starts_with("ref_");
241-
let simd = testname.starts_with("simd_");
242-
243-
return denylist || ref_types || simd;
244-
}
245-
246-
if testsuite == "memory64" {
247-
return testname.starts_with("simd") || testname.starts_with("threads");
248-
}
249-
250-
if testsuite != "winch" {
251-
return true;
252-
}
253-
}
254-
255-
// This is an empty file right now which the `wast` crate doesn't parse
256-
if testname.contains("memory_copy1") {
257-
return true;
258-
}
259-
260-
if testsuite == "gc" {
261-
if [
262-
"array_copy",
263-
"array_fill",
264-
"array_init_data",
265-
"array_init_elem",
266-
"array",
267-
"binary_gc",
268-
"binary",
269-
"br_on_cast_fail",
270-
"br_on_cast",
271-
"br_on_non_null",
272-
"br_on_null",
273-
"br_table",
274-
"call_ref",
275-
"data",
276-
"elem",
277-
"extern",
278-
"func",
279-
"global",
280-
"if",
281-
"linking",
282-
"local_get",
283-
"local_init",
284-
"ref_as_non_null",
285-
"ref_cast",
286-
"ref_eq",
287-
"ref_is_null",
288-
"ref_null",
289-
"ref_test",
290-
"ref",
291-
"return_call_indirect",
292-
"return_call_ref",
293-
"return_call",
294-
"select",
295-
"struct",
296-
"table_sub",
297-
"table",
298-
"type_canon",
299-
"type_equivalence",
300-
"type_rec",
301-
"type_subtyping",
302-
"unreached_invalid",
303-
"unreached_valid",
304-
]
305-
.contains(&testname)
306-
{
307-
return true;
308-
}
309-
}
310-
311-
match env::var("CARGO_CFG_TARGET_ARCH").unwrap().as_str() {
312-
"s390x" => {
313-
// TODO(#6530): These tests require tail calls, but s390x
314-
// doesn't support them yet.
315-
testsuite == "function_references" || testsuite == "tail_call"
316-
}
317-
318-
_ => false,
319-
}
3209
}
32110

32211
fn set_commit_info_for_rustc() {

tests/all/main.rs

-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ mod traps;
4141
mod types;
4242
mod wait_notify;
4343
mod wasi_testsuite;
44-
mod wast;
4544
// Currently Winch is only supported in x86_64.
4645
#[cfg(all(target_arch = "x86_64"))]
4746
mod winch;

0 commit comments

Comments
 (0)