nrxus / faux

Struct mocking library for Rust
https://nrxus.github.io/faux/
MIT License
411 stars 14 forks source link

Add support for `derive_more::Constructor` #58

Open FalkWoldmann opened 5 months ago

FalkWoldmann commented 5 months ago

Hi, using both derive_more::Constructor and faux on the same struct like in following example will lead to an error when trying to compile the tests.

use crate::bar::Bar;
use derive_more::Constructor;

fn main() {
    let bar = Bar::new("abc".to_string());

    let foo = Foo::new(bar);
}

#[cfg_attr(test, faux::create)]
#[derive(Constructor)]
struct Foo {
    bar: Bar,
}

mod bar {

    #[cfg_attr(test, faux::create)]
    pub(crate) struct Bar {
        pub baz: String,
    }

    #[cfg_attr(test, faux::methods)]
    impl Bar {
        fn get_baz(&self) -> &str {
            &self.baz
        }
        pub fn new(string: String) -> Self {
            Self { baz: string }
        }
    }
}

mod test {
    use crate::bar::Bar;
    use crate::Foo;

    #[test]
    fn should_mock() {
        let bar = Bar::faux();
        let foo = Foo::new(bar);
        assert!(true)
    }
}

Writing the new() function by hand works fine:

use crate::bar::Bar;
use derive_more::Constructor;

fn main() {
    let bar = Bar::new("abc".to_string());

    let foo = Foo::new(bar);
}

#[cfg_attr(test, faux::create)]
// #[derive(Constructor)]
struct Foo {
    bar: Bar,
}

#[cfg_attr(test, faux::methods)]
impl Foo {
    fn new(bar: Bar) -> Self {
        Self { bar }
    }
}

mod bar {

    #[cfg_attr(test, faux::create)]
    pub(crate) struct Bar {
        pub baz: String,
    }

    #[cfg_attr(test, faux::methods)]
    impl Bar {
        fn get_baz(&self) -> &str {
            &self.baz
        }
        pub fn new(string: String) -> Self {
            Self { baz: string }
        }
    }
}

mod test {
    use crate::bar::Bar;
    use crate::Foo;

    #[test]
    fn should_mock() {
        let bar = Bar::faux();
        let foo = Foo::new(bar);
        assert!(true)
    }
}

Do you think it would be possible to add support for #[derive(Constructor)]?

nrxus commented 5 months ago

Looking at how derive_more works I think this addition makes most sense within that crate. I am not sure if you'd be willing to make an issue or PR for them but that would allow for a more generic fix. In particular, the ask wouldn't be for them to support faux but for them to support adding an arbitrary attribute on top of their impl.

I envision something like:

#[cfg_attr(test, faux::create)]
#[derive(Constructor)]
// when in test, make the `impl` block generated by `derive_more::Constructor` forward a custom attribute
#[cfg_attr(test, constructor(forward = "faux::methods"))]
struct Foo {
    bar: Bar,
}

That way neither derive_more nor faux have to directly know about each other while still co-existing.