[FIX-CONFLICT-WITH-RSTEST-V2]: stable version, fix bugs with AssertUnwindSafe in sync_wrapper_body, remove redundant code, fix two tests, add notes for this tests

This commit is contained in:
Vyacheslav Volkov 2025-10-02 13:50:28 +03:00
parent 71c8cb64c3
commit 02bbbb7244
2 changed files with 168 additions and 167 deletions

View file

@ -32,7 +32,6 @@ pub fn test_context(attr: TokenStream, item: TokenStream) -> TokenStream {
let input = syn::parse_macro_input!(item as syn::ItemFn);
let is_async = input.sig.asyncness.is_some();
// Находим и удаляем аргумент контекста из сигнатуры
let (new_input, context_arg_name) = extract_and_remove_context_arg(input.clone());
let wrapper_body = if is_async {
@ -95,17 +94,18 @@ fn sync_wrapper_body(
let body = if args.skip_teardown {
quote! {
let #context_name = <#context_type as test_context::TestContext>::setup();
let #result_name = std::panic::catch_unwind(|| {
let mut #context_name = <#context_type as test_context::TestContext>::setup();
let #result_name = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
let #context_name = &mut #context_name;
#body
});
}));
}
} else {
quote! {
let mut #context_name = <#context_type as test_context::TestContext>::setup();
let #result_name = std::panic::catch_unwind(|| {
let #result_name = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
#body
});
}));
<#context_type as test_context::TestContext>::teardown(#context_name);
}
};
@ -138,10 +138,9 @@ fn extract_and_remove_context_arg(mut input: syn::ItemFn) -> (syn::ItemFn, Optio
for arg in &input.sig.inputs {
if let syn::FnArg::Typed(pat_type) = arg {
if let syn::Pat::Ident(pat_ident) = &*pat_type.pat {
if let syn::Type::Reference(type_ref) = &*pat_type.ty {
// Сохраняем имя аргумента контекста
if let syn::Type::Reference(_) = &*pat_type.ty {
context_arg_name = Some(pat_ident.ident.clone());
continue; // Пропускаем этот аргумент
continue;
}
}
}

View file

@ -25,194 +25,196 @@ fn test_sync_setup(ctx: &mut Context) {
assert_eq!(ctx.n, 1);
}
// #[test_context(Context)]
// #[test]
// #[should_panic(expected = "Number changed")]
// fn test_sync_teardown(ctx: &mut Context) {
// ctx.n = 2;
// }
#[test_context(Context)]
#[test]
#[should_panic(expected = "Number changed")]
fn test_sync_teardown(ctx: &mut Context) {
ctx.n = 2;
}
// #[test_context(Context)]
// #[test]
// #[should_panic(expected = "Number changed")]
// fn test_panicking_teardown(ctx: &mut Context) {
// ctx.n = 2;
// panic!("First panic");
// }
#[test_context(Context)]
#[test]
#[should_panic(expected = "Number changed")]
fn test_panicking_teardown(ctx: &mut Context) {
ctx.n = 2;
panic!("First panic");
}
// #[test_context(Context)]
// fn return_value_func(ctx: &mut Context) -> u32 {
// ctx.n
// }
#[test_context(Context)]
fn return_value_func(ctx: &mut Context) -> u32 {
ctx.n
}
// #[test]
// fn includes_return_value() {
// assert_eq!(return_value_func(), 1);
// }
#[test]
fn includes_return_value() {
assert_eq!(return_value_func(), 1);
}
// struct ContextGeneric<T> {
// n: u32,
// _marker: PhantomData<T>,
// }
struct ContextGeneric<T> {
n: u32,
_marker: PhantomData<T>,
}
// struct ContextGenericType1;
// impl TestContext for ContextGeneric<ContextGenericType1> {
// fn setup() -> Self {
// Self {
// n: 1,
// _marker: PhantomData,
// }
// }
// }
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);
// }
#[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,
// }
// }
// }
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);
// }
#[test_context(ContextGeneric<ContextGenericType2>)]
#[test]
fn test_generic_type_other(ctx: &mut ContextGeneric<ContextGenericType2>) {
assert_eq!(ctx.n, 2);
}
// struct AsyncContext {
// n: u32,
// }
struct AsyncContext {
n: u32,
}
// impl AsyncTestContext for AsyncContext {
// async fn setup() -> Self {
// Self { n: 1 }
// }
impl AsyncTestContext for AsyncContext {
async fn setup() -> Self {
Self { n: 1 }
}
// async fn teardown(self) {
// if self.n != 1 {
// panic!("Number changed");
// }
// }
// }
async fn teardown(self) {
if self.n != 1 {
panic!("Number changed");
}
}
}
// #[test_context(AsyncContext)]
// #[tokio::test]
// async fn test_async_setup(ctx: &mut AsyncContext) {
// assert_eq!(ctx.n, 1);
// }
#[test_context(AsyncContext)]
#[tokio::test]
async fn test_async_setup(ctx: &mut AsyncContext) {
assert_eq!(ctx.n, 1);
}
// #[test_context(AsyncContext)]
// #[tokio::test]
// #[should_panic(expected = "Number changed")]
// async fn test_async_teardown(ctx: &mut AsyncContext) {
// ctx.n = 2;
// }
#[test_context(AsyncContext)]
#[tokio::test]
#[should_panic(expected = "Number changed")]
async fn test_async_teardown(ctx: &mut AsyncContext) {
ctx.n = 2;
}
// #[test_context(AsyncContext)]
// #[tokio::test]
// #[should_panic(expected = "Number changed")]
// async fn test_async_panicking_teardown(ctx: &mut AsyncContext) {
// ctx.n = 2;
// panic!("First panic");
// }
#[test_context(AsyncContext)]
#[tokio::test]
#[should_panic(expected = "Number changed")]
async fn test_async_panicking_teardown(ctx: &mut AsyncContext) {
ctx.n = 2;
panic!("First panic");
}
// #[test_context(AsyncContext)]
// async fn async_return_value_func(ctx: &mut AsyncContext) -> u32 {
// ctx.n
// }
#[test_context(AsyncContext)]
async fn async_return_value_func(ctx: &mut AsyncContext) -> u32 {
ctx.n
}
// #[tokio::test]
// async fn async_includes_return_value() {
// assert_eq!(async_return_value_func().await, 1);
// }
#[tokio::test]
async fn async_includes_return_value() {
assert_eq!(async_return_value_func().await, 1);
}
// #[test_context(AsyncContext)]
// #[test]
// fn async_auto_impls_sync(ctx: &mut AsyncContext) {
// assert_eq!(ctx.n, 1);
// }
#[test_context(AsyncContext)]
#[test]
fn async_auto_impls_sync(ctx: &mut AsyncContext) {
assert_eq!(ctx.n, 1);
}
// #[test_context(Context)]
// #[test]
// fn use_different_name(test_data: &mut Context) {
// assert_eq!(test_data.n, 1);
// }
#[test_context(Context)]
#[test]
fn use_different_name(test_data: &mut Context) {
assert_eq!(test_data.n, 1);
}
// #[test_context(AsyncContext)]
// #[tokio::test]
// async fn use_different_name_async(test_data: &mut AsyncContext) {
// assert_eq!(test_data.n, 1);
// }
#[test_context(AsyncContext)]
#[tokio::test]
async fn use_different_name_async(test_data: &mut AsyncContext) {
assert_eq!(test_data.n, 1);
}
// struct TeardownPanicContext {}
struct TeardownPanicContext {}
// impl AsyncTestContext for TeardownPanicContext {
// async fn setup() -> Self {
// Self {}
// }
impl AsyncTestContext for TeardownPanicContext {
async fn setup() -> Self {
Self {}
}
// async fn teardown(self) {
// panic!("boom!");
// }
// }
async fn teardown(self) {
panic!("boom!");
}
}
// // #[test_context(TeardownPanicContext, skip_teardown)]
// // #[tokio::test]
// // async fn test_async_skip_teardown(mut _ctx: TeardownPanicContext) {}
// NOTE: redo next with transfer argument by mutable reference only, not by ownership like it was before !!!
#[test_context(TeardownPanicContext, skip_teardown)]
#[tokio::test]
async fn test_async_skip_teardown(_ctx: &mut TeardownPanicContext) {}
// // #[test_context(TeardownPanicContext, skip_teardown)]
// // #[test]
// // fn test_sync_skip_teardown(mut _ctx: TeardownPanicContext) {}
// NOTE: redo next with transfer argument by mutable reference only, not by ownership like it was before !!!
#[test_context(TeardownPanicContext, skip_teardown)]
#[test]
fn test_sync_skip_teardown(_ctx: &mut TeardownPanicContext) {}
// struct GenericContext<T> {
// contents: T,
// }
struct GenericContext<T> {
contents: T,
}
// impl TestContext for GenericContext<u32> {
// fn setup() -> Self {
// Self { contents: 1 }
// }
// }
impl TestContext for GenericContext<u32> {
fn setup() -> Self {
Self { contents: 1 }
}
}
// impl TestContext for GenericContext<String> {
// fn setup() -> Self {
// Self {
// contents: "hello world".to_string(),
// }
// }
// }
impl TestContext for GenericContext<String> {
fn setup() -> Self {
Self {
contents: "hello world".to_string(),
}
}
}
// impl AsyncTestContext for GenericContext<u64> {
// async fn setup() -> Self {
// Self { contents: 1 }
// }
// }
impl AsyncTestContext for GenericContext<u64> {
async fn setup() -> Self {
Self { contents: 1 }
}
}
// #[test_context(GenericContext<u32>)]
// #[test]
// fn test_generic_with_u32(ctx: &mut GenericContext<u32>) {
// assert_eq!(ctx.contents, 1);
// }
#[test_context(GenericContext<u32>)]
#[test]
fn test_generic_with_u32(ctx: &mut GenericContext<u32>) {
assert_eq!(ctx.contents, 1);
}
// #[test_context(GenericContext<String>)]
// #[test]
// fn test_generic_with_string(ctx: &mut GenericContext<String>) {
// assert_eq!(ctx.contents, "hello world");
// }
#[test_context(GenericContext<String>)]
#[test]
fn test_generic_with_string(ctx: &mut GenericContext<String>) {
assert_eq!(ctx.contents, "hello world");
}
// #[test_context(GenericContext<u64>)]
// #[tokio::test]
// async fn test_async_generic(test_ctx: &mut GenericContext<u64>) {
// assert_eq!(test_ctx.contents, 1);
// }
#[test_context(GenericContext<u64>)]
#[tokio::test]
async fn test_async_generic(test_ctx: &mut GenericContext<u64>) {
assert_eq!(test_ctx.contents, 1);
}
struct MyAsyncContext {
what_the_of_life: u32,
@ -236,7 +238,7 @@ impl AsyncTestContext for MyAsyncContext {
#[rstest]
#[case("Hello, World!")]
#[tokio::test]
async fn test_async_generic_sync(#[case] value: String, test_ctx: &mut MyAsyncContext) {
async fn test_async_generic_with_sync(#[case] value: String, test_ctx: &mut MyAsyncContext) {
println!("Something happens sync... {}", value);
assert_eq!(test_ctx.what_the_of_life, 42);
}