mirror of
https://codeberg.org/JasterV/test-context.git
synced 2026-04-26 18:10:06 +00:00
feat: Support generic types in test_context macro (#44)
- Allow using test_context with generic contexts like MyContext<T>
This commit is contained in:
parent
7cab7279b4
commit
a58e13ecf5
3 changed files with 80 additions and 7 deletions
36
README.md
36
README.md
|
|
@ -31,6 +31,42 @@ fn test_works(ctx: &mut MyContext) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
with generic types, you can use same type with different values
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use test_context::{test_context, TestContext};
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
|
struct MyGenericContext<T> {
|
||||||
|
value: u32,
|
||||||
|
_marker: PhantomData<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestContext for MyGenericContext<String> {
|
||||||
|
fn setup() -> MyGenericContext<String> {
|
||||||
|
MyGenericContext { value: 1, _marker: PhantomData }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test_context(MyGenericContext<String>)]
|
||||||
|
#[test]
|
||||||
|
fn test_generic_type(ctx: &mut MyGenericContext<String>) {
|
||||||
|
assert_eq!(ctx.value, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestContext for MyGenericContext<u32> {
|
||||||
|
fn setup() -> MyGenericContext<u32> {
|
||||||
|
MyGenericContext { value: 2, _marker: PhantomData }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test_context(MyGenericContext<u32>)]
|
||||||
|
#[test]
|
||||||
|
fn test_generic_type_u32(ctx: &mut MyGenericContext<u32>) {
|
||||||
|
assert_eq!(ctx.value, 2);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
Alternatively, you can use `async` functions in your test context by using the
|
Alternatively, you can use `async` functions in your test context by using the
|
||||||
`AsyncTestContext`.
|
`AsyncTestContext`.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
use syn::{parse::Parse, Ident, Token};
|
use syn::{parse::Parse, Token, Type};
|
||||||
|
|
||||||
pub(crate) struct TestContextArgs {
|
pub(crate) struct TestContextArgs {
|
||||||
pub(crate) context_type: Ident,
|
pub(crate) context_type: Type,
|
||||||
pub(crate) skip_teardown: bool,
|
pub(crate) skip_teardown: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse for TestContextArgs {
|
impl Parse for TestContextArgs {
|
||||||
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
|
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
|
||||||
let mut skip_teardown = false;
|
let mut skip_teardown = false;
|
||||||
let mut context_type: Option<Ident> = None;
|
let mut context_type: Option<Type> = None;
|
||||||
|
|
||||||
while !input.is_empty() {
|
while !input.is_empty() {
|
||||||
let lookahead = input.lookahead1();
|
let lookahead = input.lookahead1();
|
||||||
|
|
@ -18,10 +18,8 @@ impl Parse for TestContextArgs {
|
||||||
}
|
}
|
||||||
let _ = input.parse::<kw::skip_teardown>()?;
|
let _ = input.parse::<kw::skip_teardown>()?;
|
||||||
skip_teardown = true;
|
skip_teardown = true;
|
||||||
} else if lookahead.peek(Ident) {
|
} else if context_type.is_none() {
|
||||||
if context_type.is_some() {
|
// Parse any valid Rust type, including generic types
|
||||||
return Err(input.error("expected only a single type identifier"));
|
|
||||||
}
|
|
||||||
context_type = Some(input.parse()?);
|
context_type = Some(input.parse()?);
|
||||||
} else if lookahead.peek(Token![,]) {
|
} else if lookahead.peek(Token![,]) {
|
||||||
let _ = input.parse::<Token![,]>()?;
|
let _ = input.parse::<Token![,]>()?;
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
use test_context::{test_context, AsyncTestContext, TestContext};
|
use test_context::{test_context, AsyncTestContext, TestContext};
|
||||||
|
|
||||||
struct Context {
|
struct Context {
|
||||||
|
|
@ -47,6 +49,43 @@ fn includes_return_value() {
|
||||||
assert_eq!(return_value_func(), 1);
|
assert_eq!(return_value_func(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ContextGeneric<T> {
|
||||||
|
n: u32,
|
||||||
|
_marker: PhantomData<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ContextGenericType1;
|
||||||
|
impl TestContext for ContextGeneric<ContextGenericType1> {
|
||||||
|
fn setup() -> Self {
|
||||||
|
Self {
|
||||||
|
n: 1,
|
||||||
|
_marker: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test_context(ContextGeneric<ContextGenericType1>)]
|
||||||
|
#[test]
|
||||||
|
fn test_generic_type(ctx: &mut ContextGeneric<ContextGenericType1>) {
|
||||||
|
assert_eq!(ctx.n, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ContextGenericType2;
|
||||||
|
impl TestContext for ContextGeneric<ContextGenericType2> {
|
||||||
|
fn setup() -> Self {
|
||||||
|
Self {
|
||||||
|
n: 2,
|
||||||
|
_marker: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test_context(ContextGeneric<ContextGenericType2>)]
|
||||||
|
#[test]
|
||||||
|
fn test_generic_type_other(ctx: &mut ContextGeneric<ContextGenericType2>) {
|
||||||
|
assert_eq!(ctx.n, 2);
|
||||||
|
}
|
||||||
|
|
||||||
struct AsyncContext {
|
struct AsyncContext {
|
||||||
n: u32,
|
n: u32,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue