Skip to content

Commit

Permalink
macros: append generated test attribute so others are aware of it
Browse files Browse the repository at this point in the history
This way other test macros can choose to not generate
`#[::core::prelude::v1::test]` to avoid duplicated test runs.

This commit also rejects existing `#[::core::prelude::v1::test]` just
like how and why it rejects existing `#[test]`.
  • Loading branch information
kezhuw committed Apr 19, 2024
1 parent 5ba12a7 commit d6c9bc2
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 10 deletions.
4 changes: 4 additions & 0 deletions tests-build/tests/fail/macros_invalid_input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,8 @@ async fn test_crate_not_path_invalid() {}
#[test]
async fn test_has_second_test_attr() {}

#[tokio::test]
#[::core::prelude::v1::test]
async fn test_has_generated_second_test_attr() {}

fn main() {}
20 changes: 19 additions & 1 deletion tests-build/tests/fail/macros_invalid_input.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ error: Failed to parse value of `crate` as path: "456"
41 | #[tokio::test(crate = "456")]
| ^^^^^

error: second test attribute is supplied
error: second test attribute is supplied, try to order it after `tokio::test`
--> $DIR/macros_invalid_input.rs:45:1
|
45 | #[test]
Expand All @@ -93,3 +93,21 @@ note: the lint level is defined here
|
1 | #![deny(duplicate_macro_attributes)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^

error: second test attribute is supplied, try to order it after `tokio::test`
--> $DIR/macros_invalid_input.rs:49:1
|
49 | #[::core::prelude::v1::test::test]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: duplicated attribute
--> $DIR/macros_invalid_input.rs:49:1
|
49 | #[::core::prelude::v1::test::test]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: the lint level is defined here
--> $DIR/macros_invalid_input.rs:1:9
|
1 | #![deny(duplicate_macro_attributes)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
2 changes: 1 addition & 1 deletion tokio-macros/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ proc-macro = true
[dependencies]
proc-macro2 = "1.0.60"
quote = "1"
syn = { version = "2.0", features = ["full"] }
syn = { version = "2.0", features = ["full", "extra-traits"] }

[dev-dependencies]
tokio = { version = "1.0.0", path = "../tokio", features = ["full"] }
Expand Down
22 changes: 14 additions & 8 deletions tokio-macros/src/entry.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use proc_macro2::{Span, TokenStream, TokenTree};
use quote::{quote, quote_spanned, ToTokens};
use syn::parse::{Parse, ParseStream, Parser};
use syn::{braced, Attribute, Ident, Path, Signature, Visibility};
use syn::{braced, parse_quote, Attribute, Ident, Path, Signature, Visibility};

// syn::AttributeArgs does not implement syn::Parse
type AttributeArgs = syn::punctuated::Punctuated<syn::Meta, syn::Token![,]>;
Expand Down Expand Up @@ -360,7 +360,7 @@ fn parse_knobs(mut input: ItemFn, is_test: bool, config: FinalConfig) -> TokenSt
rt = quote_spanned! {last_stmt_start_span=> #rt.start_paused(#v) };
}

let header = if is_test {
let generated_attrs = if is_test {
quote! {
#[::core::prelude::v1::test]
}
Expand Down Expand Up @@ -410,7 +410,7 @@ fn parse_knobs(mut input: ItemFn, is_test: bool, config: FinalConfig) -> TokenSt
}
};

input.into_tokens(header, body, last_block)
input.into_tokens(generated_attrs, body, last_block)
}

fn token_stream_with_error(mut tokens: TokenStream, error: syn::Error) -> TokenStream {
Expand Down Expand Up @@ -451,8 +451,13 @@ pub(crate) fn test(args: TokenStream, item: TokenStream, rt_multi_thread: bool)
Ok(it) => it,
Err(e) => return token_stream_with_error(item, e),
};
let config = if let Some(attr) = input.attrs().find(|attr| attr.meta.path().is_ident("test")) {
let msg = "second test attribute is supplied";
let test_attr: Attribute = parse_quote! { #[test] };
let qualified_test_attr = parse_quote! { #[::core::prelude::v1::test] };
let config = if let Some(attr) = input
.attrs()
.find(|attr| **attr == test_attr || **attr == qualified_test_attr)
{
let msg = "second test attribute is supplied, try to order it after `tokio::test`";
Err(syn::Error::new_spanned(attr, msg))
} else {
AttributeArgs::parse_terminated
Expand Down Expand Up @@ -493,13 +498,11 @@ impl ItemFn {
/// Convert our local function item into a token stream.
fn into_tokens(
self,
header: proc_macro2::TokenStream,
generated_attrs: proc_macro2::TokenStream,
body: proc_macro2::TokenStream,
last_block: proc_macro2::TokenStream,
) -> TokenStream {
let mut tokens = proc_macro2::TokenStream::new();
header.to_tokens(&mut tokens);

// Outer attributes are simply streamed as-is.
for attr in self.outer_attrs {
attr.to_tokens(&mut tokens);
Expand All @@ -513,6 +516,9 @@ impl ItemFn {
attr.to_tokens(&mut tokens);
}

// Add generated macros at the end, so macros processed later are aware of them.
generated_attrs.to_tokens(&mut tokens);

self.vis.to_tokens(&mut tokens);
self.sig.to_tokens(&mut tokens);

Expand Down

0 comments on commit d6c9bc2

Please sign in to comment.