// vim: tw=80 use super::*; /// Performs transformations on a function to make it mockable fn mockable_fn(mut item_fn: ItemFn) -> ItemFn { demutify(&mut item_fn.sig.inputs); deimplify(&mut item_fn.sig.output); item_fn } /// Performs transformations on an Item to make it mockable fn mockable_item(item: Item) -> Item { match item { Item::Fn(item_fn) => Item::Fn(mockable_fn(item_fn)), x => x } } /// An item that's ready to be mocked. /// /// It should be functionally identical or near-identical to the original item, /// but with minor alterations that make it suitable for mocking, such as /// altered lifetimes. pub(crate) enum MockableItem { Module(MockableModule), Struct(MockableStruct) } impl From<(Attrs, Item)> for MockableItem { fn from((attrs, item): (Attrs, Item)) -> MockableItem { match item { Item::Impl(item_impl) => MockableItem::Struct(MockableStruct::from(item_impl)), Item::Mod(item_mod) => MockableItem::Module(MockableModule::from(item_mod)), Item::Trait(trait_) => MockableItem::Struct(MockableStruct::from((attrs, trait_))), _ => panic!("automock does not support this item type") } } } impl From for MockableItem { fn from(mock: MockableStruct) -> MockableItem { MockableItem::Struct(mock) } } pub(crate) struct MockableModule { pub attrs: TokenStream, pub vis: Visibility, pub mock_ident: Ident, /// Ident of the original module, if any pub orig_ident: Option, pub content: Vec } impl From for MockableModule { fn from(mod_: ItemMod) -> MockableModule { let span = mod_.span(); let vis = mod_.vis; let mock_ident = format_ident!("mock_{}", mod_.ident); let orig_ident = Some(mod_.ident); let content = if let Some((_, content)) = mod_.content { content.into_iter() .map(mockable_item) .collect() } else { compile_error(span, "automock can only mock inline modules, not modules from another file"); Vec::new() }; MockableModule { attrs: TokenStream::new(), vis, mock_ident, orig_ident, content } } }