Files
wasmtime/build.rs
Jakub Konka 3793fa3b09 Merge wasi-misc-tests repo as a subdir (#174)
* Initial checkin.

* Update to rust-lang libc.

* Add a .gitignore file.

* Factor out functions for cleaning up files and directories.

* Fix a typo in a comment.

* Print a "Success!" message if all tests passed.

* Factor out code for creating directories.

* Add wrappers around WASI functions.

These wrappers handle converting from &str to pointer+length and handle
unsafe.

* More refactoring.

* Refactor a fd_close helper.

* Move utility functions into a separate file.

* cargo update

* Add a basic test for random_get.

* Test that directories aren't resizable.

* Test clearing __WASI_RIGHT_PATH_FILESTAT_SET_SIZE.

Ensure that clearing __WASI_RIGHT_PATH_FILESTAT_SET_SIZE succeeds before
testing file truncation.

* cargo update

* Modularise tests for easier use with wasi-common crate

* Add a Code of Conduct and CONTRIBUTING.md.

* Fix typo

* Add testcase for fd_allocate

* Add positive test for fd_renumber

* Assert bufused in readlink_no_buffer testcase

* Add positive readlink testcase

* Add testcase for fd_seek and fd_tell

* Add fd_p{read, write} test

* Add README

* Add cases with trailing slashes to interesting_paths

* Split nofollow_errors testcase into two

* nofollow_errors now operators on symlinks to existing resources
* dangling_symlink covers danling symlinks tests

* Factor out a `create_file` helper function.

* Switch from the error crate to `std::io::Error::last_os_error()`.

* Use `create_file` in the readlink test too.

* Add a test for fd_filestat_set_*

* Minor refactoring

Add missing cleanup_file calls to file_pread_pwrite and
file_seek_tell.

* Add testcase for unbuffered fd_write; fixes #11

* Add testcase for path_rename

* Use the wasi crate.

Switch from depending on libc to depending on the new wasi crate to provide
the low-level WASI interfaces.

See also https://github.com/rust-lang/libc/pull/1461.

* Add a test for path_filestat_*

* Add a test for fd_readdir

* Use expect instead of unwrap

* Add a check for ino.

* Fix the build

* Don't assume a specific order of dirents

* Better test

* Test cookie value

* Fix file types

* Fix the test

* Fix the test

* Fix the test

* Cleanup

* Minor formatting tidying in README.md.

* Fix miscellaneous clippy warnings.

* Rename the crate to wasi-misc-tests.

* Update to wasi 0.7.0.

This switches from using the libc wasi bindings to using the wasi
crate's bindings. This eliminates a git dependency on libc, updates
to the new-style bindings which use Result where possible, and treats
functions that operate on raw file descriptors as unsafe.

* Add various tests for trailing-slash behavior.

* Sync new testcases with latest upstream

* Fix path_filestat testcase

* Add smoke test for fd_advise

This test is a true smoke test as it only tests whether issuing
an advise call to the host's kernel doesn't yield an error. The
consequence of issuing such a syscall is not tested.

* Check if CLOCK_MONOTONIC is actually monotonic

* Refactor the inequality assertions for more debuggable errors.

* Bump libc from 0.2.62 to 0.2.65

Bumps [libc](https://github.com/rust-lang/libc) from 0.2.62 to 0.2.65.
- [Release notes](https://github.com/rust-lang/libc/releases)
- [Commits](https://github.com/rust-lang/libc/compare/0.2.62...0.2.65)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

* Fix compilation error

* Enable Actions and add rust.yml (#35)

* Enable Actions and add rust.yml

This commit enables Github Actions and adds corresponding configuration in rust.yml file.

* Update rust.yml

* Fix formatting

* Add empty .rustfmt.toml config file

* Add badge to README

* Update README

* Clean up Github Actions and README

* Add test case for `poll_oneoff` syscall (#38)

* Add test case for `poll_oneoff` syscall

This commit adds a test case for `poll_oneoff` syscall. In particular,
it builds on the excellent test use case provided by @dunnock in their
repo [poll_oneoff_tests] (thanks!), and tests:
* simple timeout
* stdin read with timeout
* fd read and fd write polls

[poll_oneoff_tests]: https://github.com/dunnock/poll_oneoff_tests

* Apply suggestions and negative test for bad fd

Co-authored-by: Maxim Vorobjov <maxim.vorobjov@gmail.com>

* Add smoke test for STDOUT/ERR readwrite poll

* Add comment on stdin/out/err

* Add a test for `*at`-style functions returning `ENOTDIR` when `dirfd` is not a dir.

* Remove misc_testsuite submodule

* Add "publish=false" to Cargo.toml; remove LICENSE
2019-11-07 13:58:57 +01:00

272 lines
9.9 KiB
Rust

//! Build program to generate a program which runs all the testsuites.
//!
//! By generating a separate `#[test]` test for each file, we allow cargo test
//! to automatically run the files in parallel.
use std::env;
use std::fs::{read_dir, File};
use std::io::{self, Write};
use std::path::{Path, PathBuf};
fn main() {
let out_dir =
PathBuf::from(env::var("OUT_DIR").expect("The OUT_DIR environment variable must be set"));
let mut out = File::create(out_dir.join("wast_testsuite_tests.rs"))
.expect("error generating test source file");
for strategy in &[
"Cranelift",
#[cfg(feature = "lightbeam")]
"Lightbeam",
] {
writeln!(out, "#[cfg(test)]").expect("generating tests");
writeln!(out, "#[allow(non_snake_case)]").expect("generating tests");
writeln!(out, "mod {} {{", strategy).expect("generating tests");
test_directory(&mut out, "misc_testsuite", strategy).expect("generating tests");
test_directory(&mut out, "spec_testsuite", strategy).expect("generating tests");
// Skip running spec_testsuite tests if the submodule isn't checked out.
if read_dir("spec_testsuite")
.expect("reading testsuite directory")
.next()
.is_some()
{
test_file(
&mut out,
&to_os_path(&["spec_testsuite", "proposals", "simd", "simd_address.wast"]),
strategy,
)
.expect("generating tests");
test_file(
&mut out,
&to_os_path(&["spec_testsuite", "proposals", "simd", "simd_align.wast"]),
strategy,
)
.expect("generating tests");
test_file(
&mut out,
&to_os_path(&["spec_testsuite", "proposals", "simd", "simd_const.wast"]),
strategy,
)
.expect("generating tests");
let multi_value_suite = &to_os_path(&["spec_testsuite", "proposals", "multi-value"]);
test_directory(&mut out, &multi_value_suite, strategy).expect("generating tests");
} else {
println!("cargo:warning=The spec testsuite is disabled. To enable, run `git submodule update --remote`.");
}
writeln!(out, "}}").expect("generating tests");
}
}
/// Helper for creating OS-independent paths.
fn to_os_path(components: &[&str]) -> String {
let path: PathBuf = components.iter().collect();
path.display().to_string()
}
fn test_directory(out: &mut File, path: &str, strategy: &str) -> io::Result<()> {
let mut dir_entries: Vec<_> = read_dir(path)
.expect("reading testsuite directory")
.map(|r| r.expect("reading testsuite directory entry"))
.filter(|dir_entry| {
let p = dir_entry.path();
if let Some(ext) = p.extension() {
// Only look at wast files.
if ext == "wast" {
// Ignore files starting with `.`, which could be editor temporary files
if let Some(stem) = p.file_stem() {
if let Some(stemstr) = stem.to_str() {
if !stemstr.starts_with('.') {
return true;
}
}
}
}
}
false
})
.collect();
dir_entries.sort_by_key(|dir| dir.path());
let testsuite = &extract_name(path);
start_test_module(out, testsuite)?;
for dir_entry in dir_entries {
write_testsuite_tests(out, &dir_entry.path(), testsuite, strategy)?;
}
finish_test_module(out)
}
fn test_file(out: &mut File, testfile: &str, strategy: &str) -> io::Result<()> {
let path = Path::new(testfile);
let testsuite = format!("single_test_{}", extract_name(path));
start_test_module(out, &testsuite)?;
write_testsuite_tests(out, path, &testsuite, strategy)?;
finish_test_module(out)
}
/// Extract a valid Rust identifier from the stem of a path.
fn extract_name(path: impl AsRef<Path>) -> String {
path.as_ref()
.file_stem()
.expect("filename should have a stem")
.to_str()
.expect("filename should be representable as a string")
.replace("-", "_")
.replace("/", "_")
}
fn start_test_module(out: &mut File, testsuite: &str) -> io::Result<()> {
writeln!(out, " mod {} {{", testsuite)?;
writeln!(
out,
" use super::super::{{native_isa, Path, WastContext, Compiler, Features, CompilationStrategy}};"
)
}
fn finish_test_module(out: &mut File) -> io::Result<()> {
writeln!(out, " }}")
}
fn write_testsuite_tests(
out: &mut File,
path: &Path,
testsuite: &str,
strategy: &str,
) -> io::Result<()> {
let testname = extract_name(path);
writeln!(out, " #[test]")?;
if ignore(testsuite, &testname, strategy) {
writeln!(out, " #[ignore]")?;
}
writeln!(out, " fn r#{}() {{", &testname)?;
writeln!(out, " let isa = native_isa();")?;
writeln!(
out,
" let compiler = Compiler::new(isa, CompilationStrategy::{});",
strategy
)?;
writeln!(
out,
" let features = Features {{ simd: {}, multi_value: {}, ..Default::default() }};",
testsuite.contains("simd"),
testsuite.contains("multi_value")
)?;
writeln!(
out,
" let mut wast_context = WastContext::new(Box::new(compiler)).with_features(features);"
)?;
writeln!(out, " wast_context")?;
writeln!(out, " .register_spectest()")?;
writeln!(
out,
" .expect(\"instantiating \\\"spectest\\\"\");"
)?;
writeln!(out, " wast_context")?;
write!(out, " .run_file(Path::new(\"")?;
// Write out the string with escape_debug to prevent special characters such
// as backslash from being reinterpreted.
for c in path.display().to_string().chars() {
write!(out, "{}", c.escape_debug())?;
}
writeln!(out, "\"))")?;
writeln!(out, " .expect(\"error running wast file\");",)?;
writeln!(out, " }}")?;
writeln!(out)?;
Ok(())
}
/// Ignore tests that aren't supported yet.
fn ignore(testsuite: &str, testname: &str, strategy: &str) -> bool {
let is_multi_value = testsuite.ends_with("multi_value");
match strategy {
#[cfg(feature = "lightbeam")]
"Lightbeam" => match (testsuite, testname) {
(_, _) if testname.starts_with("simd") => return true,
(_, _) if is_multi_value => return true,
_ => (),
},
"Cranelift" => match (testsuite, testname) {
// We don't currently support more return values than available
// registers, and this contains a function with many, many more
// return values than that.
(_, "func") if is_multi_value => return true,
_ => {}
},
_ => panic!("unrecognized strategy"),
}
if cfg!(windows) {
return match (testsuite, testname) {
// Currently, our multi-value support only works with however many
// extra return registers we have available, and windows' fastcall
// ABI only has a single return register, so we need to wait on full
// multi-value support in Cranelift.
(_, _) if is_multi_value => true,
// Until Windows unwind information is added we must disable SIMD spec tests that trap.
(_, _) if testname.starts_with("simd") => return true,
("spec_testsuite", "address") => true,
("spec_testsuite", "align") => true,
("spec_testsuite", "call") => true,
("spec_testsuite", "call_indirect") => true,
("spec_testsuite", "conversions") => true,
("spec_testsuite", "elem") => true,
("spec_testsuite", "fac") => true,
("spec_testsuite", "func_ptrs") => true,
("spec_testsuite", "globals") => true,
("spec_testsuite", "i32") => true,
("spec_testsuite", "i64") => true,
("spec_testsuite", "f32") => true,
("spec_testsuite", "f64") => true,
("spec_testsuite", "if") => true,
("spec_testsuite", "imports") => true,
("spec_testsuite", "int_exprs") => true,
("spec_testsuite", "linking") => true,
("spec_testsuite", "memory_grow") => true,
("spec_testsuite", "memory_trap") => true,
("spec_testsuite", "resizing") => true,
("spec_testsuite", "select") => true,
("spec_testsuite", "skip_stack_guard_page") => true,
("spec_testsuite", "start") => true,
("spec_testsuite", "traps") => true,
("spec_testsuite", "unreachable") => true,
("spec_testsuite", "unwind") => true,
("misc_testsuite", "misc_traps") => true,
("misc_testsuite", "stack_overflow") => true,
(_, _) => false,
};
}
#[cfg(target_os = "linux")]
{
// Test whether the libc correctly parses the following constant; if so,
// we can run the "const" test. If not, the "const" test will fail, since
// we use wabt to parse the tests and wabt uses strtof.
extern "C" {
pub fn strtof(s: *const libc::c_char, endp: *mut *mut libc::c_char) -> libc::c_float;
}
if unsafe {
strtof(
b"8.8817847263968443574e-16" as *const u8 as *const libc::c_char,
core::ptr::null_mut(),
)
}
.to_bits()
!= 0x26800001
{
return match (testsuite, testname) {
("spec_testsuite", "const") => true,
("single_file_spec_test", "simd_const") => true,
(_, _) => false,
};
}
}
false
}