From 63cb4631a35b7447989c3cde289bee3980a7be2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Mart=C3=ADnez?= <49537445+JasterV@users.noreply.github.com> Date: Mon, 10 Nov 2025 11:04:42 +0100 Subject: [PATCH] chore: internal refactor & update docs (#64) --- .github/workflows/ci.yml | 1 - README.md | 25 ++--- test-context-macros/src/lib.rs | 6 +- test-context-macros/src/macro_args.rs | 10 +- test-context/src/lib.rs | 126 +------------------------- yamlfmt.yml | 3 + 6 files changed, 27 insertions(+), 144 deletions(-) create mode 100644 yamlfmt.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 17964e2..bac97f1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -56,4 +56,3 @@ jobs: with: command: clippy args: --all-targets -- -D warnings - diff --git a/README.md b/README.md index 2f6334e..3ad6984 100644 --- a/README.md +++ b/README.md @@ -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)] diff --git a/test-context-macros/src/lib.rs b/test-context-macros/src/lib.rs index 4efac74..8644f36 100644 --- a/test-context-macros/src/lib.rs +++ b/test-context-macros/src/lib.rs @@ -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; diff --git a/test-context-macros/src/macro_args.rs b/test-context-macros/src/macro_args.rs index 013dff2..61e04a1 100644 --- a/test-context-macros/src/macro_args.rs +++ b/test-context-macros/src/macro_args.rs @@ -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 { let mut skip_teardown = false; let mut context_type: Option = 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, diff --git a/test-context/src/lib.rs b/test-context/src/lib.rs index b5f88d8..ac92065 100644 --- a/test-context/src/lib.rs +++ b/test-context/src/lib.rs @@ -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; diff --git a/yamlfmt.yml b/yamlfmt.yml new file mode 100644 index 0000000..0d7c56d --- /dev/null +++ b/yamlfmt.yml @@ -0,0 +1,3 @@ +formatter: + type: basic + retain_line_breaks_single: true