diff --git a/CHANGELOG.md b/CHANGELOG.md index 99c7cb5c..bcc0e6ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,11 @@ This project adheres to [Semantic Versioning](http://semver.org/). functions that use `#[link_name]`. ([#503](https://github.com/asomers/mockall/pull/503)) +- Fix a panic during Drop for static methods. One way to trigger it is by + calling the method more times than is allowed by a `.times()` constraint. + Another way would be to explicitly panic during the `.returning` method. + ([#516](https://github.com/asomers/mockall/pull/516)) + ### Removed - Removed syntax deprecated since 0.9.0: using `#[automock]` directly on an diff --git a/mockall/tests/clear_expectations_on_panic.rs b/mockall/tests/clear_expectations_on_panic.rs index 1f088b48..44a8d3f4 100644 --- a/mockall/tests/clear_expectations_on_panic.rs +++ b/mockall/tests/clear_expectations_on_panic.rs @@ -11,16 +11,16 @@ use mockall::*; #[automock] pub trait Foo { fn foo() -> i32; + fn bar() -> i32; } #[test] -fn drop_expectations_on_panic() { +fn too_few_calls() { panic::catch_unwind(|| { let ctx = MockFoo::foo_context(); ctx.expect() .times(1) .return_const(42); - panic!("Panicking!"); }).unwrap_err(); // The previously set expectation should've been cleared during the panic, @@ -31,3 +31,20 @@ fn drop_expectations_on_panic() { .return_const(42); assert_eq!(42, MockFoo::foo()); } + +// We shouldn't panic during drop in this case. Regression test for +// https://github.com/asomers/mockall/issues/491 +#[should_panic(expected = "called `Result::unwrap()` on an `Err` value: PoisonError { .. }")] +#[test] +fn too_many_calls() { + panic::catch_unwind(|| { + let ctx = MockFoo::bar_context(); + ctx.expect() + .times(0); + MockFoo::bar(); + }).unwrap_err(); + + // This line will panic with a PoisonError, at least until issue #515 is + // complete. + let _ctx = MockFoo::bar_context(); +} diff --git a/mockall_derive/src/mock_function.rs b/mockall_derive/src/mock_function.rs index cb991339..433d5891 100644 --- a/mockall_derive/src/mock_function.rs +++ b/mockall_derive/src/mock_function.rs @@ -1593,7 +1593,17 @@ impl<'a> ToTokens for Context<'a> { } impl #ty_ig Drop for Context #ty_tg #ty_wc { fn drop(&mut self) { - Self::do_checkpoint() + if ::std::thread::panicking() { + // Drain all expectations so other tests can run with a + // blank slate. But ignore errors so we don't + // double-panic. + let _ = EXPECTATIONS + .lock() + .map(|mut g| g.checkpoint().collect::>()); + } else { + // Verify expectations are satisfied + Self::do_checkpoint(); + } } } ).to_tokens(tokens);