Skip to content

Commit

Permalink
Add attribute crate to proc-macro wasm-bindgen-test (rustwasm#3593)
Browse files Browse the repository at this point in the history
  • Loading branch information
FirelightFlagboy authored Sep 4, 2023
1 parent 4d4851d commit 41617bd
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 26 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
1 change: 1 addition & 0 deletions crates/test-macro/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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" }
Expand Down
61 changes: 35 additions & 26 deletions crates/test-macro/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand All @@ -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;
Expand All @@ -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); }
Expand All @@ -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
}
Expand Down Expand Up @@ -205,3 +187,30 @@ fn find_ident(iter: &mut impl Iterator<Item = TokenTree>) -> Option<Ident> {
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::<syn::Path>()?;
} else {
return Err(meta.error("unknown attribute"));
}
Ok(())
}
}
20 changes: 20 additions & 0 deletions crates/test-macro/ui-tests/crate.rs
Original file line number Diff line number Diff line change
@@ -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() {}
5 changes: 5 additions & 0 deletions crates/test-macro/ui-tests/crate.stderr
Original file line number Diff line number Diff line change
@@ -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`

0 comments on commit 41617bd

Please sign in to comment.