Skip to content

Commit 4e60952

Browse files
authored
Handle #[ignore = "reason"] on tests (#3644)
1 parent 5b42ffc commit 4e60952

File tree

11 files changed

+295
-26
lines changed

11 files changed

+295
-26
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,10 @@
6363
* Implement `TryFrom<JsValue>` for exported Rust types and strings.
6464
[#3554](https://github.com/rustwasm/wasm-bindgen/pull/3554)
6565

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

6872
* Updated the WebGPU WebIDL.

crates/futures/tests/tests.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,3 +173,15 @@ async fn should_panic_string() {
173173
async fn should_panic_expected() {
174174
panic!("error message")
175175
}
176+
177+
#[wasm_bindgen_test]
178+
#[ignore]
179+
async fn ignore() {
180+
panic!("this test should have been ignored")
181+
}
182+
183+
#[wasm_bindgen_test]
184+
#[ignore = "reason"]
185+
async fn ignore_reason() {
186+
panic!("this test should have been ignored")
187+
}

crates/test-macro/src/lib.rs

Lines changed: 81 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ pub fn wasm_bindgen_test(
2121

2222
syn::parse_macro_input!(attr with attribute_parser);
2323
let mut should_panic = None;
24+
let mut ignore = None;
2425

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

@@ -42,6 +43,21 @@ pub fn wasm_bindgen_test(
4243
Err(error) => return error,
4344
}
4445

46+
match parse_ignore(&mut body, &token) {
47+
Ok(Some((new_ignore, span))) => {
48+
if ignore.replace(new_ignore).is_some() {
49+
return compile_error(span, "duplicate `ignore` attribute");
50+
}
51+
52+
// If we found a `new_ignore`, we should skip the `#` and `[...]`.
53+
// The `[...]` is skipped here, the current `#` is skipped by using `continue`.
54+
body.next();
55+
continue;
56+
}
57+
Ok(None) => (),
58+
Err(error) => return error,
59+
}
60+
4561
leading_tokens.push(token.clone());
4662
if let TokenTree::Ident(token) = token {
4763
if token == "async" {
@@ -64,10 +80,18 @@ pub fn wasm_bindgen_test(
6480
None => quote! { ::core::option::Option::None },
6581
};
6682

83+
let ignore = match ignore {
84+
Some(Some(lit)) => {
85+
quote! { ::core::option::Option::Some(::core::option::Option::Some(#lit)) }
86+
}
87+
Some(None) => quote! { ::core::option::Option::Some(::core::option::Option::None) },
88+
None => quote! { ::core::option::Option::None },
89+
};
90+
6791
let test_body = if attributes.r#async {
68-
quote! { cx.execute_async(test_name, #ident, #should_panic); }
92+
quote! { cx.execute_async(test_name, #ident, #should_panic, #ignore); }
6993
} else {
70-
quote! { cx.execute_sync(test_name, #ident, #should_panic); }
94+
quote! { cx.execute_sync(test_name, #ident, #should_panic, #ignore); }
7195
};
7296

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

201+
fn parse_ignore(
202+
body: &mut std::iter::Peekable<token_stream::IntoIter>,
203+
token: &TokenTree,
204+
) -> Result<Option<(Option<Literal>, Span)>, proc_macro::TokenStream> {
205+
// Start by parsing the `#`
206+
match token {
207+
TokenTree::Punct(op) if op.as_char() == '#' => (),
208+
_ => return Ok(None),
209+
}
210+
211+
// Parse `[...]`
212+
let group = match body.peek() {
213+
Some(TokenTree::Group(group)) if group.delimiter() == Delimiter::Bracket => group,
214+
_ => return Ok(None),
215+
};
216+
217+
let mut stream = group.stream().into_iter();
218+
219+
// Parse `ignore`
220+
let mut span = match stream.next() {
221+
Some(TokenTree::Ident(token)) if token == "ignore" => token.span(),
222+
_ => return Ok(None),
223+
};
224+
225+
let ignore = span;
226+
227+
// We are interested in the reason string if there is any
228+
match stream.next() {
229+
// Parse `=`
230+
Some(TokenTree::Punct(op)) if op.as_char() == '=' => (),
231+
Some(token) => {
232+
return Err(compile_error(
233+
token.span(),
234+
"malformed `#[ignore = \"...\"]` attribute",
235+
))
236+
}
237+
None => {
238+
return Ok(Some((None, ignore)));
239+
}
240+
}
241+
242+
// Parse string in `#[ignore = "string"]`
243+
if let Some(TokenTree::Literal(lit)) = stream.next() {
244+
span = lit.span();
245+
let string = lit.to_string();
246+
247+
// Verify it's a string.
248+
if string.starts_with('"') && string.ends_with('"') {
249+
return Ok(Some((Some(lit), ignore)));
250+
}
251+
}
252+
253+
Err(compile_error(span, "malformed `#[ignore]` attribute"))
254+
}
255+
177256
fn find_ident(iter: &mut impl Iterator<Item = TokenTree>) -> Option<Ident> {
178257
match iter.next()? {
179258
TokenTree::Ident(i) => Some(i),

crates/test-macro/ui-tests/ignore.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
#![no_implicit_prelude]
2+
3+
extern crate wasm_bindgen_test_macro;
4+
5+
use wasm_bindgen_test_macro::wasm_bindgen_test;
6+
7+
#[wasm_bindgen_test]
8+
#[ignore]
9+
fn success_1() {}
10+
11+
#[wasm_bindgen_test]
12+
#[ignore = "test"]
13+
fn success_2() {}
14+
15+
#[wasm_bindgen_test]
16+
#[ignore]
17+
async fn async_success_1() {}
18+
19+
#[wasm_bindgen_test]
20+
#[ignore = "test"]
21+
async fn async_success_2() {}
22+
23+
#[wasm_bindgen_test]
24+
#[ignore::error]
25+
fn fail_1() {}
26+
27+
#[wasm_bindgen_test]
28+
#[ignore = 42]
29+
fn fail_2() {}
30+
31+
#[wasm_bindgen_test]
32+
#[ignore[]]
33+
fn fail_3() {}
34+
35+
#[wasm_bindgen_test]
36+
#[ignore(42)]
37+
fn fail_4() {}
38+
39+
#[wasm_bindgen_test]
40+
#[ignore(test)]
41+
fn fail_5() {}
42+
43+
#[wasm_bindgen_test]
44+
#[ignore("test")]
45+
fn fail_6() {}
46+
47+
#[wasm_bindgen_test]
48+
#[ignore = "test"]
49+
#[ignore = "test"]
50+
fn fail_7() {}
51+
52+
fn main() {}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
error: malformed `#[ignore = "..."]` attribute
2+
--> ui-tests/ignore.rs:24:9
3+
|
4+
24 | #[ignore::error]
5+
| ^
6+
7+
error: malformed `#[ignore]` attribute
8+
--> ui-tests/ignore.rs:28:12
9+
|
10+
28 | #[ignore = 42]
11+
| ^^
12+
13+
error: malformed `#[ignore = "..."]` attribute
14+
--> ui-tests/ignore.rs:32:9
15+
|
16+
32 | #[ignore[]]
17+
| ^^
18+
19+
error: malformed `#[ignore = "..."]` attribute
20+
--> ui-tests/ignore.rs:36:9
21+
|
22+
36 | #[ignore(42)]
23+
| ^^^^
24+
25+
error: malformed `#[ignore = "..."]` attribute
26+
--> ui-tests/ignore.rs:40:9
27+
|
28+
40 | #[ignore(test)]
29+
| ^^^^^^
30+
31+
error: malformed `#[ignore = "..."]` attribute
32+
--> ui-tests/ignore.rs:44:9
33+
|
34+
44 | #[ignore("test")]
35+
| ^^^^^^^^
36+
37+
error: duplicate `ignore` attribute
38+
--> ui-tests/ignore.rs:49:3
39+
|
40+
49 | #[ignore = "test"]
41+
| ^^^^^^

crates/test/sample/tests/common/mod.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,3 +69,15 @@ fn should_panic_string() {
6969
fn should_panic_expected() {
7070
panic!("error message")
7171
}
72+
73+
#[wasm_bindgen_test]
74+
#[ignore]
75+
async fn ignore() {
76+
console_log!("IGNORED");
77+
}
78+
79+
#[wasm_bindgen_test]
80+
#[should_panic = "reason"]
81+
async fn ignore_reason() {
82+
panic!("IGNORED WITH A REASON")
83+
}

crates/test/src/rt/browser.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
use js_sys::Error;
77
use wasm_bindgen::prelude::*;
88

9+
use super::TestResult;
10+
911
/// Implementation of `Formatter` for browsers.
1012
///
1113
/// Routes all output to a `pre` on the page currently. Eventually this probably
@@ -49,9 +51,8 @@ impl super::Formatter for Browser {
4951
self.pre.set_text_content(&html);
5052
}
5153

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

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

0 commit comments

Comments
 (0)