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