From 5961811baa4cfe2e0878faed37d660f2d23cbb04 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sat, 17 Aug 2019 17:36:11 -0600 Subject: [PATCH] Better panic messages for failed call counts The panic messages for a failed call counts panic will now include the name of the method. Fixes #31 --- CHANGELOG.md | 4 +++ mockall/src/lib.rs | 28 +++++++++++-------- mockall/tests/mock_reference_arguments.rs | 12 +++++--- mockall/tests/mock_return_reference.rs | 3 +- mockall/tests/mock_struct.rs | 24 ++++++++++------ .../tests/mock_struct_with_static_method.rs | 3 +- mockall_derive/src/automock.rs | 3 +- mockall_derive/src/expectation.rs | 21 +++++++++++--- mockall_derive/src/mock.rs | 2 +- 9 files changed, 68 insertions(+), 32 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2fd6e953..128eda43 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] - ReleaseDate ### Added ### Changed + +- Better panic messages when an expectation fails its expected call count. + ([#33](https://github.com/asomers/mockall/pull/33)) + ### Fixed - Methods returning non-`'static` references (mutable or otherwise) will now diff --git a/mockall/src/lib.rs b/mockall/src/lib.rs index 18060b51..e1447aea 100644 --- a/mockall/src/lib.rs +++ b/mockall/src/lib.rs @@ -1272,6 +1272,7 @@ impl From> for TimesRange { pub struct Times{ /// How many times has the expectation already been called? count: AtomicUsize, + name: String, range: TimesRange } @@ -1280,10 +1281,12 @@ impl Times { let count = self.count.fetch_add(1, Ordering::Relaxed) + 1; if count >= self.range.0.end { if self.range.0.end == 1 { - panic!("Expectation should not have been called"); + panic!("{}: Expectation should not have been called", + self.name); } else { let lim = self.range.0.end - 1; - panic!("Expectation called more than {} times", lim); + panic!("{}: Expectation called more than {} times", self.name, + lim); } } } @@ -1320,6 +1323,15 @@ impl Times { self.range.0 = 0..1; } + pub fn new>(name: S) -> Times { + // By default, allow any number of calls + Times { + count: AtomicUsize::default(), + name: name.into(), + range: TimesRange::default(), + } + } + pub fn range(&mut self, range: Range) { assert!(range.end > range.start, "Backwards range"); self.range.0 = range; @@ -1330,20 +1342,12 @@ impl Times { } } -impl Default for Times { - fn default() -> Self { - // By default, allow any number of calls - let count = AtomicUsize::default(); - let range = TimesRange::default(); - Times{count, range} - } -} - impl Drop for Times { fn drop(&mut self) { let count = self.count.load(Ordering::Relaxed); if !thread::panicking() && (count < self.range.0.start) { - panic!("Expectation called fewer than {} times", + panic!("{}: Expectation called fewer than {} times", + self.name, self.range.0.start); } } diff --git a/mockall/tests/mock_reference_arguments.rs b/mockall/tests/mock_reference_arguments.rs index ce8c2b27..25841af7 100644 --- a/mockall/tests/mock_reference_arguments.rs +++ b/mockall/tests/mock_reference_arguments.rs @@ -61,7 +61,8 @@ mod times { } #[test] - #[should_panic(expected = "Expectation called fewer than 2 times")] + #[should_panic(expected = + "MockFoo::foo: Expectation called fewer than 2 times")] fn too_few() { let mut mock = MockFoo::new(); mock.expect_foo() @@ -71,7 +72,8 @@ mod times { } #[test] - #[should_panic(expected = "Expectation called more than 2 times")] + #[should_panic(expected = + "MockFoo::foo: Expectation called more than 2 times")] fn too_many() { let mut mock = MockFoo::new(); mock.expect_foo() @@ -95,7 +97,8 @@ mod times { } #[test] - #[should_panic(expected = "Expectation called fewer than 2 times")] + #[should_panic(expected = + "MockFoo::foo: Expectation called fewer than 2 times")] fn range_too_few() { let mut mock = MockFoo::new(); mock.expect_foo() @@ -105,7 +108,8 @@ mod times { } #[test] - #[should_panic(expected = "Expectation called more than 3 times")] + #[should_panic(expected = + "MockFoo::foo: Expectation called more than 3 times")] fn range_too_many() { let mut mock = MockFoo::new(); mock.expect_foo() diff --git a/mockall/tests/mock_return_reference.rs b/mockall/tests/mock_return_reference.rs index c7ca69f7..47e22996 100644 --- a/mockall/tests/mock_return_reference.rs +++ b/mockall/tests/mock_return_reference.rs @@ -14,7 +14,8 @@ mod never { use super::*; #[test] - #[should_panic(expected = "Expectation should not have been called")] + #[should_panic(expected = + "MockFoo::bar: Expectation should not have been called")] fn fail() { let mut mock = MockFoo::new(); mock.expect_bar() diff --git a/mockall/tests/mock_struct.rs b/mockall/tests/mock_struct.rs index 37924e59..e3b22c45 100644 --- a/mockall/tests/mock_struct.rs +++ b/mockall/tests/mock_struct.rs @@ -40,7 +40,8 @@ mod checkpoint { } #[test] - #[should_panic(expected = "Expectation called fewer than 1 times")] + #[should_panic(expected = + "MockFoo::foo: Expectation called fewer than 1 times")] fn not_yet_satisfied() { let mut mock = MockFoo::new(); mock.expect_foo() @@ -159,7 +160,8 @@ mod never { use super::*; #[test] - #[should_panic(expected = "Expectation should not have been called")] + #[should_panic(expected = + "MockFoo::bar: Expectation should not have been called")] fn fail() { let mut mock = MockFoo::new(); mock.expect_bar() @@ -294,7 +296,8 @@ mod times { } #[test] - #[should_panic(expected = "Expectation called fewer than 2 times")] + #[should_panic(expected = + "MockFoo::baz: Expectation called fewer than 2 times")] fn too_few() { let mut mock = MockFoo::new(); mock.expect_baz() @@ -304,7 +307,8 @@ mod times { } #[test] - #[should_panic(expected = "Expectation called more than 2 times")] + #[should_panic(expected = + "MockFoo::baz: Expectation called more than 2 times")] fn too_many() { let mut mock = MockFoo::new(); mock.expect_baz() @@ -335,7 +339,8 @@ mod times { } #[test] - #[should_panic(expected = "Expectation called fewer than 2 times")] + #[should_panic(expected = + "MockFoo::baz: Expectation called fewer than 2 times")] fn range_too_few() { let mut mock = MockFoo::new(); mock.expect_baz() @@ -345,7 +350,8 @@ mod times { } #[test] - #[should_panic(expected = "Expectation called more than 3 times")] + #[should_panic(expected = + "MockFoo::baz: Expectation called more than 3 times")] fn range_too_many() { let mut mock = MockFoo::new(); mock.expect_baz() @@ -371,7 +377,8 @@ mod times { } #[test] - #[should_panic(expected = "Expectation called more than 3 times")] + #[should_panic(expected = + "MockFoo::baz: Expectation called more than 3 times")] fn rangeto_too_many() { let mut mock = MockFoo::new(); mock.expect_baz() @@ -413,7 +420,8 @@ mod times { } #[test] - #[should_panic(expected = "Expectation called fewer than 2 times")] + #[should_panic(expected = + "MockFoo::baz: Expectation called fewer than 2 times")] fn rangefrom_too_few() { let mut mock = MockFoo::new(); mock.expect_baz() diff --git a/mockall/tests/mock_struct_with_static_method.rs b/mockall/tests/mock_struct_with_static_method.rs index e60abb89..d112cd51 100644 --- a/mockall/tests/mock_struct_with_static_method.rs +++ b/mockall/tests/mock_struct_with_static_method.rs @@ -10,7 +10,8 @@ mock!{ } #[test] -#[should_panic(expected = "Expectation called fewer than 1 times")] +#[should_panic(expected = + "MockFoo::bar: Expectation called fewer than 1 times")] fn checkpoint() { let mut mock = MockFoo::new(); MockFoo::expect_bar() diff --git a/mockall_derive/src/automock.rs b/mockall_derive/src/automock.rs index fc9d725d..417a92af 100644 --- a/mockall_derive/src/automock.rs +++ b/mockall_derive/src/automock.rs @@ -426,7 +426,8 @@ fn mock_function(vis: &Visibility, Span::call_site()); let mut out = TokenStream::new(); Expectation::new(&TokenStream::new(), &inputs, None, generics, - &mod_ident, None, &decl.output, &expect_vis).to_tokens(&mut out); + &ident, &mod_ident, None, &decl.output, &expect_vis) + .to_tokens(&mut out); quote!( ::mockall::lazy_static! { static ref #obj: ::std::sync::Mutex<#expect_obj> = diff --git a/mockall_derive/src/expectation.rs b/mockall_derive/src/expectation.rs index 149702bb..832fc4e4 100644 --- a/mockall_derive/src/expectation.rs +++ b/mockall_derive/src/expectation.rs @@ -51,10 +51,14 @@ struct Common<'a> { /// Types used for Predicates. Will be almost the same as args, but every /// type will be a non-reference type. predty: Vec, - /// name of the expectation's private module + /// name of the original method meth_ident: &'a Ident, + /// name of the expectation's private module + mod_ident: &'a Ident, /// Output type of the Method, supersuperfied. output: Type, + /// Identifier of the parent structure, if any + parent_ident: Option<&'a Ident>, /// Visibility of the expectation /// TODO: supersuperfy it here rather than in the caller vis: Visibility @@ -280,7 +284,12 @@ impl<'a> Expectation<'a> { pub(crate) fn gen(&self) -> TokenStream { let argnames = &self.common().argnames; let attrs = &self.common().attrs; - let ident = &self.common().meth_ident; + let ident = &self.common().mod_ident; + let ident_str = if let Some(pi) = self.common().parent_ident { + format!("{}::{}", pi, self.common().meth_ident) + } else { + format!("{}", self.common().meth_ident) + }; let extra_uses = self.extra_uses(); let fn_params = &self.common().fn_params; let predty = &self.common().predty; @@ -385,7 +394,7 @@ impl<'a> Expectation<'a> { Common { matcher: Mutex::new(Matcher::default()), seq_handle: None, - times: ::mockall::Times::default() + times: ::mockall::Times::new(#ident_str) } } } @@ -496,6 +505,7 @@ impl<'a> Expectation<'a> { /// slightly different than on the original method. /// * `struct_generics` - Generics of the parent struct, if any. /// * `meth_generics` - Generics of the method being mocked + /// * `mod_ident` - Name of the expectaton's private module /// * `meth_ident` - Name of the original method /// * `parent_ident` - Name of the parent struct, if any. /// * `return_type` - Return type of the mock method @@ -506,7 +516,8 @@ impl<'a> Expectation<'a> { struct_generics: Option<&'a Generics>, meth_generics: &'a Generics, meth_ident: &'a Ident, - parent_ident: Option<&Ident>, + mod_ident: &'a Ident, + parent_ident: Option<&'a Ident>, return_type: &ReturnType, vis: &Visibility) -> Self { @@ -592,7 +603,9 @@ impl<'a> Expectation<'a> { predexprs, predty, meth_ident, + mod_ident, output, + parent_ident, vis: vis.clone() }; if ref_mut_expectation { diff --git a/mockall_derive/src/mock.rs b/mockall_derive/src/mock.rs index a8a6c408..1bf64462 100644 --- a/mockall_derive/src/mock.rs +++ b/mockall_derive/src/mock.rs @@ -394,7 +394,7 @@ fn gen_struct(mock_ident: &syn::Ident, Expectation::new(&attrs, &meth_types.expectation_inputs, Some(&generics), &meth_types.expectation_generics, - meth_ident, Some(&mock_ident), output, + meth_ident, meth_ident, Some(&mock_ident), output, &expect_vis).to_tokens(&mut mod_body); if meth_types.is_static {