Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ jobs:
run: |
cargo build --profile=${{ matrix.profile }}
cargo build --all-features --profile=${{ matrix.profile }}
cargo test --profile=${{ matrix.profile }}
cargo test --profile=${{ matrix.profile }} --features rstest
build-minimum:
name: Build using minimum versions of dependencies
runs-on: ubuntu-latest
Expand Down
4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,14 @@ include = ["src/lib.rs", "LICENSE-*", "README.md", "CHANGELOG.md"]
[[test]]
name = "default_log_filter"
path = "tests/default_log_filter.rs"
required-features = ["log", "unstable"]
required-features = ["log", "rstest", "unstable"]

[features]
default = ["log", "color"]
trace = ["dep:tracing-subscriber", "test-log-macros/trace"]
log = ["dep:env_logger", "test-log-macros/log", "tracing-subscriber?/tracing-log"]
color = ["env_logger?/auto-color", "tracing-subscriber?/ansi"]
rstest = ["test-log-macros/rstest"]
# Enable unstable features. These are generally exempt from any semantic
# versioning guarantees.
unstable = ["test-log-macros/unstable"]
Expand All @@ -52,5 +53,6 @@ env_logger = {version = "0.11", default-features = false, optional = true}
[dev-dependencies]
logging = {version = "0.4.8", package = "log"}
test-case = {version = "3.1"}
rstest = {version = "0.25.0"}
tokio = {version = "1.0", default-features = false, features = ["rt-multi-thread", "macros"]}
tracing = {version = "0.1.20"}
35 changes: 35 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ The crate comes with two features pertaining "backend" initialization:
crate.
- `trace`, disabled by default, controls initialization for the
`tracing` crate.
- `rstest`, disabled by default, allows usage of this library with
[rstest](https://github.com/la10736/rstest)

Depending on what backend the crate-under-test (and its dependencies)
use, the respective feature(s) should be enabled to make messages that
Expand All @@ -92,6 +94,39 @@ are emitted by the test manifest on the terminal.
On top of that, the `color` feature (enabled by default) controls
whether to color output by default.

#### Usage with rstest

The same syntax is supported for rstest as with regular tests, just
with swapping out `rstest` for `test`:
```rust
use test_log::rstest;

#[rstest]
fn it_works() {
info!("Checking whether it still works...");
assert_eq!(2 + 2, 4);
info!("Looks good!");
}
```

You can use `#[case]` statements as normal:
```rust
#[rstest]
#[case(4)]
fn it_works(#[case] val: i64) {
// ...
}
```

As well as wrapping other attributes, such as `tokio::test`:
```rust
#[rstest(tokio::test)]
#[case(4)]
async fn it_works(#[case] val: i64) {
// ...
}
```

#### Logging Configuration

As usual when running `cargo test`, the output is captured by the
Expand Down
1 change: 1 addition & 0 deletions macros/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ proc-macro = true
[features]
trace = []
log = []
rstest = []
unstable = []

[dependencies]
Expand Down
51 changes: 42 additions & 9 deletions macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,45 @@ use syn::Meta;
#[proc_macro_attribute]
pub fn test(attr: TokenStream, item: TokenStream) -> TokenStream {
let item = parse_macro_input!(item as ItemFn);
try_test(attr, item)
let pre = if attr.is_empty() {
quote! { #[::core::prelude::v1::test] }
} else {
let attr_tokens: Tokens = attr.into();
quote! { #[ #attr_tokens ] }
};
try_test(pre, quote! {}, item)
.unwrap_or_else(syn::Error::into_compile_error)
.into()
}

#[cfg(feature = "rstest")]
#[proc_macro_attribute]
pub fn rstest(attr: TokenStream, item: TokenStream) -> TokenStream {
// the "full" rstest syntax looks like
//
// #[rstest]
// #[case(...)]
// #[case(...)]
// #[tokio::test]
// async fn test_blah(#[case] ...)
//
// We want to support a similar usage for test_log, so with this library the syntax looks like
//
// #[rstest(tokio::test)]
// #[case(...)]
// #[case(...)]
// async fn test_blah(#[case] ...)
//
// This means we need to set "pre" and "post" fields after the "ignored" attrs below
let item = parse_macro_input!(item as ItemFn);
let pre = quote! { #[::rstest::rstest] };
let post = if attr.is_empty() {
quote! {}
} else {
let attr_tokens: Tokens = attr.into();
quote! { #[ #attr_tokens ] }
};
try_test(pre, post, item)
.unwrap_or_else(syn::Error::into_compile_error)
.into()
}
Expand All @@ -45,13 +83,7 @@ fn parse_attrs(attrs: Vec<Attribute>) -> syn::Result<(AttributeArgs, Vec<Attribu
}
}

fn try_test(attr: TokenStream, input: ItemFn) -> syn::Result<Tokens> {
let inner_test = if attr.is_empty() {
quote! { ::core::prelude::v1::test }
} else {
attr.into()
};

fn try_test(pre: Tokens, post: Tokens, input: ItemFn) -> syn::Result<Tokens> {
let ItemFn {
attrs,
vis,
Expand All @@ -64,8 +96,9 @@ fn try_test(attr: TokenStream, input: ItemFn) -> syn::Result<Tokens> {
let tracing_init = expand_tracing_init(&attribute_args);

let result = quote! {
#[#inner_test]
#pre
#(#ignored_attrs)*
#post
#vis #sig {
// We put all initialization code into a separate module here in
// order to prevent potential ambiguities that could result in
Expand Down
3 changes: 3 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@
/// ```
pub use test_log_macros::test;

#[cfg(feature = "rstest")]
pub use test_log_macros::rstest;

#[cfg(feature = "trace")]
#[doc(hidden)]
pub use tracing_subscriber;
Expand Down
28 changes: 28 additions & 0 deletions tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,34 @@ async fn trace_with_tokio_attribute() {
debug!("done");
}

#[cfg(feature = "rstest")]
#[test_log::rstest]
fn rstest() {
assert_eq!(2 + 2, 4);
}

#[cfg(feature = "rstest")]
#[test_log::rstest(tokio::test)]
async fn rstest_async() {
assert_eq!(async { 42 }.await, 42)
}

#[cfg(feature = "rstest")]
#[test_log::rstest]
#[case(1)]
#[case(2)]
fn rstest_with_cases(#[case] val: i64) {
assert_eq!(val, val);
}

#[cfg(feature = "rstest")]
#[test_log::rstest(tokio::test)]
#[case(1)]
#[case(2)]
async fn rstest_with_cases_async(#[case] val: i64) {
assert_eq!(async { val }.await, val);
}

#[cfg(feature = "unstable")]
#[test_log::test(tokio::test)]
#[test_log(default_log_filter = "info")]
Expand Down