Skip to main content

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}