Skip to content

Commit

Permalink
Handle #[ignore = "reason"] on tests (#3644)
Browse files Browse the repository at this point in the history
  • Loading branch information
daxpedda committed Oct 9, 2023
1 parent 5b42ffc commit 4e60952
Show file tree
Hide file tree
Showing 11 changed files with 295 additions and 26 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@
* Implement `TryFrom<JsValue>` for exported Rust types and strings.
[#3554](https://github.com/rustwasm/wasm-bindgen/pull/3554)

* Handle the `#[ignore = "reason"]` attribute with the `wasm_bindgen_test`
proc-macro and accept the `--include-ignored` flag with `wasm-bindgen-test-runner`.
[#3644](https://github.com/rustwasm/wasm-bindgen/pull/3644)

### Changed

* Updated the WebGPU WebIDL.
Expand Down
12 changes: 12 additions & 0 deletions crates/futures/tests/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,3 +173,15 @@ async fn should_panic_string() {
async fn should_panic_expected() {
panic!("error message")
}

#[wasm_bindgen_test]
#[ignore]
async fn ignore() {
panic!("this test should have been ignored")
}

#[wasm_bindgen_test]
#[ignore = "reason"]
async fn ignore_reason() {
panic!("this test should have been ignored")
}
83 changes: 81 additions & 2 deletions crates/test-macro/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ pub fn wasm_bindgen_test(

syn::parse_macro_input!(attr with attribute_parser);
let mut should_panic = None;
let mut ignore = None;

let mut body = TokenStream::from(body).into_iter().peekable();

Expand All @@ -42,6 +43,21 @@ pub fn wasm_bindgen_test(
Err(error) => return error,
}

match parse_ignore(&mut body, &token) {
Ok(Some((new_ignore, span))) => {
if ignore.replace(new_ignore).is_some() {
return compile_error(span, "duplicate `ignore` attribute");
}

// If we found a `new_ignore`, we should skip the `#` and `[...]`.
// The `[...]` is skipped here, the current `#` is skipped by using `continue`.
body.next();
continue;
}
Ok(None) => (),
Err(error) => return error,
}

leading_tokens.push(token.clone());
if let TokenTree::Ident(token) = token {
if token == "async" {
Expand All @@ -64,10 +80,18 @@ pub fn wasm_bindgen_test(
None => quote! { ::core::option::Option::None },
};

let ignore = match ignore {
Some(Some(lit)) => {
quote! { ::core::option::Option::Some(::core::option::Option::Some(#lit)) }
}
Some(None) => quote! { ::core::option::Option::Some(::core::option::Option::None) },
None => quote! { ::core::option::Option::None },
};

let test_body = if attributes.r#async {
quote! { cx.execute_async(test_name, #ident, #should_panic); }
quote! { cx.execute_async(test_name, #ident, #should_panic, #ignore); }
} else {
quote! { cx.execute_sync(test_name, #ident, #should_panic); }
quote! { cx.execute_sync(test_name, #ident, #should_panic, #ignore); }
};

// We generate a `#[no_mangle]` with a known prefix so the test harness can
Expand Down Expand Up @@ -174,6 +198,61 @@ fn parse_should_panic(
Err(compile_error(span, "malformed `#[should_panic]` attribute"))
}

fn parse_ignore(
body: &mut std::iter::Peekable<token_stream::IntoIter>,
token: &TokenTree,
) -> Result<Option<(Option<Literal>, Span)>, proc_macro::TokenStream> {
// Start by parsing the `#`
match token {
TokenTree::Punct(op) if op.as_char() == '#' => (),
_ => return Ok(None),
}

// Parse `[...]`
let group = match body.peek() {
Some(TokenTree::Group(group)) if group.delimiter() == Delimiter::Bracket => group,
_ => return Ok(None),
};

let mut stream = group.stream().into_iter();

// Parse `ignore`
let mut span = match stream.next() {
Some(TokenTree::Ident(token)) if token == "ignore" => token.span(),
_ => return Ok(None),
};

let ignore = span;

// We are interested in the reason string if there is any
match stream.next() {
// Parse `=`
Some(TokenTree::Punct(op)) if op.as_char() == '=' => (),
Some(token) => {
return Err(compile_error(
token.span(),
"malformed `#[ignore = \"...\"]` attribute",
))
}
None => {
return Ok(Some((None, ignore)));
}
}

// Parse string in `#[ignore = "string"]`
if let Some(TokenTree::Literal(lit)) = stream.next() {
span = lit.span();
let string = lit.to_string();

// Verify it's a string.
if string.starts_with('"') && string.ends_with('"') {
return Ok(Some((Some(lit), ignore)));
}
}

Err(compile_error(span, "malformed `#[ignore]` attribute"))
}

fn find_ident(iter: &mut impl Iterator<Item = TokenTree>) -> Option<Ident> {
match iter.next()? {
TokenTree::Ident(i) => Some(i),
Expand Down
52 changes: 52 additions & 0 deletions crates/test-macro/ui-tests/ignore.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#![no_implicit_prelude]

extern crate wasm_bindgen_test_macro;

use wasm_bindgen_test_macro::wasm_bindgen_test;

#[wasm_bindgen_test]
#[ignore]
fn success_1() {}

#[wasm_bindgen_test]
#[ignore = "test"]
fn success_2() {}

#[wasm_bindgen_test]
#[ignore]
async fn async_success_1() {}

#[wasm_bindgen_test]
#[ignore = "test"]
async fn async_success_2() {}

#[wasm_bindgen_test]
#[ignore::error]
fn fail_1() {}

#[wasm_bindgen_test]
#[ignore = 42]
fn fail_2() {}

#[wasm_bindgen_test]
#[ignore[]]
fn fail_3() {}

#[wasm_bindgen_test]
#[ignore(42)]
fn fail_4() {}

#[wasm_bindgen_test]
#[ignore(test)]
fn fail_5() {}

#[wasm_bindgen_test]
#[ignore("test")]
fn fail_6() {}

#[wasm_bindgen_test]
#[ignore = "test"]
#[ignore = "test"]
fn fail_7() {}

fn main() {}
41 changes: 41 additions & 0 deletions crates/test-macro/ui-tests/ignore.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
error: malformed `#[ignore = "..."]` attribute
--> ui-tests/ignore.rs:24:9
|
24 | #[ignore::error]
| ^

error: malformed `#[ignore]` attribute
--> ui-tests/ignore.rs:28:12
|
28 | #[ignore = 42]
| ^^

error: malformed `#[ignore = "..."]` attribute
--> ui-tests/ignore.rs:32:9
|
32 | #[ignore[]]
| ^^

error: malformed `#[ignore = "..."]` attribute
--> ui-tests/ignore.rs:36:9
|
36 | #[ignore(42)]
| ^^^^

error: malformed `#[ignore = "..."]` attribute
--> ui-tests/ignore.rs:40:9
|
40 | #[ignore(test)]
| ^^^^^^

error: malformed `#[ignore = "..."]` attribute
--> ui-tests/ignore.rs:44:9
|
44 | #[ignore("test")]
| ^^^^^^^^

error: duplicate `ignore` attribute
--> ui-tests/ignore.rs:49:3
|
49 | #[ignore = "test"]
| ^^^^^^
12 changes: 12 additions & 0 deletions crates/test/sample/tests/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,15 @@ fn should_panic_string() {
fn should_panic_expected() {
panic!("error message")
}

#[wasm_bindgen_test]
#[ignore]
async fn ignore() {
console_log!("IGNORED");
}

#[wasm_bindgen_test]
#[should_panic = "reason"]
async fn ignore_reason() {
panic!("IGNORED WITH A REASON")
}
7 changes: 4 additions & 3 deletions crates/test/src/rt/browser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
use js_sys::Error;
use wasm_bindgen::prelude::*;

use super::TestResult;

/// Implementation of `Formatter` for browsers.
///
/// Routes all output to a `pre` on the page currently. Eventually this probably
Expand Down Expand Up @@ -49,9 +51,8 @@ impl super::Formatter for Browser {
self.pre.set_text_content(&html);
}

fn log_test(&self, name: &str, result: &Result<(), JsValue>) {
let s = if result.is_ok() { "ok" } else { "FAIL" };
self.writeln(&format!("test {} ... {}", name, s));
fn log_test(&self, name: &str, result: &TestResult) {
self.writeln(&format!("test {} ... {}", name, result));
}

fn stringify_error(&self, err: &JsValue) -> String {
Expand Down

0 comments on commit 4e60952

Please sign in to comment.