summaryrefslogtreecommitdiff
path: root/src/mock_function.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/mock_function.rs')
-rw-r--r--src/mock_function.rs2436
1 files changed, 2436 insertions, 0 deletions
diff --git a/src/mock_function.rs b/src/mock_function.rs
new file mode 100644
index 0000000..86a8690
--- /dev/null
+++ b/src/mock_function.rs
@@ -0,0 +1,2436 @@
+// vim: tw=80
+use super::*;
+
+use quote::ToTokens;
+
+/// Convert a trait object reference into a reference to a Boxed trait
+///
+/// # Returns
+///
+/// Returns `true` if it was necessary to box the type.
+fn dedynify(ty: &mut Type) -> bool {
+ if let Type::Reference(ref mut tr) = ty {
+ if let Type::TraitObject(ref tto) = tr.elem.as_ref() {
+ if let Some(lt) = &tr.lifetime {
+ if lt.ident == "static" {
+ // For methods that return 'static references, the user can
+ // usually actually supply one, unlike nonstatic references.
+ // dedynify is unneeded and harmful in such cases.
+ //
+ // But we do need to add parens to prevent parsing errors
+ // when methods like returning add a `+ Send` to the output
+ // type.
+ *tr.elem = parse2(quote!((#tto))).unwrap();
+ return false;
+ }
+ }
+
+ *tr.elem = parse2(quote!(Box<#tto>)).unwrap();
+ return true;
+ }
+ }
+ false
+}
+
+/// Convert a special reference type like "&str" into a reference to its owned
+/// type like "&String".
+fn destrify(ty: &mut Type) {
+ if let Type::Reference(ref mut tr) = ty {
+ if let Some(lt) = &tr.lifetime {
+ if lt.ident == "static" {
+ // For methods that return 'static references, the user can
+ // usually actually supply one, unlike nonstatic references.
+ // destrify is unneeded and harmful in such cases.
+ return;
+ }
+ }
+
+ let path_ty: TypePath = parse2(quote!(Path)).unwrap();
+ let pathbuf_ty: Type = parse2(quote!(::std::path::PathBuf)).unwrap();
+
+ let str_ty: TypePath = parse2(quote!(str)).unwrap();
+ let string_ty: Type = parse2(quote!(::std::string::String)).unwrap();
+
+ let cstr_ty: TypePath = parse2(quote!(CStr)).unwrap();
+ let cstring_ty: Type = parse2(quote!(::std::ffi::CString)).unwrap();
+
+ let osstr_ty: TypePath = parse2(quote!(OsStr)).unwrap();
+ let osstring_ty: Type = parse2(quote!(::std::ffi::OsString)).unwrap();
+
+ match tr.elem.as_ref() {
+ Type::Path(ref path) if *path == cstr_ty => *tr.elem = cstring_ty,
+ Type::Path(ref path) if *path == osstr_ty => *tr.elem = osstring_ty,
+ Type::Path(ref path) if *path == path_ty => *tr.elem = pathbuf_ty,
+ Type::Path(ref path) if *path == str_ty => *tr.elem = string_ty,
+ Type::Slice(ts) => {
+ let inner = (*ts.elem).clone();
+ let mut segments = Punctuated::new();
+ segments.push(format_ident!("std").into());
+ segments.push(format_ident!("vec").into());
+ let mut v: PathSegment = format_ident!("Vec").into();
+ let mut abga_args = Punctuated::new();
+ abga_args.push(GenericArgument::Type(inner));
+ v.arguments = PathArguments::AngleBracketed(AngleBracketedGenericArguments {
+ colon2_token: None,
+ lt_token: Token![<](Span::call_site()),
+ args: abga_args,
+ gt_token: Token![>](Span::call_site()),
+ });
+ segments.push(v);
+
+ *tr.elem = Type::Path(TypePath {
+ qself: None,
+ path: Path {
+ leading_colon: Some(Token![::](Span::call_site())),
+ segments,
+ },
+ });
+ }
+ _ => (), // Nothing to do
+ };
+ }
+}
+
+/// Return the owned version of the input.
+fn ownify(ty: &Type) -> Type {
+ if let Type::Reference(ref tr) = &ty {
+ if tr
+ .lifetime
+ .as_ref()
+ .map_or(false, |lt| lt.ident == "static")
+ {
+ // Just a static expectation
+ ty.clone()
+ } else {
+ *tr.elem.clone()
+ }
+ } else {
+ ty.clone()
+ }
+}
+
+/// Add Send + Sync to a where clause
+fn send_syncify(wc: &mut Option<WhereClause>, bounded_ty: Type) {
+ let mut bounds = Punctuated::new();
+ bounds.push(TypeParamBound::Trait(TraitBound {
+ paren_token: None,
+ modifier: TraitBoundModifier::None,
+ lifetimes: None,
+ path: Path::from(format_ident!("Send")),
+ }));
+ bounds.push(TypeParamBound::Trait(TraitBound {
+ paren_token: None,
+ modifier: TraitBoundModifier::None,
+ lifetimes: None,
+ path: Path::from(format_ident!("Sync")),
+ }));
+ if wc.is_none() {
+ *wc = Some(WhereClause {
+ where_token: <Token![where]>::default(),
+ predicates: Punctuated::new(),
+ });
+ }
+ wc.as_mut()
+ .unwrap()
+ .predicates
+ .push(WherePredicate::Type(PredicateType {
+ lifetimes: None,
+ bounded_ty,
+ colon_token: Default::default(),
+ bounds,
+ }));
+}
+
+/// Build a MockFunction.
+#[derive(Clone, Copy, Debug)]
+pub(crate) struct Builder<'a> {
+ attrs: &'a [Attribute],
+ call_levels: Option<usize>,
+ levels: usize,
+ parent: Option<&'a Ident>,
+ sig: &'a Signature,
+ struct_: Option<&'a Ident>,
+ struct_generics: Option<&'a Generics>,
+ trait_: Option<&'a Ident>,
+ vis: &'a Visibility,
+}
+
+impl<'a> Builder<'a> {
+ pub fn attrs(&mut self, attrs: &'a [Attribute]) -> &mut Self {
+ self.attrs = attrs;
+ self
+ }
+
+ pub fn build(self) -> MockFunction {
+ let mut argnames = Vec::new();
+ let mut argty = Vec::new();
+ let mut is_static = true;
+ let mut predexprs = Vec::new();
+ let mut predty = Vec::new();
+ let mut refpredty = Vec::new();
+
+ let (mut declosured_generics, declosured_inputs, call_exprs) =
+ declosurefy(&self.sig.generics, &self.sig.inputs);
+
+ for fa in declosured_inputs.iter() {
+ if let FnArg::Typed(pt) = fa {
+ let argname = (*pt.pat).clone();
+ if pat_is_self(&argname) {
+ // A weird receiver like `Box<Self>`
+ is_static = false;
+ continue;
+ }
+ let aty = supersuperfy(&pt.ty, self.levels);
+ if let Type::Reference(ref tr) = aty {
+ predexprs.push(quote!(#argname));
+ predty.push((*tr.elem).clone());
+ let tr2 = Type::Reference(TypeReference {
+ and_token: tr.and_token,
+ lifetime: None,
+ mutability: None,
+ elem: tr.elem.clone(),
+ });
+ refpredty.push(tr2);
+ } else {
+ predexprs.push(quote!(&#argname));
+ predty.push(aty.clone());
+ let tr = TypeReference {
+ and_token: Token![&](Span::call_site()),
+ lifetime: None,
+ mutability: None,
+ elem: Box::new(aty.clone()),
+ };
+ refpredty.push(Type::Reference(tr));
+ };
+ argnames.push(argname);
+ argty.push(aty.clone());
+ } else {
+ is_static = false;
+ }
+ }
+ let (output, boxed) = match self.sig.output {
+ ReturnType::Default => (
+ Type::Tuple(TypeTuple {
+ paren_token: token::Paren::default(),
+ elems: Punctuated::new(),
+ }),
+ false,
+ ),
+ ReturnType::Type(_, ref ty) => {
+ let mut output_ty = supersuperfy(ty, self.levels);
+ destrify(&mut output_ty);
+ let boxed = dedynify(&mut output_ty);
+ (output_ty, boxed)
+ }
+ };
+ supersuperfy_generics(&mut declosured_generics, self.levels);
+ let owned_output = ownify(&output);
+ let mut return_ref = false;
+ let mut return_refmut = false;
+ if let Type::Reference(ref tr) = &output {
+ if tr.lifetime.as_ref().map_or(true, |lt| lt.ident != "static") {
+ if tr.mutability.is_none() {
+ return_ref = true;
+ } else {
+ return_refmut = true;
+ }
+ }
+ };
+ if is_static && (return_ref || return_refmut) {
+ compile_error(self.sig.span(),
+ "Mockall cannot mock static methods that return non-'static references. It's unclear what the return value's lifetime should be.");
+ }
+ let struct_generics = self.struct_generics.cloned().unwrap_or_default();
+ let (type_generics, salifetimes, srlifetimes) = split_lifetimes(
+ struct_generics.clone(),
+ &declosured_inputs,
+ &ReturnType::Type(<Token![->]>::default(), Box::new(owned_output.clone())),
+ );
+ let srltg = lifetimes_to_generics(&srlifetimes);
+ let (call_generics, malifetimes, mrlifetimes) = split_lifetimes(
+ declosured_generics,
+ &declosured_inputs,
+ &ReturnType::Type(<Token![->]>::default(), Box::new(owned_output.clone())),
+ );
+ let mrltg = lifetimes_to_generics(&mrlifetimes);
+ let cgenerics = merge_generics(&type_generics, &call_generics);
+ let egenerics = merge_generics(&merge_generics(&cgenerics, &srltg), &mrltg);
+ let alifetimes = salifetimes
+ .into_iter()
+ .collect::<HashSet<LifetimeDef>>()
+ .union(&malifetimes.into_iter().collect::<HashSet<_>>())
+ .cloned()
+ .collect();
+
+ let fn_params = egenerics.type_params().map(|tp| tp.ident.clone()).collect();
+ let call_levels = self.call_levels.unwrap_or(self.levels);
+
+ MockFunction {
+ alifetimes,
+ argnames,
+ argty,
+ attrs: self.attrs.to_vec(),
+ call_exprs,
+ call_generics,
+ call_vis: expectation_visibility(self.vis, call_levels),
+ egenerics,
+ cgenerics,
+ fn_params,
+ is_static,
+ mod_ident: self
+ .parent
+ .unwrap_or(&Ident::new("FIXME", Span::call_site()))
+ .clone(),
+ output,
+ owned_output,
+ boxed,
+ predexprs,
+ predty,
+ refpredty,
+ return_ref,
+ return_refmut,
+ sig: self.sig.clone(),
+ struct_: self.struct_.cloned(),
+ struct_generics,
+ trait_: self.trait_.cloned(),
+ type_generics,
+ privmod_vis: expectation_visibility(self.vis, self.levels),
+ }
+ }
+
+ /// How many levels of modules beneath the original function this one is
+ /// nested.
+ pub fn call_levels(&mut self, levels: usize) -> &mut Self {
+ self.call_levels = Some(levels);
+ self
+ }
+
+ /// How many levels of modules beneath the original function this one's
+ /// private module is nested.
+ pub fn levels(&mut self, levels: usize) -> &mut Self {
+ self.levels = levels;
+ self
+ }
+
+ /// # Arguments
+ ///
+ /// * sig: The signature of the mockable function
+ /// * v: The visibility of the mockable function
+ pub fn new(sig: &'a Signature, vis: &'a Visibility) -> Self {
+ Builder {
+ attrs: &[],
+ levels: 0,
+ call_levels: None,
+ parent: None,
+ sig,
+ struct_: None,
+ struct_generics: None,
+ trait_: None,
+ vis,
+ }
+ }
+
+ /// Supply the name of the parent module
+ pub fn parent(&mut self, ident: &'a Ident) -> &mut Self {
+ self.parent = Some(ident);
+ self
+ }
+
+ /// Supply the name of the parent struct, if any
+ pub fn struct_(&mut self, ident: &'a Ident) -> &mut Self {
+ self.struct_ = Some(ident);
+ self
+ }
+
+ /// Supply the Generics of the parent struct, if any
+ pub fn struct_generics(&mut self, generics: &'a Generics) -> &mut Self {
+ self.struct_generics = Some(generics);
+ self
+ }
+
+ /// Supply the name of the method's trait, if any
+ pub fn trait_(&mut self, ident: &'a Ident) -> &mut Self {
+ self.trait_ = Some(ident);
+ self
+ }
+}
+
+#[derive(Clone)]
+pub(crate) struct MockFunction {
+ /// Lifetimes of the mocked method that relate to the arguments but not the
+ /// return value
+ alifetimes: Punctuated<LifetimeDef, token::Comma>,
+ /// Names of the method arguments
+ argnames: Vec<Pat>,
+ /// Types of the method arguments
+ argty: Vec<Type>,
+ /// any attributes on the original function, like #[inline]
+ pub attrs: Vec<Attribute>,
+ /// Expressions that should be used for Expectation::call's arguments
+ call_exprs: Vec<TokenStream>,
+ /// Generics used for the expectation call
+ call_generics: Generics,
+ /// Visibility of the mock function itself
+ call_vis: Visibility,
+ /// Generics of the Expectation object
+ egenerics: Generics,
+ /// Generics of the Common object
+ cgenerics: Generics,
+ /// The mock function's generic types as a list of types
+ fn_params: Vec<Ident>,
+ /// Is this for a static method or free function?
+ is_static: bool,
+ /// name of the function's parent module
+ mod_ident: Ident,
+ /// Output type of the Method, supersuperfied.
+ output: Type,
+ /// Owned version of the output type of the Method, supersuperfied.
+ ///
+ /// If the real output type is a non-'static reference, then it will differ
+ /// from this field.
+ owned_output: Type,
+ /// True if the `owned_type` is boxed by `Box<>`.
+ boxed: bool,
+ /// Expressions that create the predicate arguments from the call arguments
+ predexprs: Vec<TokenStream>,
+ /// Types used for Predicates. Will be almost the same as args, but every
+ /// type will be a non-reference type.
+ predty: Vec<Type>,
+ /// Does the function return a non-'static reference?
+ return_ref: bool,
+ /// Does the function return a mutable reference?
+ return_refmut: bool,
+ /// References to every type in `predty`.
+ refpredty: Vec<Type>,
+ /// The signature of the mockable function
+ sig: Signature,
+ /// Name of the parent structure, if any
+ struct_: Option<Ident>,
+ /// Generics of the parent structure
+ struct_generics: Generics,
+ /// Name of this method's trait, if the method comes from a trait
+ trait_: Option<Ident>,
+ /// Type generics of the mock structure
+ type_generics: Generics,
+ /// Visibility of the expectation and its methods
+ privmod_vis: Visibility,
+}
+
+impl MockFunction {
+ /// Return the mock function itself
+ ///
+ /// # Arguments
+ ///
+ /// * `modname`: Name of the parent struct's private module
+ // Supplying modname is an unfortunately hack. Ideally MockFunction
+ // wouldn't need to know that.
+ pub fn call(&self, modname: Option<&Ident>) -> impl ToTokens {
+ let attrs = AttrFormatter::new(&self.attrs).format();
+ let call_exprs = &self.call_exprs;
+ let (_, tg, _) = if self.is_method_generic() || self.is_static() {
+ &self.egenerics
+ } else {
+ &self.call_generics
+ }
+ .split_for_impl();
+ let tbf = tg.as_turbofish();
+ let name = self.name();
+ let desc = self.desc();
+ let no_match_msg = quote!(std::format!(
+ "{}: No matching expectation found", #desc));
+ let sig = &self.sig;
+ let (vis, dead_code) = if self.trait_.is_some() {
+ (&Visibility::Inherited, quote!())
+ } else {
+ let dead_code = if let Visibility::Inherited = self.call_vis {
+ // This private method may be a helper only used by the struct's
+ // other methods, which we are mocking. If so, the mock method
+ // will be dead code. But we can't simply eliminate it, because
+ // it might also be used by other code in the same module.
+ quote!(#[allow(dead_code)])
+ } else {
+ quote!()
+ };
+ (&self.call_vis, dead_code)
+ };
+ let substruct_obj = if let Some(trait_) = &self.trait_ {
+ let ident = format_ident!("{}_expectations", trait_);
+ quote!(#ident.)
+ } else {
+ quote!()
+ };
+ let call = if self.return_refmut {
+ Ident::new("call_mut", Span::call_site())
+ } else {
+ Ident::new("call", Span::call_site())
+ };
+ let mut deref = quote!();
+ if self.boxed {
+ if self.return_ref {
+ deref = quote!(&**);
+ } else if self.return_refmut {
+ deref = quote!(&mut **);
+ }
+ }
+ if self.is_static {
+ let outer_mod_path = self.outer_mod_path(modname);
+ quote!(
+ // Don't add a doc string. The original is included in #attrs
+ #(#attrs)*
+ #dead_code
+ #vis #sig {
+ let no_match_msg = #no_match_msg;
+ #deref {
+ let __mockall_guard = #outer_mod_path::EXPECTATIONS
+ .lock().unwrap();
+ /*
+ * TODO: catch panics, then gracefully release the mutex
+ * so it won't be poisoned. This requires bounding any
+ * generic parameters with UnwindSafe
+ */
+ /* std::panic::catch_unwind(|| */
+ __mockall_guard.#call#tbf(#(#call_exprs,)*)
+ /*)*/
+ }.expect(&no_match_msg)
+ }
+ )
+ } else {
+ quote!(
+ // Don't add a doc string. The original is included in #attrs
+ #(#attrs)*
+ #dead_code
+ #vis #sig {
+ let no_match_msg = #no_match_msg;
+ #deref self.#substruct_obj #name.#call#tbf(#(#call_exprs,)*)
+ .expect(&no_match_msg)
+ }
+
+ )
+ }
+ }
+
+ /// Return this method's contribution to its parent's checkpoint method
+ pub fn checkpoint(&self) -> impl ToTokens {
+ let attrs = AttrFormatter::new(&self.attrs).doc(false).format();
+ let inner_mod_ident = self.inner_mod_ident();
+ if self.is_static {
+ quote!(
+ #(#attrs)*
+ {
+ let __mockall_timeses = #inner_mod_ident::EXPECTATIONS.lock()
+ .unwrap()
+ .checkpoint()
+ .collect::<Vec<_>>();
+ }
+ )
+ } else {
+ let name = &self.name();
+ quote!(#(#attrs)* { self.#name.checkpoint(); })
+ }
+ }
+
+ /// Return a function that creates a Context object for this function
+ ///
+ /// # Arguments
+ ///
+ /// * `modname`: Name of the parent struct's private module
+ // Supplying modname is an unfortunately hack. Ideally MockFunction
+ // wouldn't need to know that.
+ pub fn context_fn(&self, modname: Option<&Ident>) -> impl ToTokens {
+ let attrs = AttrFormatter::new(&self.attrs).doc(false).format();
+ let context_docstr = format!(
+ "Create a [`Context`]({}{}/struct.Context.html) for mocking the `{}` method",
+ modname.map(|m| format!("{}/", m)).unwrap_or_default(),
+ self.inner_mod_ident(),
+ self.name()
+ );
+ let context_ident = format_ident!("{}_context", self.name());
+ let (_, tg, _) = self.type_generics.split_for_impl();
+ let outer_mod_path = self.outer_mod_path(modname);
+ let v = &self.call_vis;
+ quote!(
+ #(#attrs)*
+ #[doc = #context_docstr]
+ #v fn #context_ident() -> #outer_mod_path::Context #tg
+ {
+ #outer_mod_path::Context::default()
+ }
+ )
+ }
+
+ /// Generate a code fragment that will print a description of the invocation
+ fn desc(&self) -> impl ToTokens {
+ let argnames = &self.argnames;
+ let name = if let Some(s) = &self.struct_ {
+ format!("{}::{}", s, self.sig.ident)
+ } else {
+ format!("{}::{}", self.mod_ident, self.sig.ident)
+ };
+ let fields = vec!["{:?}"; argnames.len()].join(", ");
+ let fstr = format!("{}({})", name, fields);
+ quote!(std::format!(#fstr, #(::mockall::MaybeDebugger(&#argnames)),*))
+ }
+
+ /// Generate code for the expect_ method
+ ///
+ /// # Arguments
+ ///
+ /// * `modname`: Name of the parent struct's private module
+ /// * `self_args`: If supplied, these are the
+ /// AngleBracketedGenericArguments of the self type of the
+ /// trait impl. e.g. The `T` in `impl Foo for Bar<T>`.
+ // Supplying modname is an unfortunately hack. Ideally MockFunction
+ // wouldn't need to know that.
+ pub fn expect(&self, modname: &Ident, self_args: Option<&PathArguments>) -> impl ToTokens {
+ let attrs = AttrFormatter::new(&self.attrs).doc(false).format();
+ let name = self.name();
+ let expect_ident = format_ident!("expect_{}", &name);
+ let expectation_obj = self.expectation_obj(self_args);
+ let funcname = &self.sig.ident;
+ let (_, tg, _) = if self.is_method_generic() {
+ &self.egenerics
+ } else {
+ &self.call_generics
+ }
+ .split_for_impl();
+ let (ig, _, wc) = self.call_generics.split_for_impl();
+ let mut wc = wc.cloned();
+ if self.is_method_generic() && (self.return_ref || self.return_refmut) {
+ // Add Senc + Sync, required for downcast, since Expectation
+ // stores an Option<#owned_output>
+ send_syncify(&mut wc, self.owned_output.clone());
+ }
+ let tbf = tg.as_turbofish();
+ let vis = &self.call_vis;
+
+ #[cfg(not(feature = "nightly_derive"))]
+ let must_use = quote!(#[must_use =
+ "Must set return value when not using the \"nightly\" feature"
+ ]);
+ #[cfg(feature = "nightly_derive")]
+ let must_use = quote!();
+
+ let substruct_obj = if let Some(trait_) = &self.trait_ {
+ let ident = format_ident!("{}_expectations", trait_);
+ quote!(#ident.)
+ } else {
+ quote!()
+ };
+ let docstr = format!(
+ "Create an [`Expectation`]({}/{}/struct.Expectation.html) for mocking the `{}` method",
+ modname,
+ self.inner_mod_ident(),
+ funcname
+ );
+ quote!(
+ #must_use
+ #[doc = #docstr]
+ #(#attrs)*
+ #vis fn #expect_ident #ig(&mut self)
+ -> &mut #modname::#expectation_obj
+ #wc
+ {
+ self.#substruct_obj #name.expect#tbf()
+ }
+ )
+ }
+
+ /// Return the name of this function's expecation object
+ fn expectation_obj(&self, self_args: Option<&PathArguments>) -> impl ToTokens {
+ let inner_mod_ident = self.inner_mod_ident();
+ if let Some(PathArguments::AngleBracketed(abga)) = self_args {
+ // staticize any lifetimes that might be present in the Expectation
+ // object but not in the self args. These come from the method's
+ // return type.
+ let mut abga2 = abga.clone();
+ for _ in self.egenerics.lifetimes() {
+ let lt = Lifetime::new("'static", Span::call_site());
+ let la = GenericArgument::Lifetime(lt);
+ abga2.args.insert(0, la);
+ }
+ assert!(
+ !self.is_method_generic(),
+ "specific impls with generic methods are TODO"
+ );
+ quote!(#inner_mod_ident::Expectation #abga2)
+ } else {
+ // staticize any lifetimes. This is necessary for methods that
+ // return non-static types, because the Expectation itself must be
+ // 'static.
+ let segenerics = staticize(&self.egenerics);
+ let (_, tg, _) = segenerics.split_for_impl();
+ quote!(#inner_mod_ident::Expectation #tg)
+ }
+ }
+
+ /// Return the name of this function's expecations object
+ pub fn expectations_obj(&self) -> impl ToTokens {
+ let inner_mod_ident = self.inner_mod_ident();
+ if self.is_method_generic() {
+ quote!(#inner_mod_ident::GenericExpectations)
+ } else {
+ quote!(#inner_mod_ident::Expectations)
+ }
+ }
+
+ pub fn field_definition(&self, modname: Option<&Ident>) -> TokenStream {
+ let name = self.name();
+ let attrs = AttrFormatter::new(&self.attrs).doc(false).format();
+ let expectations_obj = &self.expectations_obj();
+ if self.is_method_generic() {
+ quote!(#(#attrs)* #name: #modname::#expectations_obj)
+ } else {
+ // staticize any lifetimes. This is necessary for methods that
+ // return non-static types, because the Expectation itself must be
+ // 'static.
+ let segenerics = staticize(&self.egenerics);
+ let (_, tg, _) = segenerics.split_for_impl();
+ quote!(#(#attrs)* #name: #modname::#expectations_obj #tg)
+ }
+ }
+
+ /// Human-readable name of the mock function
+ fn funcname(&self) -> String {
+ if let Some(si) = &self.struct_ {
+ format!("{}::{}", si, self.name())
+ } else {
+ format!("{}", self.name())
+ }
+ }
+
+ fn hrtb(&self) -> Option<BoundLifetimes> {
+ if self.alifetimes.is_empty() {
+ None
+ } else {
+ Some(BoundLifetimes {
+ lifetimes: self.alifetimes.clone(),
+ lt_token: <Token![<]>::default(),
+ gt_token: <Token![>]>::default(),
+ ..Default::default()
+ })
+ }
+ }
+
+ fn is_expectation_generic(&self) -> bool {
+ self.egenerics
+ .params
+ .iter()
+ .any(|p| matches!(p, GenericParam::Type(_)))
+ || self.egenerics.where_clause.is_some()
+ }
+
+ /// Is the mock method generic (as opposed to a non-generic method of a
+ /// generic mock struct)?
+ pub fn is_method_generic(&self) -> bool {
+ self.call_generics
+ .params
+ .iter()
+ .any(|p| matches!(p, GenericParam::Type(_)))
+ || self.call_generics.where_clause.is_some()
+ }
+
+ fn outer_mod_path(&self, modname: Option<&Ident>) -> Path {
+ let mut path = if let Some(m) = modname {
+ Path::from(PathSegment::from(m.clone()))
+ } else {
+ Path {
+ leading_colon: None,
+ segments: Punctuated::new(),
+ }
+ };
+ path.segments
+ .push(PathSegment::from(self.inner_mod_ident()));
+ path
+ }
+
+ fn inner_mod_ident(&self) -> Ident {
+ format_ident!("__{}", &self.name())
+ }
+
+ pub fn is_static(&self) -> bool {
+ self.is_static
+ }
+
+ pub fn name(&self) -> &Ident {
+ &self.sig.ident
+ }
+
+ /// Generate code for this function's private module
+ pub fn priv_module(&self) -> impl ToTokens {
+ let attrs = AttrFormatter::new(&self.attrs).doc(false).format();
+ let common = &Common { f: self };
+ let context = &Context { f: self };
+ let expectation: Box<dyn ToTokens> = if self.return_ref {
+ Box::new(RefExpectation { f: self })
+ } else if self.return_refmut {
+ Box::new(RefMutExpectation { f: self })
+ } else {
+ Box::new(StaticExpectation { f: self })
+ };
+ let expectations: Box<dyn ToTokens> = if self.return_ref {
+ Box::new(RefExpectations { f: self })
+ } else if self.return_refmut {
+ Box::new(RefMutExpectations { f: self })
+ } else {
+ Box::new(StaticExpectations { f: self })
+ };
+ let generic_expectations = GenericExpectations { f: self };
+ let guard: Box<dyn ToTokens> = if self.is_expectation_generic() {
+ Box::new(GenericExpectationGuard { f: self })
+ } else {
+ Box::new(ConcreteExpectationGuard { f: self })
+ };
+ let matcher = &Matcher { f: self };
+ let std_mutexguard = if self.is_static {
+ quote!(
+ use std::sync::MutexGuard;
+ )
+ } else {
+ quote!()
+ };
+ let inner_mod_ident = self.inner_mod_ident();
+ let rfunc: Box<dyn ToTokens> = if self.return_ref {
+ Box::new(RefRfunc { f: self })
+ } else if self.return_refmut {
+ Box::new(RefMutRfunc { f: self })
+ } else {
+ Box::new(StaticRfunc { f: self })
+ };
+ quote!(
+ #(#attrs)*
+ #[allow(missing_docs)]
+ pub mod #inner_mod_ident {
+ use super::*;
+ use ::mockall::CaseTreeExt;
+ #std_mutexguard
+ use ::std::{
+ boxed::Box,
+ mem,
+ ops::{DerefMut, Range},
+ sync::Mutex,
+ vec::Vec,
+ };
+ #rfunc
+ #matcher
+ #common
+ #expectation
+ #expectations
+ #generic_expectations
+ #guard
+ #context
+ }
+ )
+ }
+}
+
+/// Holds parts of the expectation that are common for all output types
+struct Common<'a> {
+ f: &'a MockFunction,
+}
+
+impl<'a> ToTokens for Common<'a> {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ let argnames = &self.f.argnames;
+ let predty = &self.f.predty;
+ let hrtb = self.f.hrtb();
+ let funcname = self.f.funcname();
+ let (ig, tg, wc) = self.f.cgenerics.split_for_impl();
+ let lg = lifetimes_to_generics(&self.f.alifetimes);
+ let refpredty = &self.f.refpredty;
+ let with_generics_idents = (0..self.f.predty.len())
+ .map(|i| format_ident!("MockallMatcher{}", i))
+ .collect::<Vec<_>>();
+ let with_generics = with_generics_idents
+ .iter()
+ .zip(self.f.predty.iter())
+ .map(|(id, mt)| quote!(#id: #hrtb ::mockall::Predicate<#mt> + Send + 'static, ))
+ .collect::<TokenStream>();
+ let with_args = self
+ .f
+ .argnames
+ .iter()
+ .zip(with_generics_idents.iter())
+ .map(|(argname, id)| quote!(#argname: #id, ))
+ .collect::<TokenStream>();
+ let boxed_withargs = argnames
+ .iter()
+ .map(|aa| quote!(Box::new(#aa), ))
+ .collect::<TokenStream>();
+ quote!(
+ /// Holds the stuff that is independent of the output type
+ struct Common #ig #wc {
+ matcher: Mutex<Matcher #tg>,
+ seq_handle: Option<::mockall::SeqHandle>,
+ times: ::mockall::Times
+ }
+
+ impl #ig std::default::Default for Common #tg #wc
+ {
+ fn default() -> Self {
+ Common {
+ matcher: Mutex::new(Matcher::default()),
+ seq_handle: None,
+ times: ::mockall::Times::default()
+ }
+ }
+ }
+
+ impl #ig Common #tg #wc {
+ fn call(&self, desc: &str) {
+ self.times.call()
+ .unwrap_or_else(|m| {
+ let desc = std::format!(
+ "{}", self.matcher.lock().unwrap());
+ panic!("{}: Expectation({}) {}", #funcname, desc,
+ m);
+ });
+ self.verify_sequence(desc);
+ if ::mockall::ExpectedCalls::TooFew != self.times.is_satisfied() {
+ self.satisfy_sequence()
+ }
+ }
+
+ fn in_sequence(&mut self, __mockall_seq: &mut ::mockall::Sequence)
+ -> &mut Self
+ {
+ assert!(self.times.is_exact(),
+ "Only Expectations with an exact call count have sequences");
+ self.seq_handle = Some(__mockall_seq.next_handle());
+ self
+ }
+
+ fn is_done(&self) -> bool {
+ self.times.is_done()
+ }
+
+ #[allow(clippy::ptr_arg)]
+ fn matches #lg (&self, #( #argnames: &#predty, )*) -> bool {
+ self.matcher.lock().unwrap().matches(#(#argnames, )*)
+ }
+
+ /// Forbid this expectation from ever being called.
+ fn never(&mut self) {
+ self.times.never();
+ }
+
+ fn satisfy_sequence(&self) {
+ if let Some(__mockall_handle) = &self.seq_handle {
+ __mockall_handle.satisfy()
+ }
+ }
+
+ /// Expect this expectation to be called any number of times
+ /// contained with the given range.
+ fn times<MockallR>(&mut self, __mockall_r: MockallR)
+ where MockallR: Into<::mockall::TimesRange>
+ {
+ self.times.times(__mockall_r)
+ }
+
+ fn with<#with_generics>(&mut self, #with_args)
+ {
+ let mut __mockall_guard = self.matcher.lock().unwrap();
+ *__mockall_guard.deref_mut() =
+ Matcher::Pred(Box::new((#boxed_withargs)));
+ }
+
+ fn withf<MockallF>(&mut self, __mockall_f: MockallF)
+ where MockallF: #hrtb Fn(#( #refpredty, )*)
+ -> bool + Send + 'static
+ {
+ let mut __mockall_guard = self.matcher.lock().unwrap();
+ *__mockall_guard.deref_mut() =
+ Matcher::Func(Box::new(__mockall_f));
+ }
+
+ fn withf_st<MockallF>(&mut self, __mockall_f: MockallF)
+ where MockallF: #hrtb Fn(#( #refpredty, )*)
+ -> bool + 'static
+ {
+ let mut __mockall_guard = self.matcher.lock().unwrap();
+ *__mockall_guard.deref_mut() =
+ Matcher::FuncSt(
+ ::mockall::Fragile::new(Box::new(__mockall_f))
+ );
+ }
+
+ fn verify_sequence(&self, desc: &str) {
+ if let Some(__mockall_handle) = &self.seq_handle {
+ __mockall_handle.verify(desc)
+ }
+ }
+ }
+
+ impl #ig Drop for Common #tg #wc {
+ fn drop(&mut self) {
+ if !::std::thread::panicking() {
+ let desc = std::format!(
+ "{}", self.matcher.lock().unwrap());
+ match self.times.is_satisfied() {
+ ::mockall::ExpectedCalls::TooFew => {
+ panic!("{}: Expectation({}) called {} time(s) which is fewer than expected {}",
+ #funcname,
+ desc,
+ self.times.count(),
+ self.times.minimum());
+ },
+ ::mockall::ExpectedCalls::TooMany => {
+ panic!("{}: Expectation({}) called {} time(s) which is more than expected {}",
+ #funcname,
+ desc,
+ self.times.count(),
+ self.times.maximum());
+ },
+ _ => ()
+ }
+ }
+ }
+ }
+ ).to_tokens(tokens);
+ }
+}
+
+/// Generates methods that are common for all Expectation types
+struct CommonExpectationMethods<'a> {
+ f: &'a MockFunction,
+}
+
+impl<'a> ToTokens for CommonExpectationMethods<'a> {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ let argnames = &self.f.argnames;
+ let hrtb = self.f.hrtb();
+ let lg = lifetimes_to_generics(&self.f.alifetimes);
+ let predty = &self.f.predty;
+ let with_generics_idents = (0..self.f.predty.len())
+ .map(|i| format_ident!("MockallMatcher{}", i))
+ .collect::<Vec<_>>();
+ let with_generics = with_generics_idents
+ .iter()
+ .zip(self.f.predty.iter())
+ .map(|(id, mt)| quote!(#id: #hrtb ::mockall::Predicate<#mt> + Send + 'static, ))
+ .collect::<TokenStream>();
+ let with_args = self
+ .f
+ .argnames
+ .iter()
+ .zip(with_generics_idents.iter())
+ .map(|(argname, id)| quote!(#argname: #id, ))
+ .collect::<TokenStream>();
+ let v = &self.f.privmod_vis;
+ quote!(
+ /// Add this expectation to a
+ /// [`Sequence`](../../../mockall/struct.Sequence.html).
+ #v fn in_sequence(&mut self, __mockall_seq: &mut ::mockall::Sequence)
+ -> &mut Self
+ {
+ self.common.in_sequence(__mockall_seq);
+ self
+ }
+
+ fn is_done(&self) -> bool {
+ self.common.is_done()
+ }
+
+ /// Validate this expectation's matcher.
+ #[allow(clippy::ptr_arg)]
+ fn matches #lg (&self, #(#argnames: &#predty, )*) -> bool {
+ self.common.matches(#(#argnames, )*)
+ }
+
+ /// Forbid this expectation from ever being called.
+ #v fn never(&mut self) -> &mut Self {
+ self.common.never();
+ self
+ }
+
+ /// Create a new, default, [`Expectation`](struct.Expectation.html)
+ #v fn new() -> Self {
+ Self::default()
+ }
+
+ /// Expect this expectation to be called exactly once. Shortcut for
+ /// [`times(1)`](#method.times).
+ #v fn once(&mut self) -> &mut Self {
+ self.times(1)
+ }
+
+ /// Restrict the number of times that that this method may be called.
+ ///
+ /// The argument may be:
+ /// * A fixed number: `.times(4)`
+ /// * Various types of range:
+ /// - `.times(5..10)`
+ /// - `.times(..10)`
+ /// - `.times(5..)`
+ /// - `.times(5..=10)`
+ /// - `.times(..=10)`
+ /// * The wildcard: `.times(..)`
+ #v fn times<MockallR>(&mut self, __mockall_r: MockallR) -> &mut Self
+ where MockallR: Into<::mockall::TimesRange>
+ {
+ self.common.times(__mockall_r);
+ self
+ }
+
+ /// Set matching crieteria for this Expectation.
+ ///
+ /// The matching predicate can be anything implemening the
+ /// [`Predicate`](../../../mockall/trait.Predicate.html) trait. Only
+ /// one matcher can be set per `Expectation` at a time.
+ #v fn with<#with_generics>(&mut self, #with_args) -> &mut Self
+ {
+ self.common.with(#(#argnames, )*);
+ self
+ }
+
+ /// Set a matching function for this Expectation.
+ ///
+ /// This is equivalent to calling [`with`](#method.with) with a
+ /// function argument, like `with(predicate::function(f))`.
+ #v fn withf<MockallF>(&mut self, __mockall_f: MockallF) -> &mut Self
+ where MockallF: #hrtb Fn(#(&#predty, )*)
+ -> bool + Send + 'static
+ {
+ self.common.withf(__mockall_f);
+ self
+ }
+
+ /// Single-threaded version of [`withf`](#method.withf).
+ /// Can be used when the argument type isn't `Send`.
+ #v fn withf_st<MockallF>(&mut self, __mockall_f: MockallF) -> &mut Self
+ where MockallF: #hrtb Fn(#(&#predty, )*)
+ -> bool + 'static
+ {
+ self.common.withf_st(__mockall_f);
+ self
+ }
+ )
+ .to_tokens(tokens);
+ }
+}
+
+/// Holds the moethods of the Expectations object that are common for all
+/// Expectation types
+struct CommonExpectationsMethods<'a> {
+ f: &'a MockFunction,
+}
+
+impl<'a> ToTokens for CommonExpectationsMethods<'a> {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ let (ig, tg, wc) = self.f.egenerics.split_for_impl();
+ let v = &self.f.privmod_vis;
+ quote!(
+ /// A collection of [`Expectation`](struct.Expectations.html)
+ /// objects. Users will rarely if ever use this struct directly.
+ #[doc(hidden)]
+ #v struct Expectations #ig ( Vec<Expectation #tg>) #wc;
+
+ impl #ig Expectations #tg #wc {
+ /// Verify that all current expectations are satisfied and clear
+ /// them.
+ #v fn checkpoint(&mut self) -> std::vec::Drain<Expectation #tg>
+ {
+ self.0.drain(..)
+ }
+
+ /// Create a new expectation for this method.
+ #v fn expect(&mut self) -> &mut Expectation #tg
+ {
+ self.0.push(Expectation::default());
+ let __mockall_l = self.0.len();
+ &mut self.0[__mockall_l - 1]
+ }
+
+ #v fn new() -> Self {
+ Self::default()
+ }
+ }
+ impl #ig Default for Expectations #tg #wc
+ {
+ fn default() -> Self {
+ Expectations(Vec::new())
+ }
+ }
+ )
+ .to_tokens(tokens);
+ }
+}
+
+/// The ExpectationGuard structure for static methods with no generic types
+struct ExpectationGuardCommonMethods<'a> {
+ f: &'a MockFunction,
+}
+
+impl<'a> ToTokens for ExpectationGuardCommonMethods<'a> {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ if !self.f.is_static {
+ return;
+ }
+
+ let argnames = &self.f.argnames;
+ let argty = &self.f.argty;
+ let (_, tg, _) = self.f.egenerics.split_for_impl();
+ let keyid = gen_keyid(&self.f.egenerics);
+ let expectations = if self.f.is_expectation_generic() {
+ quote!(self.guard
+ .store
+ .get_mut(&::mockall::Key::new::#keyid())
+ .unwrap()
+ .downcast_mut::<Expectations #tg>()
+ .unwrap())
+ } else {
+ quote!(self.guard)
+ };
+ let hrtb = self.f.hrtb();
+ let output = &self.f.output;
+ let predty = &self.f.predty;
+ let with_generics_idents = (0..self.f.predty.len())
+ .map(|i| format_ident!("MockallMatcher{}", i))
+ .collect::<Vec<_>>();
+ let with_generics = with_generics_idents
+ .iter()
+ .zip(self.f.predty.iter())
+ .map(|(id, mt)| quote!(#id: #hrtb ::mockall::Predicate<#mt> + Send + 'static, ))
+ .collect::<TokenStream>();
+ let with_args = self
+ .f
+ .argnames
+ .iter()
+ .zip(with_generics_idents.iter())
+ .map(|(argname, id)| quote!(#argname: #id, ))
+ .collect::<TokenStream>();
+ let v = &self.f.privmod_vis;
+ quote!(
+ /// Just like
+ /// [`Expectation::in_sequence`](struct.Expectation.html#method.in_sequence)
+ #v fn in_sequence(&mut self,
+ __mockall_seq: &mut ::mockall::Sequence)
+ -> &mut Expectation #tg
+ {
+ #expectations.0[self.i].in_sequence(__mockall_seq)
+ }
+
+ /// Just like
+ /// [`Expectation::never`](struct.Expectation.html#method.never)
+ #v fn never(&mut self) -> &mut Expectation #tg {
+ #expectations.0[self.i].never()
+ }
+
+ /// Just like
+ /// [`Expectation::once`](struct.Expectation.html#method.once)
+ #v fn once(&mut self) -> &mut Expectation #tg {
+ #expectations.0[self.i].once()
+ }
+
+ /// Just like
+ /// [`Expectation::return_const`](struct.Expectation.html#method.return_const)
+ #v fn return_const<MockallOutput>
+ (&mut self, __mockall_c: MockallOutput)
+ -> &mut Expectation #tg
+ where MockallOutput: Clone + Into<#output> + Send + 'static
+ {
+ #expectations.0[self.i].return_const(__mockall_c)
+ }
+
+ /// Just like
+ /// [`Expectation::return_const_st`](struct.Expectation.html#method.return_const_st)
+ #v fn return_const_st<MockallOutput>
+ (&mut self, __mockall_c: MockallOutput)
+ -> &mut Expectation #tg
+ where MockallOutput: Clone + Into<#output> + 'static
+ {
+ #expectations.0[self.i].return_const_st(__mockall_c)
+ }
+
+ /// Just like
+ /// [`Expectation::returning`](struct.Expectation.html#method.returning)
+ #v fn returning<MockallF>(&mut self, __mockall_f: MockallF)
+ -> &mut Expectation #tg
+ where MockallF: #hrtb FnMut(#(#argty, )*)
+ -> #output + Send + 'static
+ {
+ #expectations.0[self.i].returning(__mockall_f)
+ }
+
+ /// Just like
+ /// [`Expectation::return_once`](struct.Expectation.html#method.return_once)
+ #v fn return_once<MockallF>(&mut self, __mockall_f: MockallF)
+ -> &mut Expectation #tg
+ where MockallF: #hrtb FnOnce(#(#argty, )*)
+ -> #output + Send + 'static
+ {
+ #expectations.0[self.i].return_once(__mockall_f)
+ }
+
+ /// Just like
+ /// [`Expectation::return_once_st`](struct.Expectation.html#method.return_once_st)
+ #v fn return_once_st<MockallF>(&mut self, __mockall_f: MockallF)
+ -> &mut Expectation #tg
+ where MockallF: #hrtb FnOnce(#(#argty, )*)
+ -> #output + 'static
+ {
+ #expectations.0[self.i].return_once_st(__mockall_f)
+ }
+
+
+ /// Just like
+ /// [`Expectation::returning_st`](struct.Expectation.html#method.returning_st)
+ #v fn returning_st<MockallF>(&mut self, __mockall_f: MockallF)
+ -> &mut Expectation #tg
+ where MockallF: #hrtb FnMut(#(#argty, )*)
+ -> #output + 'static
+ {
+ #expectations.0[self.i].returning_st(__mockall_f)
+ }
+
+ /// Just like
+ /// [`Expectation::times`](struct.Expectation.html#method.times)
+ #v fn times<MockallR>(&mut self, __mockall_r: MockallR)
+ -> &mut Expectation #tg
+ where MockallR: Into<::mockall::TimesRange>
+ {
+ #expectations.0[self.i].times(__mockall_r)
+ }
+
+ /// Just like
+ /// [`Expectation::with`](struct.Expectation.html#method.with)
+ #v fn with<#with_generics> (&mut self, #with_args)
+ -> &mut Expectation #tg
+ {
+ #expectations.0[self.i].with(#(#argnames, )*)
+ }
+
+ /// Just like
+ /// [`Expectation::withf`](struct.Expectation.html#method.withf)
+ #v fn withf<MockallF>(&mut self, __mockall_f: MockallF)
+ -> &mut Expectation #tg
+ where MockallF: #hrtb Fn(#(&#predty, )*)
+ -> bool + Send + 'static
+ {
+ #expectations.0[self.i].withf(__mockall_f)
+ }
+
+ /// Just like
+ /// [`Expectation::withf_st`](struct.Expectation.html#method.withf_st)
+ #v fn withf_st<MockallF>(&mut self, __mockall_f: MockallF)
+ -> &mut Expectation #tg
+ where MockallF: #hrtb Fn(#(&#predty, )*)
+ -> bool + 'static
+ {
+ #expectations.0[self.i].withf_st(__mockall_f)
+ }
+ )
+ .to_tokens(tokens);
+ }
+}
+
+/// The ExpectationGuard structure for static methods with no generic types
+struct ConcreteExpectationGuard<'a> {
+ f: &'a MockFunction,
+}
+
+impl<'a> ToTokens for ConcreteExpectationGuard<'a> {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ if !self.f.is_static {
+ return;
+ }
+
+ let common_methods = ExpectationGuardCommonMethods { f: self.f };
+ let (_, tg, _) = self.f.egenerics.split_for_impl();
+ let ltdef = LifetimeDef::new(Lifetime::new("'__mockall_lt", Span::call_site()));
+ let mut e_generics = self.f.egenerics.clone();
+ e_generics.lt_token.get_or_insert(<Token![<]>::default());
+ e_generics.params.push(GenericParam::Lifetime(ltdef));
+ e_generics.gt_token.get_or_insert(<Token![>]>::default());
+ let (e_ig, e_tg, e_wc) = e_generics.split_for_impl();
+ let (ei_ig, _, _) = e_generics.split_for_impl();
+ let v = &self.f.privmod_vis;
+ quote!(
+ ::mockall::lazy_static! {
+ #[doc(hidden)]
+ #v static ref EXPECTATIONS:
+ ::std::sync::Mutex<Expectations #tg> =
+ ::std::sync::Mutex::new(Expectations::new());
+ }
+ /// Like an [`&Expectation`](struct.Expectation.html) but
+ /// protected by a Mutex guard. Useful for mocking static
+ /// methods. Forwards accesses to an `Expectation` object.
+ // We must return the MutexGuard to the caller so he can
+ // configure the expectation. But we can't bundle both the
+ // guard and the &Expectation into the same structure; the
+ // borrow checker won't let us. Instead we'll record the
+ // expectation's position within the Expectations vector so we
+ // can proxy its methods.
+ //
+ // ExpectationGuard is only defined for expectations that return
+ // 'static return types.
+ #v struct ExpectationGuard #e_ig #e_wc {
+ guard: MutexGuard<'__mockall_lt, Expectations #tg>,
+ i: usize
+ }
+
+ #[allow(clippy::unused_unit)]
+ impl #ei_ig ExpectationGuard #e_tg #e_wc
+ {
+ // Should only be called from the mockall_derive generated
+ // code
+ #[doc(hidden)]
+ #v fn new(mut __mockall_guard: MutexGuard<'__mockall_lt, Expectations #tg>)
+ -> Self
+ {
+ __mockall_guard.expect(); // Drop the &Expectation
+ let __mockall_i = __mockall_guard.0.len() - 1;
+ ExpectationGuard{guard: __mockall_guard, i: __mockall_i}
+ }
+
+ #common_methods
+ }
+ )
+ .to_tokens(tokens);
+ }
+}
+
+/// The ExpectationGuard structure for static methods with generic types
+struct GenericExpectationGuard<'a> {
+ f: &'a MockFunction,
+}
+
+impl<'a> ToTokens for GenericExpectationGuard<'a> {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ if !self.f.is_static {
+ return;
+ }
+
+ let common_methods = ExpectationGuardCommonMethods { f: self.f };
+ let (_, tg, _) = self.f.egenerics.split_for_impl();
+ let keyid = gen_keyid(&self.f.egenerics);
+ let ltdef = LifetimeDef::new(Lifetime::new("'__mockall_lt", Span::call_site()));
+ let mut egenerics = self.f.egenerics.clone();
+ egenerics.lt_token.get_or_insert(<Token![<]>::default());
+ egenerics.params.push(GenericParam::Lifetime(ltdef));
+ egenerics.gt_token.get_or_insert(<Token![>]>::default());
+ let (e_ig, e_tg, e_wc) = egenerics.split_for_impl();
+ let fn_params = &self.f.fn_params;
+ let tbf = tg.as_turbofish();
+ let v = &self.f.privmod_vis;
+ quote!(
+ ::mockall::lazy_static! {
+ #v static ref EXPECTATIONS:
+ ::std::sync::Mutex<GenericExpectations> =
+ ::std::sync::Mutex::new(GenericExpectations::new());
+ }
+ /// Like an [`&Expectation`](struct.Expectation.html) but
+ /// protected by a Mutex guard. Useful for mocking static
+ /// methods. Forwards accesses to an `Expectation` object.
+ #v struct ExpectationGuard #e_ig #e_wc{
+ guard: MutexGuard<'__mockall_lt, GenericExpectations>,
+ i: usize,
+ _phantom: ::std::marker::PhantomData<(#(#fn_params,)*)>,
+ }
+
+ #[allow(clippy::unused_unit)]
+ impl #e_ig ExpectationGuard #e_tg #e_wc
+ {
+ // Should only be called from the mockall_derive generated
+ // code
+ #[doc(hidden)]
+ #v fn new(mut __mockall_guard: MutexGuard<'__mockall_lt, GenericExpectations>)
+ -> Self
+ {
+ let __mockall_ee: &mut Expectations #tg =
+ __mockall_guard.store.entry(
+ ::mockall::Key::new::#keyid()
+ ).or_insert_with(||
+ Box::new(Expectations #tbf ::new()))
+ .downcast_mut()
+ .unwrap();
+ __mockall_ee.expect(); // Drop the &Expectation
+ let __mockall_i = __mockall_ee.0.len() - 1;
+ ExpectationGuard{guard: __mockall_guard, i: __mockall_i,
+ _phantom: ::std::marker::PhantomData}
+ }
+
+ #common_methods
+ }
+ )
+ .to_tokens(tokens);
+ }
+}
+
+/// Generates Context, which manages the context for expectations of static
+/// methods.
+struct Context<'a> {
+ f: &'a MockFunction,
+}
+
+impl<'a> ToTokens for Context<'a> {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ if !self.f.is_static {
+ return;
+ }
+
+ let ltdef = LifetimeDef::new(Lifetime::new("'__mockall_lt", Span::call_site()));
+ let mut egenerics = self.f.egenerics.clone();
+ egenerics.lt_token.get_or_insert(<Token![<]>::default());
+ egenerics.params.push(GenericParam::Lifetime(ltdef));
+ egenerics.gt_token.get_or_insert(<Token![>]>::default());
+ let (_, e_tg, _) = egenerics.split_for_impl();
+ let (ty_ig, ty_tg, ty_wc) = self.f.type_generics.split_for_impl();
+ let mut meth_generics = self.f.call_generics.clone();
+ let ltdef = LifetimeDef::new(Lifetime::new("'__mockall_lt", Span::call_site()));
+ meth_generics.params.push(GenericParam::Lifetime(ltdef));
+ let (meth_ig, _meth_tg, meth_wc) = meth_generics.split_for_impl();
+ let ctx_fn_params = self
+ .f
+ .struct_generics
+ .type_params()
+ .map(|tp| tp.ident.clone())
+ .collect::<Punctuated<Ident, Token![,]>>();
+ let v = &self.f.privmod_vis;
+
+ #[cfg(not(feature = "nightly_derive"))]
+ let must_use = quote!(#[must_use =
+ "Must set return value when not using the \"nightly\" feature"
+ ]);
+ #[cfg(feature = "nightly_derive")]
+ let must_use = quote!();
+
+ quote!(
+ /// Manages the context for expectations of static methods.
+ ///
+ /// Expectations on this method will be validated and cleared when
+ /// the `Context` object drops. The `Context` object does *not*
+ /// provide any form of synchronization, so multiple tests that set
+ /// expectations on the same static method must provide their own.
+ #[must_use = "Context only serves to create expectations" ]
+ #v struct Context #ty_ig #ty_wc {
+ // Prevent "unused type parameter" errors
+ // Surprisingly, PhantomData<Fn(generics)> is Send even if
+ // generics are not, unlike PhantomData<generics>
+ _phantom: ::std::marker::PhantomData<
+ Box<dyn Fn(#ctx_fn_params) + Send>
+ >
+ }
+ impl #ty_ig Context #ty_tg #ty_wc {
+ /// Verify that all current expectations for this method are
+ /// satisfied and clear them.
+ #v fn checkpoint(&self) {
+ Self::do_checkpoint()
+ }
+ #[doc(hidden)]
+ #v fn do_checkpoint() {
+ let __mockall_timeses = EXPECTATIONS
+ .lock()
+ .unwrap()
+ .checkpoint()
+ .collect::<Vec<_>>();
+ }
+
+ /// Create a new expectation for this method.
+ #must_use
+ #v fn expect #meth_ig ( &self,) -> ExpectationGuard #e_tg
+ #meth_wc
+ {
+ ExpectationGuard::new(EXPECTATIONS.lock().unwrap())
+ }
+ }
+ impl #ty_ig Default for Context #ty_tg #ty_wc {
+ fn default() -> Self {
+ Context {_phantom: std::marker::PhantomData}
+ }
+ }
+ impl #ty_ig Drop for Context #ty_tg #ty_wc {
+ fn drop(&mut self) {
+ Self::do_checkpoint()
+ }
+ }
+ )
+ .to_tokens(tokens);
+ }
+}
+
+struct Matcher<'a> {
+ f: &'a MockFunction,
+}
+
+impl<'a> ToTokens for Matcher<'a> {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ let (ig, tg, wc) = self.f.cgenerics.split_for_impl();
+ let argnames = &self.f.argnames;
+ let braces = argnames.iter().fold(String::new(), |mut acc, _argname| {
+ if acc.is_empty() {
+ acc.push_str("{}");
+ } else {
+ acc.push_str(", {}");
+ }
+ acc
+ });
+ let fn_params = &self.f.fn_params;
+ let hrtb = self.f.hrtb();
+ let indices = (0..argnames.len())
+ .map(|i| syn::Index::from(i))
+ .collect::<Vec<_>>();
+ let lg = lifetimes_to_generics(&self.f.alifetimes);
+ let pred_matches = argnames
+ .iter()
+ .enumerate()
+ .map(|(i, argname)| {
+ let idx = syn::Index::from(i);
+ quote!(__mockall_pred.#idx.eval(#argname),)
+ })
+ .collect::<TokenStream>();
+ let preds = self
+ .f
+ .predty
+ .iter()
+ .map(|t| quote!(Box<dyn #hrtb ::mockall::Predicate<#t> + Send>,))
+ .collect::<TokenStream>();
+ let predty = &self.f.predty;
+ let refpredty = &self.f.refpredty;
+ quote!(
+ enum Matcher #ig #wc {
+ Always,
+ Func(Box<dyn #hrtb Fn(#( #refpredty, )*) -> bool + Send>),
+ // Version of Matcher::Func for closures that aren't Send
+ FuncSt(::mockall::Fragile<Box<dyn #hrtb Fn(#( #refpredty, )*) -> bool>>),
+ Pred(Box<(#preds)>),
+ // Prevent "unused type parameter" errors
+ // Surprisingly, PhantomData<Fn(generics)> is Send even if
+ // generics are not, unlike PhantomData<generics>
+ _Phantom(Box<dyn Fn(#(#fn_params,)*) + Send>)
+ }
+ impl #ig Matcher #tg #wc {
+ #[allow(clippy::ptr_arg)]
+ fn matches #lg (&self, #( #argnames: &#predty, )*) -> bool {
+ match self {
+ Matcher::Always => true,
+ Matcher::Func(__mockall_f) =>
+ __mockall_f(#(#argnames, )*),
+ Matcher::FuncSt(__mockall_f) =>
+ (__mockall_f.get())(#(#argnames, )*),
+ Matcher::Pred(__mockall_pred) =>
+ [#pred_matches]
+ .iter()
+ .all(|__mockall_x| *__mockall_x),
+ _ => unreachable!()
+ }
+ }
+ }
+
+ impl #ig Default for Matcher #tg #wc {
+ #[allow(unused_variables)]
+ fn default() -> Self {
+ Matcher::Always
+ }
+ }
+
+ impl #ig ::std::fmt::Display for Matcher #tg #wc {
+ fn fmt(&self, __mockall_fmt: &mut ::std::fmt::Formatter<'_>)
+ -> ::std::fmt::Result
+ {
+ match self {
+ Matcher::Always => write!(__mockall_fmt, "<anything>"),
+ Matcher::Func(_) => write!(__mockall_fmt, "<function>"),
+ Matcher::FuncSt(_) => write!(__mockall_fmt, "<single threaded function>"),
+ Matcher::Pred(__mockall_p) => {
+ write!(__mockall_fmt, #braces,
+ #(__mockall_p.#indices,)*)
+ }
+ _ => unreachable!(),
+ }
+ }
+ }
+ )
+ .to_tokens(tokens);
+ }
+}
+
+struct RefRfunc<'a> {
+ f: &'a MockFunction,
+}
+
+impl<'a> ToTokens for RefRfunc<'a> {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ let fn_params = &self.f.fn_params;
+ let (ig, tg, wc) = self.f.egenerics.split_for_impl();
+ let lg = lifetimes_to_generics(&self.f.alifetimes);
+ let owned_output = &self.f.owned_output;
+
+ #[cfg(not(feature = "nightly_derive"))]
+ let default_err_msg = "Returning default values requires the \"nightly\" feature";
+ #[cfg(feature = "nightly_derive")]
+ let default_err_msg = "Can only return default values for types that impl std::Default";
+
+ quote!(
+ enum Rfunc #ig #wc {
+ Default(Option<#owned_output>),
+ Const(#owned_output),
+ // Prevent "unused type parameter" errors Surprisingly,
+ // PhantomData<Fn(generics)> is Send even if generics are not,
+ // unlike PhantomData<generics>
+ _Phantom(Mutex<Box<dyn Fn(#(#fn_params,)*) + Send>>)
+ }
+
+ impl #ig Rfunc #tg #wc {
+ fn call #lg (&self)
+ -> std::result::Result<&#owned_output, &'static str>
+ {
+ match self {
+ Rfunc::Default(Some(ref __mockall_o)) => {
+ ::std::result::Result::Ok(__mockall_o)
+ },
+ Rfunc::Default(None) => {
+ Err(#default_err_msg)
+ },
+ Rfunc::Const(ref __mockall_o) => {
+ ::std::result::Result::Ok(__mockall_o)
+ },
+ Rfunc::_Phantom(_) => unreachable!()
+ }
+ }
+ }
+
+ impl #ig std::default::Default for Rfunc #tg #wc
+ {
+ fn default() -> Self {
+ use ::mockall::ReturnDefault;
+ Rfunc::Default(::mockall::DefaultReturner::<#owned_output>
+ ::maybe_return_default())
+ }
+ }
+ )
+ .to_tokens(tokens);
+ }
+}
+
+struct RefMutRfunc<'a> {
+ f: &'a MockFunction,
+}
+
+impl<'a> ToTokens for RefMutRfunc<'a> {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ let argnames = &self.f.argnames;
+ let argty = &self.f.argty;
+ let fn_params = &self.f.fn_params;
+ let (ig, tg, wc) = self.f.egenerics.split_for_impl();
+ let lg = lifetimes_to_generics(&self.f.alifetimes);
+ let owned_output = &self.f.owned_output;
+ let output = &self.f.output;
+
+ #[cfg(not(feature = "nightly_derive"))]
+ let default_err_msg = "Returning default values requires the \"nightly\" feature";
+ #[cfg(feature = "nightly_derive")]
+ let default_err_msg = "Can only return default values for types that impl std::Default";
+
+ quote!(
+ #[allow(clippy::unused_unit)]
+ enum Rfunc #ig #wc {
+ Default(Option<#owned_output>),
+ Mut((Box<dyn FnMut(#(#argty, )*) -> #owned_output + Send + Sync>),
+ Option<#owned_output>),
+ // Version of Rfunc::Mut for closures that aren't Send
+ MutSt((::mockall::Fragile<
+ Box<dyn FnMut(#(#argty, )*) -> #owned_output >>
+ ), Option<#owned_output>
+ ),
+ Var(#owned_output),
+ // Prevent "unused type parameter" errors Surprisingly,
+ // PhantomData<Fn(generics)> is Send even if generics are not,
+ // unlike PhantomData<generics>
+ _Phantom(Mutex<Box<dyn Fn(#(#fn_params,)*) + Send>>)
+ }
+
+ impl #ig Rfunc #tg #wc {
+ fn call_mut #lg (&mut self, #(#argnames: #argty, )*)
+ -> std::result::Result<#output, &'static str>
+ {
+ match self {
+ Rfunc::Default(Some(ref mut __mockall_o)) => {
+ ::std::result::Result::Ok(__mockall_o)
+ },
+ Rfunc::Default(None) => {
+ Err(#default_err_msg)
+ },
+ Rfunc::Mut(ref mut __mockall_f, ref mut __mockall_o) =>
+ {
+ *__mockall_o = Some(__mockall_f(#(#argnames, )*));
+ if let Some(ref mut __mockall_o2) = __mockall_o {
+ ::std::result::Result::Ok(__mockall_o2)
+ } else {
+ unreachable!()
+ }
+ },
+ Rfunc::MutSt(ref mut __mockall_f, ref mut __mockall_o)=>
+ {
+ *__mockall_o = Some((__mockall_f.get_mut())(
+ #(#argnames, )*)
+ );
+ if let Some(ref mut __mockall_o2) = __mockall_o {
+ ::std::result::Result::Ok(__mockall_o2)
+ } else {
+ unreachable!()
+ }
+ },
+ Rfunc::Var(ref mut __mockall_o) => {
+ ::std::result::Result::Ok(__mockall_o)
+ },
+ Rfunc::_Phantom(_) => unreachable!()
+ }
+ }
+ }
+
+ impl #ig std::default::Default for Rfunc #tg #wc
+ {
+ fn default() -> Self {
+ use ::mockall::ReturnDefault;
+ Rfunc::Default(::mockall::DefaultReturner::<#owned_output>
+ ::maybe_return_default())
+ }
+ }
+ )
+ .to_tokens(tokens);
+ }
+}
+
+struct StaticRfunc<'a> {
+ f: &'a MockFunction,
+}
+
+impl<'a> ToTokens for StaticRfunc<'a> {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ let argnames = &self.f.argnames;
+ let argty = &self.f.argty;
+ let fn_params = &self.f.fn_params;
+ let (ig, tg, wc) = self.f.egenerics.split_for_impl();
+ let hrtb = self.f.hrtb();
+ let lg = lifetimes_to_generics(&self.f.alifetimes);
+ let output = &self.f.output;
+ quote!(
+ #[allow(clippy::unused_unit)]
+ enum Rfunc #ig #wc {
+ Default,
+ // Indicates that a `return_once` expectation has already
+ // returned
+ Expired,
+ Mut(Box<dyn #hrtb FnMut(#(#argty, )*) -> #output + Send>),
+ // Version of Rfunc::Mut for closures that aren't Send
+ MutSt(::mockall::Fragile<
+ Box<dyn #hrtb FnMut(#(#argty, )*) -> #output >>
+ ),
+ Once(Box<dyn #hrtb FnOnce(#(#argty, )*) -> #output + Send>),
+ // Version of Rfunc::Once for closure that aren't Send
+ OnceSt(::mockall::Fragile<
+ Box<dyn #hrtb FnOnce(#(#argty, )*) -> #output>>
+ ),
+ // Prevent "unused type parameter" errors Surprisingly,
+ // PhantomData<Fn(generics)> is Send even if generics are not,
+ // unlike PhantomData<generics>
+ _Phantom(Box<dyn Fn(#(#fn_params,)*) + Send>)
+ }
+
+ impl #ig Rfunc #tg #wc {
+ fn call_mut #lg (&mut self, #( #argnames: #argty, )* )
+ -> std::result::Result<#output, &'static str>
+ {
+ match self {
+ Rfunc::Default => {
+ use ::mockall::ReturnDefault;
+ ::mockall::DefaultReturner::<#output>
+ ::return_default()
+ },
+ Rfunc::Expired => {
+ Err("called twice, but it returns by move")
+ },
+ Rfunc::Mut(__mockall_f) => {
+ ::std::result::Result::Ok(__mockall_f( #(#argnames, )* ))
+ },
+ Rfunc::MutSt(__mockall_f) => {
+ ::std::result::Result::Ok((__mockall_f.get_mut())(#(#argnames,)*))
+ },
+ Rfunc::Once(_) => {
+ if let Rfunc::Once(mut __mockall_f) =
+ mem::replace(self, Rfunc::Expired) {
+ ::std::result::Result::Ok(__mockall_f( #(#argnames, )* ))
+ } else {
+ unreachable!()
+ }
+ },
+ Rfunc::OnceSt(_) => {
+ if let Rfunc::OnceSt(mut __mockall_f) =
+ mem::replace(self, Rfunc::Expired) {
+ ::std::result::Result::Ok((__mockall_f.into_inner())(#(#argnames,)*))
+ } else {
+ unreachable!()
+ }
+ },
+ Rfunc::_Phantom(_) => unreachable!()
+ }
+ }
+ }
+
+ impl #ig std::default::Default for Rfunc #tg #wc
+ {
+ fn default() -> Self {
+ Rfunc::Default
+ }
+ }
+ ).to_tokens(tokens);
+ }
+}
+
+/// An expectation type for functions that take a &self and return a reference
+struct RefExpectation<'a> {
+ f: &'a MockFunction,
+}
+
+impl<'a> ToTokens for RefExpectation<'a> {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ let argnames = &self.f.argnames;
+ let argty = &self.f.argty;
+ let common_methods = CommonExpectationMethods { f: self.f };
+ let desc = self.f.desc();
+ let funcname = self.f.funcname();
+ let (ig, tg, wc) = self.f.egenerics.split_for_impl();
+
+ let (_, common_tg, _) = self.f.cgenerics.split_for_impl();
+ let lg = lifetimes_to_generics(&self.f.alifetimes);
+ let output = &self.f.output;
+ let owned_output = &self.f.owned_output;
+ let v = &self.f.privmod_vis;
+ quote!(
+ /// Expectation type for methods taking a `&self` argument and
+ /// returning immutable references. This is the type returned by
+ /// the `expect_*` methods.
+ #v struct Expectation #ig #wc {
+ common: Common #common_tg,
+ rfunc: Rfunc #tg,
+ }
+
+ #[allow(clippy::unused_unit)]
+ impl #ig Expectation #tg #wc {
+ /// Call this [`Expectation`] as if it were the real method.
+ #v fn call #lg (&self, #(#argnames: #argty, )*) -> #output
+ {
+ self.common.call(&#desc);
+ self.rfunc.call().unwrap_or_else(|m| {
+ let desc = std::format!(
+ "{}", self.common.matcher.lock().unwrap());
+ panic!("{}: Expectation({}) {}", #funcname, desc,
+ m);
+ })
+ }
+
+ /// Return a reference to a constant value from the `Expectation`
+ #v fn return_const(&mut self, __mockall_o: #owned_output)
+ -> &mut Self
+ {
+ self.rfunc = Rfunc::Const(__mockall_o);
+ self
+ }
+
+ #common_methods
+ }
+ impl #ig Default for Expectation #tg #wc
+ {
+ fn default() -> Self {
+ Expectation {
+ common: Common::default(),
+ rfunc: Rfunc::default()
+ }
+ }
+ }
+ )
+ .to_tokens(tokens);
+ }
+}
+
+/// For methods that take &mut self and return a reference
+struct RefMutExpectation<'a> {
+ f: &'a MockFunction,
+}
+
+impl<'a> ToTokens for RefMutExpectation<'a> {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ let common_methods = CommonExpectationMethods { f: self.f };
+ let argnames = &self.f.argnames;
+ let argty = &self.f.argty;
+ let desc = self.f.desc();
+ let funcname = self.f.funcname();
+ let (ig, tg, wc) = self.f.egenerics.split_for_impl();
+ let (_, common_tg, _) = self.f.cgenerics.split_for_impl();
+ let lg = lifetimes_to_generics(&self.f.alifetimes);
+ let owned_output = &self.f.owned_output;
+ let v = &self.f.privmod_vis;
+ quote!(
+ /// Expectation type for methods taking a `&mut self` argument and
+ /// returning references. This is the type returned by the
+ /// `expect_*` methods.
+ #v struct Expectation #ig #wc {
+ common: Common #common_tg,
+ rfunc: Rfunc #tg
+ }
+
+ #[allow(clippy::unused_unit)]
+ impl #ig Expectation #tg #wc {
+ /// Simulating calling the real method for this expectation
+ #v fn call_mut #lg (&mut self, #(#argnames: #argty, )*)
+ -> &mut #owned_output
+ {
+ self.common.call(&#desc);
+ let desc = std::format!(
+ "{}", self.common.matcher.lock().unwrap());
+ self.rfunc.call_mut(#(#argnames, )*).unwrap_or_else(|m| {
+ panic!("{}: Expectation({}) {}", #funcname, desc,
+ m);
+ })
+ }
+
+ /// Convenience method that can be used to supply a return value
+ /// for a `Expectation`. The value will be returned by mutable
+ /// reference.
+ #v fn return_var(&mut self, __mockall_o: #owned_output) -> &mut Self
+ {
+ self.rfunc = Rfunc::Var(__mockall_o);
+ self
+ }
+
+ /// Supply a closure that the `Expectation` will use to create its
+ /// return value. The return value will be returned by mutable
+ /// reference.
+ #v fn returning<MockallF>(&mut self, __mockall_f: MockallF)
+ -> &mut Self
+ where MockallF: FnMut(#(#argty, )*) -> #owned_output + Send + Sync + 'static
+ {
+ self.rfunc = Rfunc::Mut(Box::new(__mockall_f), None);
+ self
+ }
+
+ /// Single-threaded version of [`returning`](#method.returning).
+ /// Can be used when the argument or return type isn't `Send`.
+ #v fn returning_st<MockallF>(&mut self, __mockall_f: MockallF)
+ -> &mut Self
+ where MockallF: FnMut(#(#argty, )*) -> #owned_output + 'static
+ {
+ self.rfunc = Rfunc::MutSt(
+ ::mockall::Fragile::new(Box::new(__mockall_f)), None);
+ self
+ }
+
+ #common_methods
+ }
+ impl #ig Default for Expectation #tg #wc
+ {
+ fn default() -> Self {
+ Expectation {
+ common: Common::default(),
+ rfunc: Rfunc::default()
+ }
+ }
+ }
+ )
+ .to_tokens(tokens);
+ }
+}
+
+/// An expectation type for functions return a `'static` value
+struct StaticExpectation<'a> {
+ f: &'a MockFunction,
+}
+
+impl<'a> ToTokens for StaticExpectation<'a> {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ let common_methods = CommonExpectationMethods { f: self.f };
+ let argnames = &self.f.argnames;
+ let argty = &self.f.argty;
+ let desc = self.f.desc();
+ let hrtb = self.f.hrtb();
+ let funcname = self.f.funcname();
+ let (ig, tg, wc) = self.f.egenerics.split_for_impl();
+ let (_, common_tg, _) = self.f.cgenerics.split_for_impl();
+ let lg = lifetimes_to_generics(&self.f.alifetimes);
+ let output = &self.f.output;
+ let v = &self.f.privmod_vis;
+
+ quote!(
+ /// Expectation type for methods that return a `'static` type.
+ /// This is the type returned by the `expect_*` methods.
+ #v struct Expectation #ig #wc {
+ common: Common #common_tg,
+ rfunc: Mutex<Rfunc #tg>,
+ }
+
+ #[allow(clippy::unused_unit)]
+ impl #ig Expectation #tg #wc {
+ /// Call this [`Expectation`] as if it were the real method.
+ #[doc(hidden)]
+ #v fn call #lg (&self, #(#argnames: #argty, )* ) -> #output
+ {
+ self.common.call(&#desc);
+ self.rfunc.lock().unwrap().call_mut(#(#argnames, )*)
+ .unwrap_or_else(|message| {
+ let desc = std::format!(
+ "{}", self.common.matcher.lock().unwrap());
+ panic!("{}: Expectation({}) {}", #funcname, desc,
+ message);
+ })
+ }
+
+ /// Return a constant value from the `Expectation`
+ ///
+ /// The output type must be `Clone`. The compiler can't always
+ /// infer the proper type to use with this method; you will
+ /// usually need to specify it explicitly. i.e.
+ /// `return_const(42i32)` instead of `return_const(42)`.
+ // We must use Into<#output> instead of #output because where
+ // clauses don't accept equality constraints.
+ // https://github.com/rust-lang/rust/issues/20041
+ #[allow(unused_variables)]
+ #v fn return_const<MockallOutput>(&mut self,
+ __mockall_c: MockallOutput)
+ -> &mut Self
+ where MockallOutput: Clone + Into<#output> + Send + 'static
+ {
+ self.returning(move |#(#argnames, )*| __mockall_c.clone().into())
+ }
+
+ /// Single-threaded version of
+ /// [`return_const`](#method.return_const). This is useful for
+ /// return types that are not `Send`.
+ ///
+ /// The output type must be `Clone`. The compiler can't always
+ /// infer the proper type to use with this method; you will
+ /// usually need to specify it explicitly. i.e.
+ /// `return_const(42i32)` instead of `return_const(42)`.
+ ///
+ /// It is a runtime error to call the mock method from a
+ /// different thread than the one that originally called this
+ /// method.
+ // We must use Into<#output> instead of #output because where
+ // clauses don't accept equality constraints.
+ // https://github.com/rust-lang/rust/issues/20041
+ #[allow(unused_variables)]
+ #v fn return_const_st<MockallOutput>(&mut self,
+ __mockall_c: MockallOutput)
+ -> &mut Self
+ where MockallOutput: Clone + Into<#output> + 'static
+ {
+ self.returning_st(move |#(#argnames, )*| __mockall_c.clone().into())
+ }
+
+ /// Supply an `FnOnce` closure that will provide the return
+ /// value for this Expectation. This is useful for return types
+ /// that aren't `Clone`. It will be an error to call this
+ /// method multiple times.
+ #v fn return_once<MockallF>(&mut self, __mockall_f: MockallF)
+ -> &mut Self
+ where MockallF: #hrtb FnOnce(#(#argty, )*)
+ -> #output + Send + 'static
+ {
+ {
+ let mut __mockall_guard = self.rfunc.lock().unwrap();
+ *__mockall_guard.deref_mut() =
+ Rfunc::Once(Box::new(__mockall_f));
+ }
+ self
+ }
+
+ /// Single-threaded version of
+ /// [`return_once`](#method.return_once). This is useful for
+ /// return types that are neither `Send` nor `Clone`.
+ ///
+ /// It is a runtime error to call the mock method from a
+ /// different thread than the one that originally called this
+ /// method. It is also a runtime error to call the method more
+ /// than once.
+ #v fn return_once_st<MockallF>(&mut self, __mockall_f:
+ MockallF) -> &mut Self
+ where MockallF: #hrtb FnOnce(#(#argty, )*)
+ -> #output + 'static
+ {
+ {
+ let mut __mockall_guard = self.rfunc.lock().unwrap();
+ *__mockall_guard.deref_mut() = Rfunc::OnceSt(
+ ::mockall::Fragile::new(Box::new(__mockall_f)));
+ }
+ self
+ }
+
+ /// Supply a closure that will provide the return value for this
+ /// `Expectation`. The method's arguments are passed to the
+ /// closure by value.
+ #v fn returning<MockallF>(&mut self, __mockall_f: MockallF)
+ -> &mut Self
+ where MockallF: #hrtb FnMut(#(#argty, )*)
+ -> #output + Send + 'static
+ {
+ {
+ let mut __mockall_guard = self.rfunc.lock().unwrap();
+ *__mockall_guard.deref_mut() =
+ Rfunc::Mut(Box::new(__mockall_f));
+ }
+ self
+ }
+
+ /// Single-threaded version of [`returning`](#method.returning).
+ /// Can be used when the argument or return type isn't `Send`.
+ ///
+ /// It is a runtime error to call the mock method from a
+ /// different thread than the one that originally called this
+ /// method.
+ #v fn returning_st<MockallF>(&mut self, __mockall_f: MockallF)
+ -> &mut Self
+ where MockallF: #hrtb FnMut(#(#argty, )*)
+ -> #output + 'static
+ {
+ {
+ let mut __mockall_guard = self.rfunc.lock().unwrap();
+ *__mockall_guard.deref_mut() = Rfunc::MutSt(
+ ::mockall::Fragile::new(Box::new(__mockall_f)));
+ }
+ self
+ }
+
+ #common_methods
+ }
+ impl #ig Default for Expectation #tg #wc
+ {
+ fn default() -> Self {
+ Expectation {
+ common: Common::default(),
+ rfunc: Mutex::new(Rfunc::default())
+ }
+ }
+ }
+ )
+ .to_tokens(tokens);
+ }
+}
+
+/// An collection of RefExpectation's
+struct RefExpectations<'a> {
+ f: &'a MockFunction,
+}
+
+impl<'a> ToTokens for RefExpectations<'a> {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ let common_methods = CommonExpectationsMethods { f: self.f };
+ let argnames = &self.f.argnames;
+ let argty = &self.f.argty;
+ let (ig, tg, wc) = self.f.egenerics.split_for_impl();
+ let lg = lifetimes_to_generics(&self.f.alifetimes);
+ let output = &self.f.output;
+ let predexprs = &self.f.predexprs;
+ let v = &self.f.privmod_vis;
+ quote!(
+ #common_methods
+ impl #ig Expectations #tg #wc {
+ /// Simulate calling the real method. Every current expectation
+ /// will be checked in FIFO order and the first one with
+ /// matching arguments will be used.
+ #v fn call #lg (&self, #(#argnames: #argty, )* )
+ -> Option<#output>
+ {
+ self.0.iter()
+ .find(|__mockall_e|
+ __mockall_e.matches(#(#predexprs, )*) &&
+ (!__mockall_e.is_done() || self.0.len() == 1))
+ .map(move |__mockall_e|
+ __mockall_e.call(#(#argnames),*)
+ )
+ }
+
+ }
+ )
+ .to_tokens(tokens);
+ }
+}
+
+/// An collection of RefMutExpectation's
+struct RefMutExpectations<'a> {
+ f: &'a MockFunction,
+}
+
+impl<'a> ToTokens for RefMutExpectations<'a> {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ let common_methods = CommonExpectationsMethods { f: self.f };
+ let argnames = &self.f.argnames;
+ let argty = &self.f.argty;
+ let (ig, tg, wc) = self.f.egenerics.split_for_impl();
+ let lg = lifetimes_to_generics(&self.f.alifetimes);
+ let output = &self.f.output;
+ let predexprs = &self.f.predexprs;
+ let v = &self.f.privmod_vis;
+ quote!(
+ #common_methods
+ impl #ig Expectations #tg #wc {
+ /// Simulate calling the real method. Every current expectation
+ /// will be checked in FIFO order and the first one with
+ /// matching arguments will be used.
+ #v fn call_mut #lg (&mut self, #(#argnames: #argty, )* )
+ -> Option<#output>
+ {
+ let __mockall_n = self.0.len();
+ self.0.iter_mut()
+ .find(|__mockall_e|
+ __mockall_e.matches(#(#predexprs, )*) &&
+ (!__mockall_e.is_done() || __mockall_n == 1))
+ .map(move |__mockall_e|
+ __mockall_e.call_mut(#(#argnames, )*)
+ )
+ }
+
+ }
+ )
+ .to_tokens(tokens);
+ }
+}
+
+/// An collection of Expectation's for methods returning static values
+struct StaticExpectations<'a> {
+ f: &'a MockFunction,
+}
+
+impl<'a> ToTokens for StaticExpectations<'a> {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ let common_methods = CommonExpectationsMethods { f: self.f };
+ let argnames = &self.f.argnames;
+ let argty = &self.f.argty;
+ let (ig, tg, wc) = self.f.egenerics.split_for_impl();
+ let lg = lifetimes_to_generics(&self.f.alifetimes);
+ let output = &self.f.output;
+ let predexprs = &self.f.predexprs;
+ let v = &self.f.privmod_vis;
+ quote!(
+ #common_methods
+ impl #ig Expectations #tg #wc {
+ /// Simulate calling the real method. Every current expectation
+ /// will be checked in FIFO order and the first one with
+ /// matching arguments will be used.
+ #v fn call #lg (&self, #(#argnames: #argty, )* )
+ -> Option<#output>
+ {
+ self.0.iter()
+ .find(|__mockall_e|
+ __mockall_e.matches(#(#predexprs, )*) &&
+ (!__mockall_e.is_done() || self.0.len() == 1))
+ .map(move |__mockall_e|
+ __mockall_e.call(#(#argnames, )*)
+ )
+ }
+
+ }
+ )
+ .to_tokens(tokens);
+ }
+}
+
+struct GenericExpectations<'a> {
+ f: &'a MockFunction,
+}
+
+impl<'a> ToTokens for GenericExpectations<'a> {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ if !self.f.is_expectation_generic() {
+ return;
+ }
+ if !self.f.is_static() && !self.f.is_method_generic() {
+ return;
+ }
+
+ let ge = StaticGenericExpectations { f: self.f };
+ let v = &self.f.privmod_vis;
+ quote!(
+ /// A collection of [`Expectation`](struct.Expectations.html)
+ /// objects for a generic method. Users will rarely if ever use
+ /// this struct directly.
+ #[doc(hidden)]
+ #[derive(Default)]
+ #v struct GenericExpectations{
+ store: std::collections::hash_map::HashMap<::mockall::Key,
+ Box<dyn ::mockall::AnyExpectations>>
+ }
+ impl GenericExpectations {
+ /// Verify that all current expectations are satisfied and clear
+ /// them. This applies to all sets of generic parameters!
+ #v fn checkpoint(&mut self) ->
+ std::collections::hash_map::Drain<::mockall::Key,
+ Box<dyn ::mockall::AnyExpectations>>
+ {
+ self.store.drain()
+ }
+
+ #v fn new() -> Self {
+ Self::default()
+ }
+ }
+ #ge
+ )
+ .to_tokens(tokens);
+ }
+}
+
+/// Generates methods for GenericExpectations for methods returning static
+/// values
+struct StaticGenericExpectations<'a> {
+ f: &'a MockFunction,
+}
+
+impl<'a> ToTokens for StaticGenericExpectations<'a> {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ let argnames = &self.f.argnames;
+ let argty = &self.f.argty;
+ let (ig, tg, wc) = self.f.egenerics.split_for_impl();
+ let keyid = gen_keyid(&self.f.egenerics);
+ let mut any_wc = wc.cloned();
+ if self.f.return_ref || self.f.return_refmut {
+ // Add Senc + Sync, required for downcast, since Expectation
+ // stores an Option<#owned_output>
+ send_syncify(&mut any_wc, self.f.owned_output.clone());
+ }
+ let tbf = tg.as_turbofish();
+ let output = &self.f.output;
+ let v = &self.f.privmod_vis;
+ let (call, get, self_, downcast) = if self.f.return_refmut {
+ (
+ format_ident!("call_mut"),
+ format_ident!("get_mut"),
+ quote!(&mut self),
+ format_ident!("downcast_mut"),
+ )
+ } else {
+ (
+ format_ident!("call"),
+ format_ident!("get"),
+ quote!(&self),
+ format_ident!("downcast_ref"),
+ )
+ };
+ quote!(
+ impl #ig ::mockall::AnyExpectations for Expectations #tg #any_wc {}
+ impl GenericExpectations {
+ /// Simulating calling the real method.
+ #v fn #call #ig (#self_, #(#argnames: #argty, )* )
+ -> Option<#output> #wc
+ {
+ self.store.#get(&::mockall::Key::new::#keyid())
+ .map(|__mockall_e| {
+ __mockall_e.#downcast::<Expectations #tg>()
+ .unwrap()
+ .#call(#(#argnames, )*)
+ }).flatten()
+ }
+
+ /// Create a new Expectation.
+ #v fn expect #ig (&mut self) -> &mut Expectation #tg #any_wc
+ {
+ self.store.entry(::mockall::Key::new::#keyid())
+ .or_insert_with(|| Box::new(Expectations #tbf::new()))
+ .downcast_mut::<Expectations #tg>()
+ .unwrap()
+ .expect()
+ }
+ }
+ )
+ .to_tokens(tokens)
+ }
+}