diff --git a/CHANGELOG.md b/CHANGELOG.md index ad1467af0c8..9a12d912268 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,6 +42,10 @@ * Add bindings for `CanvasTransform.setTransform(DOMMatrix2DInit)`. [#3580](https://github.com/rustwasm/wasm-bindgen/pull/3580) +* Add a `crate` attribute to the `wasm_bindgen_test` proc-macro to specify a + non-default path to the `wasm-bindgen-test` crate. + [#3593](https://github.com/rustwasm/wasm-bindgen/pull/3593) + ### Changed * Updated the WebGPU WebIDL. diff --git a/crates/test-macro/Cargo.toml b/crates/test-macro/Cargo.toml index 88d8c5de171..540fd7f0a7a 100644 --- a/crates/test-macro/Cargo.toml +++ b/crates/test-macro/Cargo.toml @@ -14,6 +14,7 @@ proc-macro = true [dependencies] proc-macro2 = "1.0" quote = "1.0" +syn = { version = "2.0", default-features = false, features = [ "parsing", "proc-macro", "derive", "printing" ] } [dev-dependencies] wasm-bindgen-test = { path = "../test" } diff --git a/crates/test-macro/src/lib.rs b/crates/test-macro/src/lib.rs index 53050be011c..8215bb3206a 100644 --- a/crates/test-macro/src/lib.rs +++ b/crates/test-macro/src/lib.rs @@ -16,30 +16,11 @@ pub fn wasm_bindgen_test( attr: proc_macro::TokenStream, body: proc_macro::TokenStream, ) -> proc_macro::TokenStream { - let mut attr = attr.into_iter(); - let mut r#async = false; + let mut attributes = Attributes::default(); + let attribute_parser = syn::meta::parser(|meta| attributes.parse(meta)); + + syn::parse_macro_input!(attr with attribute_parser); let mut should_panic = None; - while let Some(token) = attr.next() { - match &token { - proc_macro::TokenTree::Ident(i) if i.to_string() == "async" => r#async = true, - _ => { - return compile_error( - token.span().into(), - "malformed `#[wasm_bindgen_test]` attribute", - ) - } - } - match &attr.next() { - Some(proc_macro::TokenTree::Punct(op)) if op.as_char() == ',' => {} - Some(_) => { - return compile_error( - token.span().into(), - "malformed `#[wasm_bindgen_test]` attribute", - ) - } - None => break, - } - } let mut body = TokenStream::from(body).into_iter().peekable(); @@ -64,7 +45,7 @@ pub fn wasm_bindgen_test( leading_tokens.push(token.clone()); if let TokenTree::Ident(token) = token { if token == "async" { - r#async = true; + attributes.r#async = true; } if token == "fn" { break; @@ -83,7 +64,7 @@ pub fn wasm_bindgen_test( None => quote! { ::core::option::Option::None }, }; - let test_body = if r#async { + let test_body = if attributes.r#async { quote! { cx.execute_async(test_name, #ident, #should_panic); } } else { quote! { cx.execute_sync(test_name, #ident, #should_panic); } @@ -93,10 +74,11 @@ pub fn wasm_bindgen_test( // later slurp up all of these functions and pass them as arguments to the // main test harness. This is the entry point for all tests. let name = format_ident!("__wbgt_{}_{}", ident, CNT.fetch_add(1, Ordering::SeqCst)); + let wasm_bindgen_path = attributes.wasm_bindgen_path; tokens.extend( quote! { #[no_mangle] - pub extern "C" fn #name(cx: &::wasm_bindgen_test::__rt::Context) { + pub extern "C" fn #name(cx: &#wasm_bindgen_path::__rt::Context) { let test_name = ::core::concat!(::core::module_path!(), "::", ::core::stringify!(#ident)); #test_body } @@ -205,3 +187,30 @@ fn find_ident(iter: &mut impl Iterator) -> Option { fn compile_error(span: Span, msg: &str) -> proc_macro::TokenStream { quote_spanned! { span => compile_error!(#msg); }.into() } + +struct Attributes { + r#async: bool, + wasm_bindgen_path: syn::Path, +} + +impl Default for Attributes { + fn default() -> Self { + Self { + r#async: false, + wasm_bindgen_path: syn::parse_quote!(::wasm_bindgen_test), + } + } +} + +impl Attributes { + fn parse(&mut self, meta: syn::meta::ParseNestedMeta) -> syn::parse::Result<()> { + if meta.path.is_ident("async") { + self.r#async = true; + } else if meta.path.is_ident("crate") { + self.wasm_bindgen_path = meta.value()?.parse::()?; + } else { + return Err(meta.error("unknown attribute")); + } + Ok(()) + } +} diff --git a/crates/test-macro/ui-tests/crate.rs b/crates/test-macro/ui-tests/crate.rs new file mode 100644 index 00000000000..2087f7575b6 --- /dev/null +++ b/crates/test-macro/ui-tests/crate.rs @@ -0,0 +1,20 @@ +#![no_implicit_prelude] + +extern crate wasm_bindgen_test_macro; +// +use wasm_bindgen_test_macro::wasm_bindgen_test; + +pub mod wasm { + pub extern crate wasm_bindgen_test as test; +} + +#[wasm_bindgen_test(crate = ::wasm_bindgen_test)] +fn success_1() {} + +#[wasm_bindgen_test(crate = crate::wasm::test)] +fn success_2() {} + +#[wasm_bindgen_test(crate = foo)] +fn failure_1() {} + +fn main() {} diff --git a/crates/test-macro/ui-tests/crate.stderr b/crates/test-macro/ui-tests/crate.stderr new file mode 100644 index 00000000000..2bace352ee4 --- /dev/null +++ b/crates/test-macro/ui-tests/crate.stderr @@ -0,0 +1,5 @@ +error[E0433]: failed to resolve: use of undeclared crate or module `foo` + --> ui-tests/crate.rs:17:29 + | +17 | #[wasm_bindgen_test(crate = foo)] + | ^^^ use of undeclared crate or module `foo`