audunhalland / entrait

Loosely coupled Rust application design made easy
83 stars 1 forks source link

Mocking traits with &impl and &mut impl parameters #27

Closed wackazong closed 1 year ago

wackazong commented 1 year ago

Both functions give me compiler errrors for cargo build --tests. I use entrait with the unimock feature as dependency. Is there a way to make them work with entrait/unimock?

use entrait::entrait;

pub trait MyTrait {}

#[entrait(Foo, mock_api=FooMock)]
fn foo<D>(_: &D, _foo: &impl MyTrait) -> i32 {
    unimplemented!()
}

#[entrait(Bar, mock_api=BarMock)]
fn bar<D>(_: &D, _bar: &mut impl MyTrait) -> i32 {
    unimplemented!()
}

fn main() {}

Errors:

error[E0658]: `impl Trait` in type aliases is unstable
 --> src/main.rs:6:25
  |
6 | fn foo<D>(_: &D, _foo: &impl MyTrait) -> i32 {
  |                         ^^^^^^^^^^^^
  |
  = note: see issue #63063 <https://github.com/rust-lang/rust/issues/63063> for more information

error[E0658]: `impl Trait` in type aliases is unstable
  --> src/main.rs:11:29
   |
11 | fn bar<D>(_: &D, _bar: &mut impl MyTrait) -> i32 {
   |                             ^^^^^^^^^^^^
   |
   = note: see issue #63063 <https://github.com/rust-lang/rust/issues/63063> for more information

error: unconstrained opaque type
 --> src/main.rs:6:25
  |
6 | fn foo<D>(_: &D, _foo: &impl MyTrait) -> i32 {
  |                         ^^^^^^^^^^^^
  |
  = note: `Inputs` must be used in combination with a concrete type within the same impl

error[E0599]: the method `unimock_try_debug` exists for mutable reference `&mut _::<impl MockFn for BarMock>::Inputs<'_>::{opaque#0}`, but its trait bounds were not satisfied
  --> src/main.rs:10:1
   |
10 | #[entrait(Bar, mock_api=BarMock)]
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ method cannot be called due to unsatisfied trait bounds
   |
   = note: the following trait bounds were not satisfied:
           `&mut _::<impl MockFn for BarMock>::Inputs<'_>::{opaque#0}: Debug`
           which is required by `&mut _::<impl MockFn for BarMock>::Inputs<'_>::{opaque#0}: ProperDebug`
           `_::<impl MockFn for BarMock>::Inputs<'_>::{opaque#0}: Debug`
           which is required by `_::<impl MockFn for BarMock>::Inputs<'_>::{opaque#0}: ProperDebug`
   = note: this error originates in the attribute macro `::entrait::__unimock::unimock` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0308]: mismatched types
   --> src/main.rs:6:18
    |
5   | #[entrait(Foo, mock_api=FooMock)]
    | --------------------------------- arguments to this function are incorrect
6   | fn foo<D>(_: &D, _foo: &impl MyTrait) -> i32 {
    |                  ^^^^   ------------
    |                  |      |
    |                  |      the expected opaque type
    |                  |      this type parameter
    |                  expected `&_::<impl MockFn for ...>::Inputs<'_>::{opaque#0}`, found `&impl MyTrait`
    |
    = note: expected reference `&_::<impl MockFn for FooMock>::Inputs<'_>::{opaque#0}`
               found reference `&impl MyTrait`
    = help: type parameters must be constrained to match other types
    = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
note: function defined here
   --> /Users/ander/.cargo/registry/src/github.com-1ecc6299db9ec823/unimock-0.4.12/src/macro_api.rs:209:8
    |
209 | pub fn eval<'u, 'i, F>(unimock: &'u Unimock, inputs: F::Inputs<'i>) -> Evaluation<'u, 'i, F>
    |        ^^^^

error[E0308]: mismatched types
   --> src/main.rs:11:18
    |
10  | #[entrait(Bar, mock_api=BarMock)]
    | --------------------------------- arguments to this function are incorrect
11  | fn bar<D>(_: &D, _bar: &mut impl MyTrait) -> i32 {
    |                  ^^^^       ------------
    |                  |          |
    |                  |          the expected opaque type
    |                  |          this type parameter
    |                  expected `&mut _::<impl MockFn for ...>::Inputs<'_>::{opaque#0}`, found `&mut impl MyTrait`
    |
    = note: expected mutable reference `&mut _::<impl MockFn for BarMock>::Inputs<'_>::{opaque#0}`
               found mutable reference `&mut impl MyTrait`
    = help: type parameters must be constrained to match other types
    = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
note: function defined here
   --> /Users/ander/.cargo/registry/src/github.com-1ecc6299db9ec823/unimock-0.4.12/src/macro_api.rs:209:8
    |
209 | pub fn eval<'u, 'i, F>(unimock: &'u Unimock, inputs: F::Inputs<'i>) -> Evaluation<'u, 'i, F>
    |        ^^^^

Some errors have detailed explanations: E0308, E0599, E0658.
For more information about an error, try `rustc --explain E0308`.
wackazong commented 1 year ago

I changed the syntax to generic functions which compiles just fine:

use std::fmt::Debug;

use entrait::entrait;

pub trait MyTrait: Debug {}

#[entrait(Foo, mock_api=FooMock)]
fn foo<D, T: MyTrait>(_: &D, _foo: &T) -> i32 {
    unimplemented!()
}

#[entrait(Bar, mock_api=BarMock)]
fn bar<D, T: MyTrait>(_: &D, _bar: &mut T) -> i32 {
    unimplemented!()
}

fn main() {}
wackazong commented 1 year ago

Sidenote: when using the module version of the entrait macro, I need to use distinct generic type parameters for all functions. This example will not compile and complain about the name `T` is already used for a generic parameter in this item's generic parameters

use std::fmt::Debug;

use entrait::entrait;

pub trait MyTrait: Debug {
    fn foor();
}

#[entrait(pub Foo, mock_api=mock, no_deps)]
mod my_module {
    pub fn foo<T: super::MyTrait>(_foo: &T) -> i32 {
        unimplemented!()
    }
    pub fn bar<T: super::MyTrait>(_bar: &mut T) -> i32 {
        unimplemented!()
    }
}

fn main() {}