double_derive/lib.rs
1mod double_trait;
2mod dummies;
3mod dummy_impl;
4
5use syn::{Error, ItemTrait, parse_macro_input};
6
7/// Generates a "dummy" implementation for each method in a trait and implements the trait for `Dummy`.
8///
9/// This eases implementing test doubles in cases there the test does not require all the methods of
10/// a trait. The compiler is happy as there is a default implementation and you can focus on
11/// overwriting the behavior which is of interest to your test.
12///
13/// * Most default implementations will call `unimplemented!`.
14/// * Existing default implementations are respected and not overridden.
15/// * Methods returning `impl` Trait will not work unless they are specifically supproted by this
16/// crate. One way to deal with this, is to give them an explicit default implementation in the
17/// test case. E.g.,
18///
19/// ```
20/// # trait Answer {}
21/// # struct DummyAnswer;
22/// # impl Answer for DummyAnswer {}
23///
24/// #[cfg_attr(test, double_trait::dummies)]
25/// trait MyTrait {
26/// #[cfg(not(test))]
27/// fn answer(&self) -> impl Answer;
28///
29/// // `dummies` can not interfere a type for `impl Answer`, so we provide a default impl here.
30/// #[cfg(test)]
31/// fn answer(&self) -> impl Answer {
32/// DummyAnswer
33/// }
34///
35/// // ... other methods ...
36/// }
37/// ```
38///
39/// * Associated types are implemented using `Dummy`.
40/// * Async methods and methods returning `impl Future` are supported and inherit the default from
41/// their sync counterparts.
42/// * Methods returning `impl Iterator` are supported and will return an empty iterator.
43/// * Methods returning `impl Stream` are supported if the `stream` feature is activated and will
44/// return an empty Stream.
45/// * Methods returning `Result`, will use the default behavior of the `Ok` type and wrap it in
46/// `Ok`.
47/// * Methods returning `Option` will return `None`.
48/// * Methods returning `Vec` will return `Vec::new`.
49///
50#[proc_macro_attribute]
51pub fn dummies(
52 _attr: proc_macro::TokenStream,
53 item: proc_macro::TokenStream,
54) -> proc_macro::TokenStream {
55 let item = parse_macro_input!(item as ItemTrait);
56
57 let output = dummies::expand(item).unwrap_or_else(Error::into_compile_error);
58
59 proc_macro::TokenStream::from(output)
60}