-
Notifications
You must be signed in to change notification settings - Fork 501
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Macro for logging with test_case. Might be needed once this bug is fixed: frondeus/test-case#101 See here: https://docs.google.com/document/d/1zAbVqlSNeM5zaOqt4b-hFISlKy6ua9bh0mm99SHrb4E/edit#
- Loading branch information
Showing
2 changed files
with
103 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
[package] | ||
name = "test_utils_macros" | ||
version.workspace = true | ||
edition.workspace = true | ||
|
||
[lib] | ||
proc-macro = true | ||
|
||
[features] | ||
testing = [] | ||
|
||
[dependencies] | ||
env_logger.workspace = true | ||
indexmap.workspace = true | ||
itertools.workspace = true | ||
syn.workspace = true | ||
quote.workspace = true | ||
|
||
[dev-dependencies] | ||
proc-macro2 = "1.0" | ||
test-case-macros = "2.2.1" | ||
test-case.workspace = true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
use proc_macro::TokenStream; | ||
use quote::__private::TokenStream as TokenStream2; | ||
use quote::{quote, ToTokens}; | ||
use syn::parse::{Parse, ParseStream, Parser}; | ||
use syn::punctuated::Punctuated; | ||
use syn::{parenthesized, token, Error, Expr, LitStr, Token}; | ||
|
||
// A macro to replace #[test], which allows logging. | ||
#[proc_macro_attribute] | ||
pub fn test(_attr: TokenStream, item: TokenStream) -> TokenStream { | ||
let item_fn = syn::parse_macro_input!(item as syn::ItemFn); | ||
proc_macro::TokenStream::from(quote! { | ||
#[test_log::test] | ||
#item_fn | ||
}) | ||
} | ||
|
||
/// Represents a single test-case of the form: `(args...; "name")`. | ||
struct WrappedTestCase { | ||
_paren_token: token::Paren, | ||
test_case: Punctuated<Expr, Token![,]>, | ||
_semi: Token![;], | ||
name: LitStr, | ||
} | ||
impl Parse for WrappedTestCase { | ||
fn parse(input: ParseStream<'_>) -> Result<Self, Error> { | ||
let content; | ||
Ok(WrappedTestCase { | ||
_paren_token: parenthesized!(content in input), | ||
test_case: Punctuated::parse_separated_nonempty_with(&content, Expr::parse)?, | ||
_semi: content.parse()?, | ||
name: content.parse()?, | ||
}) | ||
} | ||
} | ||
impl ToTokens for WrappedTestCase { | ||
fn to_tokens(&self, tokens: &mut TokenStream2) { | ||
let test_case = &self.test_case; | ||
let name = &self.name; | ||
let all = quote! { (#test_case; #name) }; | ||
tokens.extend(all); | ||
} | ||
} | ||
|
||
/// A comma-separated array of `WrappedTestCase`s. e.g.: `(1, "case1"), (2, "case2")`. | ||
struct TestCaseArray { | ||
pub test_cases: Punctuated<WrappedTestCase, Token![,]>, | ||
} | ||
impl Parse for TestCaseArray { | ||
fn parse(input: ParseStream<'_>) -> Result<Self, Error> { | ||
Ok(TestCaseArray { | ||
test_cases: Punctuated::parse_separated_nonempty_with(input, WrappedTestCase::parse)?, | ||
}) | ||
} | ||
} | ||
|
||
/// A macro to replace #[test_case], which allows logging. | ||
/// The syntax is similar but not the same: instead of having multiple `#[test_case(...)]` | ||
/// attributes, use a single `#[test_case((1, "case1"), (2, "case2"))]` attribute. | ||
#[proc_macro_attribute] | ||
pub fn test_case(attr: TokenStream, item: TokenStream) -> TokenStream { | ||
let item_fn = syn::parse_macro_input!(item as syn::ItemFn); | ||
|
||
let mut all_test_cases = quote! {}; | ||
let parser = TestCaseArray::parse; | ||
let test_case_arr = parser.parse(attr).expect("unexpected macro failure"); | ||
|
||
for wrapped_test_case in test_case_arr.test_cases { | ||
let test_case = wrapped_test_case.test_case; | ||
all_test_cases = quote! { | ||
#all_test_cases | ||
#[test_case::test_case(#test_case)] | ||
}; | ||
} | ||
|
||
proc_macro::TokenStream::from(quote! { | ||
#all_test_cases | ||
#[test_log::test] | ||
#item_fn | ||
}) | ||
} |