chore: internal refactor & update docs (#64)

This commit is contained in:
Víctor Martínez 2025-11-10 11:04:42 +01:00 committed by GitHub
parent b37885d27c
commit 63cb4631a3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 27 additions and 144 deletions

View file

@ -56,4 +56,3 @@ jobs:
with:
command: clippy
args: --all-targets -- -D warnings

View file

@ -7,7 +7,7 @@
A library for providing custom setup/teardown for Rust tests without needing a test harness.
```rust
```rust ignore
use test_context::{test_context, TestContext};
struct MyContext {
@ -77,7 +77,7 @@ The `AsyncTestContext` works well with async test wrappers like
[`actix_rt::test`](https://docs.rs/actix-rt/1.1.1/actix_rt/attr.test.html) or
[`tokio::test`](https://docs.rs/tokio/1.0.2/tokio/attr.test.html).
```rust
```rust ignore
#[test_context(MyAsyncContext)]
#[tokio::test]
async fn test_works(ctx: &mut MyAsyncContext) {
@ -95,7 +95,7 @@ that runs setup/teardown.
Valid:
```rust
```rust ignore
#[test_context(MyAsyncContext)]
#[tokio::test]
async fn my_test(ctx: &mut MyAsyncContext) {}
@ -103,7 +103,7 @@ async fn my_test(ctx: &mut MyAsyncContext) {}
Invalid:
```rust
```rust ignore
#[tokio::test]
#[test_context(MyAsyncContext)]
async fn my_test(ctx: &mut MyAsyncContext) {}
@ -130,7 +130,7 @@ tests annotated with `#[tokio::test]` continue to work as usual without the feat
Also, if you don't care about the teardown execution for a specific test,
you can use the `skip_teardown` keyword on the macro like this:
```rust
```rust ignore
use test_context::{test_context, TestContext};
struct MyContext {}
@ -150,7 +150,7 @@ fn test_without_teardown(ctx: &MyContext) {}
If the teardown is ON (default behavior), you can only take a reference to the context, either mutable or immutable, as follows:
```rust
```rust ignore
#[test_context(MyContext)]
#[test]
fn test_with_teardown_using_immutable_ref(ctx: &MyContext) {}
@ -162,7 +162,7 @@ fn test_with_teardown_using_mutable_ref(ctx: &mut MyContext) {}
❌The following is invalid:
```rust
```rust ignore
#[test_context(MyContext)]
#[test]
fn test_with_teardown_taking_ownership(ctx: MyContext) {}
@ -170,7 +170,7 @@ fn test_with_teardown_taking_ownership(ctx: MyContext) {}
If the teardown is skipped (as specified in the section above), you can take an immutable ref, mutable ref or full ownership of the context:
```rust
```rust ignore
#[test_context(MyContext, skip_teardown)]
#[test]
fn test_without_teardown(ctx: MyContext) {
@ -186,14 +186,13 @@ fn test_without_teardown_taking_a_ref(ctx: &MyContext) {}
fn test_without_teardown_taking_a_mut_ref(ctx: &mut MyContext) {}
```
## ⚠️ Ensure that the context type specified in the macro matches the test function argument type exactly
The error occurs when a context type with an absolute path is mixed with an it's alias.
For example:
```
```rust ignore
mod database {
use test_context::TestContext;
@ -207,7 +206,8 @@ mod database {
```
✅The following code will work:
```
```rust ignore
use database::Connection as DbConn;
#[test_context(DbConn)]
@ -228,7 +228,8 @@ fn test1(ctx: &mut database::Connection) {
```
❌The following code will not work:
```
```rust ignore
use database::Connection as DbConn;
#[test_context(database::Connection)]

View file

@ -2,7 +2,7 @@ mod macro_args;
mod test_args;
use crate::test_args::{ContextArg, ContextArgMode, TestArg};
use macro_args::TestContextArgs;
use macro_args::MacroArgs;
use proc_macro::TokenStream;
use quote::{format_ident, quote};
use syn::ItemFn;
@ -29,7 +29,7 @@ use syn::ItemFn;
/// ```
#[proc_macro_attribute]
pub fn test_context(attr: TokenStream, item: TokenStream) -> TokenStream {
let args = syn::parse_macro_input!(attr as TestContextArgs);
let args = syn::parse_macro_input!(attr as MacroArgs);
let input = syn::parse_macro_input!(item as syn::ItemFn);
let (input, context_args) = remove_context_args(input, args.context_type.clone());
@ -86,7 +86,7 @@ fn remove_context_args(
fn refactor_input_body(
input: syn::ItemFn,
args: &TestContextArgs,
args: &MacroArgs,
context_arg: ContextArg,
) -> syn::ItemFn {
let context_type = &args.context_type;

View file

@ -1,11 +1,15 @@
use syn::{Token, Type, parse::Parse};
pub(crate) struct TestContextArgs {
/// Contains the parsed arguments passed to the macro `#[test_context(..)]`
pub(crate) struct MacroArgs {
/// The context type passed in the macro arguments.
/// It must implement `TestContext` or `AsyncTestContext`
pub(crate) context_type: Type,
pub(crate) skip_teardown: bool,
}
impl Parse for TestContextArgs {
impl Parse for MacroArgs {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
let mut skip_teardown = false;
let mut context_type: Option<Type> = None;
@ -28,7 +32,7 @@ impl Parse for TestContextArgs {
}
}
Ok(TestContextArgs {
Ok(MacroArgs {
context_type: context_type
.ok_or(input.error("expected at least one type identifier"))?,
skip_teardown,

View file

@ -1,128 +1,4 @@
//! A library for providing custom setup/teardown for Rust tests without needing a test harness.
//!
//! ```no_run
//! use test_context::{test_context, TestContext};
//!
//! struct MyContext {
//! value: String
//! }
//!
//! impl TestContext for MyContext {
//! fn setup() -> MyContext {
//! MyContext { value: "Hello, world!".to_string() }
//! }
//!
//! fn teardown(self) {
//! // Perform any teardown you wish.
//! }
//! }
//!
//! #[test_context(MyContext)]
//! #[test]
//! fn test_works(ctx: &mut MyContext) {
//! assert_eq!(ctx.value, "Hello, world!");
//! }
//! ```
//!
//! Alternatively, you can use `async` functions in your test context by using the
//! `AsyncTestContext`.
//!
//! ```no_run
//! use test_context::{test_context, AsyncTestContext};
//!
//! struct MyAsyncContext {
//! value: String
//! }
//!
//! impl AsyncTestContext for MyAsyncContext {
//! async fn setup() -> MyAsyncContext {
//! MyAsyncContext { value: "Hello, world!".to_string() }
//! }
//!
//! async fn teardown(self) {
//! // Perform any teardown you wish.
//! }
//! }
//!
//! #[test_context(MyAsyncContext)]
//! #[test]
//! fn test_works(ctx: &mut MyAsyncContext) {
//! assert_eq!(ctx.value, "Hello, World!");
//! }
//! ```
//!
//! The `AsyncTestContext` works well with async test wrappers like
//! [`actix_rt::test`](https://docs.rs/actix-rt/1.1.1/actix_rt/attr.test.html) or
//! [`tokio::test`](https://docs.rs/tokio/1.0.2/tokio/attr.test.html).
//!
//! ```no_run
//! use test_context::{test_context, AsyncTestContext};
//!
//! struct MyAsyncContext {
//! value: String
//! }
//!
//! impl AsyncTestContext for MyAsyncContext {
//! async fn setup() -> MyAsyncContext {
//! MyAsyncContext { value: "Hello, world!".to_string() }
//! }
//! async fn teardown(self) {
//! // Perform any teardown you wish.
//! }
//! }
//!
//! #[test_context(MyAsyncContext)]
//! #[tokio::test]
//! async fn test_async_works(ctx: &mut MyAsyncContext) {
//! assert_eq!(ctx.value, "Hello, World!");
//! }
//! ```
//!
//! # Attribute order
//!
//! Attribute order matters. Always place `#[test_context(...)]` before other test attributes
//! like `#[tokio::test]` or `#[test]`.
//!
//! Why: Rust expands attributes in source order. `#[test_context]` wraps your function and
//! re-attaches the remaining attributes to the wrapper; it must run first so the test attributes
//! apply to the wrapper that performs setup/teardown.
//!
//! Valid:
//! ```ignore
//! #[test_context(MyAsyncContext)]
//! #[tokio::test]
//! async fn my_test(ctx: &mut MyAsyncContext) {}
//! ```
//!
//! Invalid:
//! ```ignore
//! #[tokio::test]
//! #[test_context(MyAsyncContext)]
//! async fn my_test(ctx: &mut MyAsyncContext) {}
//! ```
//!
//! # Skipping the teardown execution
//!
//! Also, if you don't care about the teardown execution for a specific test,
//! you can use the `skip_teardown` keyword on the macro like this:
//!
//! ```no_run
//! use test_context::{test_context, TestContext};
//!
//! struct MyContext {}
//!
//! impl TestContext for MyContext {
//! fn setup() -> MyContext {
//! MyContext {}
//! }
//! }
//!
//! #[test_context(MyContext, skip_teardown)]
//! #[test]
//! fn test_without_teardown(ctx: &mut MyContext) {
//! // Perform any operations that require full ownership of your context
//! }
//! ```
#![doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/../README.md"))]
// Reimported to allow for use in the macro.
pub use futures;

3
yamlfmt.yml Normal file
View file

@ -0,0 +1,3 @@
formatter:
type: basic
retain_line_breaks_single: true