1 // vim: tw=80
2 use super::*;
3 
4 /// Performs transformations on a function to make it mockable
mockable_fn(mut item_fn: ItemFn) -> ItemFn5 fn mockable_fn(mut item_fn: ItemFn) -> ItemFn {
6     demutify(&mut item_fn.sig.inputs);
7     deimplify(&mut item_fn.sig.output);
8     item_fn
9 }
10 
11 /// Performs transformations on an Item to make it mockable
mockable_item(item: Item) -> Item12 fn mockable_item(item: Item) -> Item {
13     match item {
14         Item::Fn(item_fn) => Item::Fn(mockable_fn(item_fn)),
15         x => x
16     }
17 }
18 
19 /// An item that's ready to be mocked.
20 ///
21 /// It should be functionally identical or near-identical to the original item,
22 /// but with minor alterations that make it suitable for mocking, such as
23 /// altered lifetimes.
24 pub(crate) enum MockableItem {
25     Module(MockableModule),
26     Struct(MockableStruct)
27 }
28 
29 impl From<(Attrs, Item)> for MockableItem {
from((attrs, item): (Attrs, Item)) -> MockableItem30     fn from((attrs, item): (Attrs, Item)) -> MockableItem {
31         match item {
32             Item::Impl(item_impl) =>
33                 MockableItem::Struct(MockableStruct::from(item_impl)),
34             Item::Mod(item_mod) =>
35                 MockableItem::Module(MockableModule::from(item_mod)),
36             Item::Trait(trait_) =>
37                 MockableItem::Struct(MockableStruct::from((attrs, trait_))),
38             _ => panic!("automock does not support this item type")
39         }
40     }
41 }
42 
43 impl From<MockableStruct> for MockableItem {
from(mock: MockableStruct) -> MockableItem44     fn from(mock: MockableStruct) -> MockableItem {
45         MockableItem::Struct(mock)
46     }
47 }
48 
49 pub(crate) struct MockableModule {
50     pub attrs: TokenStream,
51     pub vis: Visibility,
52     pub mock_ident: Ident,
53     /// Ident of the original module, if any
54     pub orig_ident: Option<Ident>,
55     pub content: Vec<Item>
56 }
57 
58 impl From<ItemMod> for MockableModule {
from(mod_: ItemMod) -> MockableModule59     fn from(mod_: ItemMod) -> MockableModule {
60         let span = mod_.span();
61         let vis = mod_.vis;
62         let mock_ident = format_ident!("mock_{}", mod_.ident);
63         let orig_ident = Some(mod_.ident);
64         let content = if let Some((_, content)) = mod_.content {
65             content.into_iter()
66             .map(mockable_item)
67             .collect()
68         } else {
69             compile_error(span,
70             "automock can only mock inline modules, not modules from another file");
71             Vec::new()
72         };
73         MockableModule {
74             attrs: TokenStream::new(),
75             vis,
76             mock_ident,
77             orig_ident,
78             content
79         }
80     }
81 }
82