mirror of
https://codeberg.org/JasterV/test-context.git
synced 2026-04-26 18:10:06 +00:00
chore: internal refactor & update docs (#64)
This commit is contained in:
parent
b37885d27c
commit
63cb4631a3
6 changed files with 27 additions and 144 deletions
1
.github/workflows/ci.yml
vendored
1
.github/workflows/ci.yml
vendored
|
|
@ -56,4 +56,3 @@ jobs:
|
|||
with:
|
||||
command: clippy
|
||||
args: --all-targets -- -D warnings
|
||||
|
||||
|
|
|
|||
25
README.md
25
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)]
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
3
yamlfmt.yml
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
formatter:
|
||||
type: basic
|
||||
retain_line_breaks_single: true
|
||||
Loading…
Reference in a new issue