diff options
| author | Henry <mail@henrygressmann.de> | 2023-12-23 18:19:12 +0100 |
|---|---|---|
| committer | Henry <mail@henrygressmann.de> | 2023-12-23 18:19:12 +0100 |
| commit | 154d5fe5311ede2be44036900ad7598fe5fc8664 (patch) | |
| tree | e66a7e08e2108f4f85e308f2e60680be4447f9e1 /crates | |
| parent | ac6b812d7555c7a84a3e8d12d64fdb34d8f536f2 (diff) | |
tests: improve test glue code
Signed-off-by: Henry <mail@henrygressmann.de>
Diffstat (limited to 'crates')
| -rw-r--r-- | crates/tinywasm/Cargo.toml | 2 | ||||
| -rw-r--r-- | crates/tinywasm/tests/test-mvp.rs | 2 | ||||
| -rw-r--r-- | crates/tinywasm/tests/test-wast.rs | 21 | ||||
| -rw-r--r-- | crates/tinywasm/tests/testsuite/mod.rs | 2 | ||||
| -rw-r--r-- | crates/tinywasm/tests/testsuite/run.rs | 268 |
5 files changed, 158 insertions, 137 deletions
diff --git a/crates/tinywasm/Cargo.toml b/crates/tinywasm/Cargo.toml index 852c31c..86b65eb 100644 --- a/crates/tinywasm/Cargo.toml +++ b/crates/tinywasm/Cargo.toml @@ -20,7 +20,7 @@ tinywasm-types={version="0.0.6-alpha.0", path="../types", default-features=false [dev-dependencies] wasm-testsuite={path="../wasm-testsuite"} wast={version="69.0"} -owo-colors={version="3.5"} +owo-colors={version="4.0"} eyre={version="0.6"} serde_json={version="1.0"} serde={version="1.0", features=["derive"]} diff --git a/crates/tinywasm/tests/test-mvp.rs b/crates/tinywasm/tests/test-mvp.rs index eab372b..fdd043d 100644 --- a/crates/tinywasm/tests/test-mvp.rs +++ b/crates/tinywasm/tests/test-mvp.rs @@ -9,7 +9,7 @@ fn main() -> Result<()> { fn test_mvp() -> Result<()> { let mut test_suite = TestSuite::new(); - test_suite.run(wasm_testsuite::MVP_TESTS)?; + test_suite.run_spec_group(wasm_testsuite::MVP_TESTS)?; test_suite.save_csv("./tests/generated/mvp.csv", env!("CARGO_PKG_VERSION"))?; if test_suite.failed() { diff --git a/crates/tinywasm/tests/test-wast.rs b/crates/tinywasm/tests/test-wast.rs index 47e7d95..0770cb6 100644 --- a/crates/tinywasm/tests/test-wast.rs +++ b/crates/tinywasm/tests/test-wast.rs @@ -1,3 +1,5 @@ +use std::path::PathBuf; + use eyre::{bail, Result}; use testsuite::TestSuite; @@ -9,8 +11,20 @@ fn main() -> Result<()> { bail!("usage: cargo test-wast <wast-file>") } - let wast_file = &args[1]; - test_wast(wast_file)?; + // cwd for relative paths, absolute paths are kept as-is + let cwd = std::env::current_dir()?; + + // if current dir is crates/tinywasm, then we want to go up 2 levels + let mut wast_file = if cwd.ends_with("crates/tinywasm") { + PathBuf::from("../../") + } else { + PathBuf::from("./") + }; + + wast_file.push(&args[1]); + let wast_file = cwd.join(wast_file); + + test_wast(wast_file.to_str().expect("wast_file is not a valid path"))?; Ok(()) } @@ -19,7 +33,8 @@ fn test_wast(wast_file: &str) -> Result<()> { println!("args: {:?}", args); let mut test_suite = TestSuite::new(); - test_suite.run(&[wast_file])?; + println!("running wast file: {}", wast_file); + test_suite.run_paths(&[wast_file])?; if test_suite.failed() { eprintln!("\n\nfailed one or more tests:\n{:#?}", test_suite); diff --git a/crates/tinywasm/tests/testsuite/mod.rs b/crates/tinywasm/tests/testsuite/mod.rs index d5cde5f..2a9cf4e 100644 --- a/crates/tinywasm/tests/testsuite/mod.rs +++ b/crates/tinywasm/tests/testsuite/mod.rs @@ -1,3 +1,5 @@ +#![allow(dead_code)] // rust analyzer doesn't recognize that code is used by tests without harness + use eyre::Result; use std::io::{BufRead, Seek, SeekFrom}; use std::{ diff --git a/crates/tinywasm/tests/testsuite/run.rs b/crates/tinywasm/tests/testsuite/run.rs index 23c470c..afac117 100644 --- a/crates/tinywasm/tests/testsuite/run.rs +++ b/crates/tinywasm/tests/testsuite/run.rs @@ -7,165 +7,169 @@ use tinywasm_types::TinyWasmModule; use wast::{lexer::Lexer, parser::ParseBuffer, Wast}; impl TestSuite { - pub fn run(&mut self, tests: &[&str]) -> Result<()> { + pub fn run_paths(&mut self, tests: &[&str]) -> Result<()> { tests.iter().for_each(|group| { - let test_group = self.test_group(group); + let group_wast = std::fs::read(group).expect("failed to read test wast"); + let group_wast = Cow::Owned(group_wast); + self.run_group(group, group_wast).expect("failed to run group"); + }); - let wast = if group.starts_with("./") { - let file = std::fs::read(group).expect("failed to read test wast"); - Cow::Owned(file) - } else { - wasm_testsuite::get_test_wast(group).expect("failed to get test wast") - }; + Ok(()) + } - let wast = std::str::from_utf8(&wast).expect("failed to convert wast to utf8"); + pub fn run_spec_group(&mut self, tests: &[&str]) -> Result<()> { + tests.iter().for_each(|group| { + let group_wast = wasm_testsuite::get_test_wast(group).expect("failed to get test wast"); + self.run_group(group, group_wast).expect("failed to run group"); + }); - let mut lexer = Lexer::new(wast); - // we need to allow confusing unicode characters since they are technically valid wasm - lexer.allow_confusing_unicode(true); + Ok(()) + } - let buf = ParseBuffer::new_with_lexer(lexer).expect("failed to create parse buffer"); - let wast_data = wast::parser::parse::<Wast>(&buf).expect("failed to parse wat"); + pub fn run_group(&mut self, group_name: &str, group_wast: Cow<'_, [u8]>) -> Result<()> { + let test_group = self.test_group(group_name); + let wast = std::str::from_utf8(&group_wast).expect("failed to convert wast to utf8"); - let mut last_module: Option<TinyWasmModule> = None; - for (i, directive) in wast_data.directives.into_iter().enumerate() { - let span = directive.span(); - use wast::WastDirective::*; - let name = format!("{}-{}", group, i); + let mut lexer = Lexer::new(wast); + // we need to allow confusing unicode characters since they are technically valid wasm + lexer.allow_confusing_unicode(true); - match directive { - // TODO: needs to support more binary sections - Wat(mut module) => { - let result = catch_unwind_silent(move || parse_module_bytes(&module.encode().unwrap())) - .map_err(|e| eyre!("failed to parse module: {:?}", e)) - .and_then(|res| res); + let buf = ParseBuffer::new_with_lexer(lexer).expect("failed to create parse buffer"); + let wast_data = wast::parser::parse::<Wast>(&buf).expect("failed to parse wat"); - match &result { - Err(_) => last_module = None, - Ok(m) => last_module = Some(m.clone()), - } + let mut last_module: Option<TinyWasmModule> = None; + for (i, directive) in wast_data.directives.into_iter().enumerate() { + let span = directive.span(); + use wast::WastDirective::*; + let name = format!("{}-{}", group_name, i); - test_group.add_result(&format!("{}-parse", name), span, result.map(|_| ())); + match directive { + Wat(mut module) => { + let result = catch_unwind_silent(move || parse_module_bytes(&module.encode().unwrap())) + .map_err(|e| eyre!("failed to parse module: {:?}", e)) + .and_then(|res| res); + + match &result { + Err(_) => last_module = None, + Ok(m) => last_module = Some(m.clone()), } - AssertMalformed { - span, - mut module, - message: _, - } => { - let Ok(module) = module.encode() else { - test_group.add_result(&format!("{}-malformed", name), span, Ok(())); - continue; - }; + test_group.add_result(&format!("{}-parse", name), span, result.map(|_| ())); + } - let res = catch_unwind_silent(|| parse_module_bytes(&module)) - .map_err(|e| eyre!("failed to parse module: {:?}", e)) - .and_then(|res| res); + AssertMalformed { + span, + mut module, + message: _, + } => { + let Ok(module) = module.encode() else { + test_group.add_result(&format!("{}-malformed", name), span, Ok(())); + continue; + }; - test_group.add_result( - &format!("{}-malformed", name), - span, - match res { - Ok(_) => Err(eyre!("expected module to be malformed")), - Err(_) => Ok(()), - }, - ); - } + let res = catch_unwind_silent(|| parse_module_bytes(&module)) + .map_err(|e| eyre!("failed to parse module: {:?}", e)) + .and_then(|res| res); - AssertInvalid { + test_group.add_result( + &format!("{}-malformed", name), span, - mut module, - message: _, - } => { - let res = catch_unwind_silent(move || parse_module_bytes(&module.encode().unwrap())) - .map_err(|e| eyre!("failed to parse module: {:?}", e)) - .and_then(|res| res); - - test_group.add_result( - &format!("{}-invalid", name), - span, - match res { - Ok(_) => Err(eyre!("expected module to be invalid")), - Err(_) => Ok(()), - }, - ); - } + match res { + Ok(_) => Err(eyre!("expected module to be malformed")), + Err(_) => Ok(()), + }, + ); + } - AssertTrap { exec, message: _, span } => { - let res: Result<tinywasm::Result<()>, _> = catch_unwind_silent(|| { - let (module, name) = match exec { - wast::WastExecute::Wat(_wat) => unimplemented!("wat"), - wast::WastExecute::Get { module: _, global: _ } => unimplemented!("get"), - wast::WastExecute::Invoke(invoke) => (last_module.as_ref(), invoke.name), - }; - exec_fn(module, name, &[]).map(|_| ()) - }); + AssertInvalid { + span, + mut module, + message: _, + } => { + let res = catch_unwind_silent(move || parse_module_bytes(&module.encode().unwrap())) + .map_err(|e| eyre!("failed to parse module: {:?}", e)) + .and_then(|res| res); + test_group.add_result( + &format!("{}-invalid", name), + span, match res { - Err(err) => test_group.add_result( - &format!("{}-trap", name), - span, - Err(eyre!("test panicked: {:?}", err)), - ), - Ok(Err(tinywasm::Error::Trap(_))) => { - test_group.add_result(&format!("{}-trap", name), span, Ok(())) - } - Ok(Err(err)) => test_group.add_result( - &format!("{}-trap", name), - span, - Err(eyre!("expected trap, got error: {:?}", err)), - ), - Ok(Ok(())) => test_group.add_result( - &format!("{}-trap", name), - span, - Err(eyre!("expected trap, got ok")), - ), + Ok(_) => Err(eyre!("expected module to be invalid")), + Err(_) => Ok(()), + }, + ); + } + + AssertTrap { exec, message: _, span } => { + let res: Result<tinywasm::Result<()>, _> = catch_unwind_silent(|| { + let (module, name) = match exec { + wast::WastExecute::Wat(_wat) => unimplemented!("wat"), + wast::WastExecute::Get { module: _, global: _ } => unimplemented!("get"), + wast::WastExecute::Invoke(invoke) => (last_module.as_ref(), invoke.name), + }; + exec_fn(module, name, &[]).map(|_| ()) + }); + + match res { + Err(err) => test_group.add_result( + &format!("{}-trap", name), + span, + Err(eyre!("test panicked: {:?}", err)), + ), + Ok(Err(tinywasm::Error::Trap(_))) => { + test_group.add_result(&format!("{}-trap", name), span, Ok(())) + } + Ok(Err(err)) => test_group.add_result( + &format!("{}-trap", name), + span, + Err(eyre!("expected trap, got error: {:?}", err)), + ), + Ok(Ok(())) => { + test_group.add_result(&format!("{}-trap", name), span, Err(eyre!("expected trap, got ok"))) } } + } - AssertReturn { span, exec, results } => { - let res: Result<Result<()>, _> = catch_unwind_silent(|| { - let invoke = match exec { - wast::WastExecute::Wat(_) => unimplemented!("wat"), - wast::WastExecute::Get { module: _, global: _ } => { - return Err(eyre!("get not supported")) - } - wast::WastExecute::Invoke(invoke) => invoke, - }; + AssertReturn { span, exec, results } => { + let res: Result<Result<()>, _> = catch_unwind_silent(|| { + let invoke = match exec { + wast::WastExecute::Wat(_) => unimplemented!("wat"), + wast::WastExecute::Get { module: _, global: _ } => return Err(eyre!("get not supported")), + wast::WastExecute::Invoke(invoke) => invoke, + }; - let args = invoke - .args - .into_iter() - .map(wastarg2tinywasmvalue) - .collect::<Result<Vec<_>>>()?; + let args = invoke + .args + .into_iter() + .map(wastarg2tinywasmvalue) + .collect::<Result<Vec<_>>>()?; - let outcomes = exec_fn(last_module.as_ref(), invoke.name, &args)?; - let expected = results - .into_iter() - .map(wastret2tinywasmvalue) - .collect::<Result<Vec<_>>>()?; + let outcomes = exec_fn(last_module.as_ref(), invoke.name, &args)?; + let expected = results + .into_iter() + .map(wastret2tinywasmvalue) + .collect::<Result<Vec<_>>>()?; - if outcomes.len() != expected.len() { - return Err(eyre!("expected {} results, got {}", expected.len(), outcomes.len())); - } - outcomes - .iter() - .zip(expected) - .enumerate() - .try_for_each(|(i, (outcome, exp))| { - (outcome == &exp) - .then_some(()) - .ok_or_else(|| eyre!("result {} did not match: {:?} != {:?}", i, outcome, exp)) - }) - }); + if outcomes.len() != expected.len() { + return Err(eyre!("expected {} results, got {}", expected.len(), outcomes.len())); + } + outcomes + .iter() + .zip(expected) + .enumerate() + .try_for_each(|(i, (outcome, exp))| { + (outcome == &exp) + .then_some(()) + .ok_or_else(|| eyre!("result {} did not match: {:?} != {:?}", i, outcome, exp)) + }) + }); - let res = res.map_err(|e| eyre!("test panicked: {:?}", e)).and_then(|r| r); - test_group.add_result(&format!("{}-return", name), span, res); - } - _ => test_group.add_result(&format!("{}-unknown", name), span, Err(eyre!("unsupported directive"))), + let res = res.map_err(|e| eyre!("test panicked: {:?}", e)).and_then(|r| r); + test_group.add_result(&format!("{}-return", name), span, res); } + _ => test_group.add_result(&format!("{}-unknown", name), span, Err(eyre!("unsupported directive"))), } - }); + } Ok(()) } |
