From f694453a097d9efde81943309813542877d1b2ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Medina?= Date: Thu, 8 Sep 2022 20:50:47 -0700 Subject: [PATCH] allow `::` as generic arguments in `impl` signature also support multiple `impl` blocks for the same struct in the same module --- CHANGELOG.md | 11 +++++++++++ Cargo.toml | 4 ++-- faux_macros/Cargo.toml | 3 ++- faux_macros/src/methods.rs | 16 +++++++++++----- faux_macros/src/methods/morphed.rs | 2 +- tests/generic_struct.rs | 12 ++++++++++++ 6 files changed, 39 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 751702f..b4f8484 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ # CHANGELOG +## v0.1.8 +* Fix issue where a type with `::` could not be used as a generic + argument in an `impl` signature. +* Support multiple `impl` blocks for the same struct in the same + module + * This relies on the uniqueness of a uuid v4 which is technically + not guaranteed to be unique but pretty darn likely to be. + +### Minor Breaking Change +* Bump MSRV to 1.56 + ## v0.1.7 * Don't change the parameter names in mocked methods if their pattern diff --git a/Cargo.toml b/Cargo.toml index 7dd63ed..ff4ccd4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "faux" -version = "0.1.7" +version = "0.1.8" authors = ["Andres "] license = "MIT" description = "A library to mock structs" @@ -12,7 +12,7 @@ readme = "README.md" rust-version = "1.56" [dependencies] -faux_macros = { path = "faux_macros", version = "0.1.7" } +faux_macros = { path = "faux_macros", version = "0.1.8" } paste = "1.0.4" [dev-dependencies] diff --git a/faux_macros/Cargo.toml b/faux_macros/Cargo.toml index aee7aca..14b868a 100644 --- a/faux_macros/Cargo.toml +++ b/faux_macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "faux_macros" -version = "0.1.7" +version = "0.1.8" authors = ["Andres "] edition = "2021" license = "MIT" @@ -15,6 +15,7 @@ syn = { version = "1.0.58", features = ["full", "extra-traits"] } quote = "1.0.8" proc-macro2 = "1.0.24" darling = "0.14" +uuid = { version = "0.8.2", features = ["v4"] } [dev-dependencies] faux = { path = "../" } diff --git a/faux_macros/src/methods.rs b/faux_macros/src/methods.rs index 6c1fbdc..8814f28 100644 --- a/faux_macros/src/methods.rs +++ b/faux_macros/src/methods.rs @@ -5,6 +5,7 @@ use crate::{create, self_type::SelfType}; use darling::FromMeta; use morphed::Signature; use quote::quote; +use syn::PathArguments; #[derive(Default, FromMeta)] #[darling(default)] @@ -131,21 +132,23 @@ impl From for proc_macro::TokenStream { real, morphed, whens, - real_ty, + mut real_ty, morphed_ty, } = mockable; // create an identifier for the mod containing the real implementation // this is necessary until we are allowed to introduce type aliases within impl blocks let mod_ident = { + let uuid = uuid::Uuid::new_v4(); let ident = &real_ty.path.segments.last().unwrap().ident; syn::Ident::new( &match &real.trait_ { - None => format!("_faux_real_impl_{}", ident), + None => format!("_faux_real_impl_{}_{}", ident, uuid.to_simple()), Some((_, trait_, _)) => format!( - "_faux_real_impl_{}_{}", + "_faux_real_impl_{}_{}_{}", ident, - trait_.segments.last().unwrap().ident + trait_.segments.last().unwrap().ident, + uuid.to_simple() ), }, proc_macro2::Span::call_site(), @@ -164,6 +167,8 @@ impl From for proc_macro::TokenStream { let alias = { let mut path_to_ty = morphed_ty.path.segments; let path_to_real_from_alias_mod = { + // let mut real_ty = real_ty.clone(); + real_ty.path.segments.last_mut().unwrap().arguments = PathArguments::None; let first_path = &real_ty.path.segments.first().unwrap().ident; if *first_path == syn::Ident::new("crate", first_path.span()) { // if it is an absolute position then no need to "super" up to find it @@ -186,11 +191,12 @@ impl From for proc_macro::TokenStream { quote! { pub(#(#supers)::*) } }; let pathless_type = path_to_ty.pop().unwrap(); + let ident = &pathless_type.value().ident; quote! { //do not warn for things like Foo = RealFoo #[allow(non_camel_case_types)] #[allow(clippy::builtin_type_shadow)] - #pub_supers type #pathless_type = #path_to_real_from_alias_mod; + #pub_supers use #path_to_real_from_alias_mod as #ident; } }; diff --git a/faux_macros/src/methods/morphed.rs b/faux_macros/src/methods/morphed.rs index 339c417..9777805 100644 --- a/faux_macros/src/methods/morphed.rs +++ b/faux_macros/src/methods/morphed.rs @@ -239,7 +239,7 @@ impl<'a> Signature<'a> { self.method_data .as_ref() .filter(|m| !m.is_private) - .map(|m| m.create_when(self.output, &self.name)) + .map(|m| m.create_when(self.output, self.name)) } fn wrap_self( diff --git a/tests/generic_struct.rs b/tests/generic_struct.rs index d0fa6d9..3b59f10 100644 --- a/tests/generic_struct.rs +++ b/tests/generic_struct.rs @@ -28,6 +28,13 @@ impl<'a, T: std::fmt::Debug, R> Generic<'a, T, R> { } } +#[faux::methods] +impl<'a, R> Generic<'a, i32, R> { + pub fn get_i32(&self) -> i32 { + self.a + } +} + #[test] fn real() { let hello = "hello".to_string(); @@ -35,6 +42,7 @@ fn real() { assert_eq!(real.get(), &20); assert_eq!(real.get_ref(), &10); assert_eq!(real.life_ref(), &hello); + assert_eq!(real.get_i32(), 10); } #[test] @@ -49,4 +57,8 @@ fn mocked() { unsafe { faux::when!(fake.life_ref).then_unchecked(|_| &2) } assert_eq!(fake.life_ref(), &2); + + let mut int_fake: Generic = Generic::faux(); + faux::when!(int_fake.get_i32()).then_return(4); + assert_eq!(int_fake.get_i32(), 4); }