feat: Support generic types in test_context macro (#44)

- Allow using test_context with generic contexts like MyContext<T>
This commit is contained in:
Changju Lee 2025-01-27 19:53:39 +09:00 committed by Victor Martinez
parent 7cab7279b4
commit 464cd415a6
3 changed files with 61 additions and 7 deletions

View file

@ -29,6 +29,22 @@ impl TestContext for MyContext {
fn test_works(ctx: &mut MyContext) {
assert_eq!(ctx.value, "Hello, World!");
}
struct MyGenericContext<T> {
value: T
}
impl TestContext for MyGenericContext<u32> {
fn setup() -> MyGenericContext<u32> {
MyGenericContext { value: 1 }
}
}
#[test_context(MyGenericContext<u32>)]
#[test]
fn test_generic_type(ctx: &mut MyGenericContext<u32>) {
assert_eq!(ctx.value, 1);
}
```
Alternatively, you can use `async` functions in your test context by using the

View file

@ -1,14 +1,14 @@
use syn::{parse::Parse, Ident, Token};
use syn::{parse::Parse, Token, Type};
pub(crate) struct TestContextArgs {
pub(crate) context_type: Ident,
pub(crate) context_type: Type,
pub(crate) skip_teardown: bool,
}
impl Parse for TestContextArgs {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
let mut skip_teardown = false;
let mut context_type: Option<Ident> = None;
let mut context_type: Option<Type> = None;
while !input.is_empty() {
let lookahead = input.lookahead1();
@ -18,10 +18,8 @@ impl Parse for TestContextArgs {
}
let _ = input.parse::<kw::skip_teardown>()?;
skip_teardown = true;
} else if lookahead.peek(Ident) {
if context_type.is_some() {
return Err(input.error("expected only a single type identifier"));
}
} else if context_type.is_none() {
// Parse any valid Rust type, including generic types
context_type = Some(input.parse()?);
} else if lookahead.peek(Token![,]) {
let _ = input.parse::<Token![,]>()?;

View file

@ -131,3 +131,43 @@ async fn test_async_skip_teardown(mut _ctx: TeardownPanicContext) {}
#[test_context(TeardownPanicContext, skip_teardown)]
#[test]
fn test_sync_skip_teardown(mut _ctx: TeardownPanicContext) {}
struct GenericContext<T> {
contents: T,
}
impl TestContext for GenericContext<u32> {
fn setup() -> Self {
Self { contents: 1 }
}
}
impl TestContext for GenericContext<String> {
fn setup() -> Self {
Self { contents: format!("hello world") }
}
}
impl AsyncTestContext for GenericContext<u64> {
async fn setup() -> Self {
Self { contents: 1 }
}
}
#[test_context(GenericContext<u32>)]
#[test]
fn test_generic_with_u32(ctx: &mut GenericContext<u32>) {
assert_eq!(ctx.contents, 1);
}
#[test_context(GenericContext<String>)]
#[test]
fn test_generic_with_string(ctx: &mut GenericContext<String>) {
assert_eq!(ctx.contents, "hello world");
}
#[test_context(GenericContext<u64>)]
#[tokio::test]
async fn test_async_generic(ctx: &mut GenericContext<u64>) {
assert_eq!(ctx.contents, 1);
}