diff options
| author | HampusM <hampus@hampusmat.com> | 2022-11-11 13:42:32 +0100 | 
|---|---|---|
| committer | HampusM <hampus@hampusmat.com> | 2022-11-11 13:42:32 +0100 | 
| commit | 9ed051d56ef14290e532be2716b6f4fe6924b935 (patch) | |
| tree | 1f0976fde21e06b7de9ee269b0d0ed35cbe20585 /macros | |
| parent | 3a0432e690f2ad7af4fb7ccf98ccfba6b3d49705 (diff) | |
test: add unit tests for parsing declare_default_factory macro args
Diffstat (limited to 'macros')
| -rw-r--r-- | macros/Cargo.toml | 1 | ||||
| -rw-r--r-- | macros/src/factory/declare_default_args.rs | 178 | 
2 files changed, 176 insertions, 3 deletions
| diff --git a/macros/Cargo.toml b/macros/Cargo.toml index 730566f..a2ed87b 100644 --- a/macros/Cargo.toml +++ b/macros/Cargo.toml @@ -32,3 +32,4 @@ thiserror = "1.0.37"  syrette = { version = "0.4.1", path = ".." }  mockall = "0.11.1"  pretty_assertions = "1.3.0" +syn = { version = "1.0.96", features = ["full", "extra-traits"] } diff --git a/macros/src/factory/declare_default_args.rs b/macros/src/factory/declare_default_args.rs index d19eba8..0828f9e 100644 --- a/macros/src/factory/declare_default_args.rs +++ b/macros/src/factory/declare_default_args.rs @@ -17,7 +17,7 @@ impl Parse for DeclareDefaultFactoryMacroArgs  {      fn parse(input: syn::parse::ParseStream) -> syn::Result<Self>      { -        let interface = input.parse().unwrap(); +        let interface = input.parse()?;          if !input.peek(Token![,]) {              return Ok(Self { @@ -26,7 +26,7 @@ impl Parse for DeclareDefaultFactoryMacroArgs              });          } -        input.parse::<Token![,]>().unwrap(); +        input.parse::<Token![,]>()?;          let flags = Punctuated::<MacroFlag, Token![,]>::parse_terminated(input)?; @@ -48,9 +48,181 @@ impl Parse for DeclareDefaultFactoryMacroArgs              .collect::<Vec<_>>();          if let Some(dupe_flag_name) = flag_names.iter().find_duplicate() { -            return Err(input.error(format!("Duplicate flag '{}'", dupe_flag_name))); +            return Err(input.error(format!("Duplicate flag '{dupe_flag_name}'")));          }          Ok(Self { interface, flags })      }  } + +#[cfg(test)] +mod tests +{ +    use std::error::Error; + +    use proc_macro2::Span; +    use quote::{format_ident, quote}; +    use syn::token::Dyn; +    use syn::{ +        parse2, +        Path, +        PathArguments, +        PathSegment, +        TraitBound, +        TraitBoundModifier, +        Type, +        TypeParamBound, +        TypeTraitObject, +    }; + +    use super::*; +    use crate::macro_flag::MacroFlag; + +    #[test] +    fn can_parse_with_interface_only() -> Result<(), Box<dyn Error>> +    { +        let input_args = quote! { +            dyn IFoo +        }; + +        let dec_def_fac_args = parse2::<DeclareDefaultFactoryMacroArgs>(input_args)?; + +        assert_eq!( +            dec_def_fac_args.interface, +            Type::TraitObject(TypeTraitObject { +                dyn_token: Some(Dyn::default()), +                bounds: Punctuated::from_iter(vec![TypeParamBound::Trait(TraitBound { +                    paren_token: None, +                    modifier: TraitBoundModifier::None, +                    lifetimes: None, +                    path: Path { +                        leading_colon: None, +                        segments: Punctuated::from_iter(vec![PathSegment { +                            ident: format_ident!("IFoo"), +                            arguments: PathArguments::None +                        }]) +                    } +                })]) +            }) +        ); + +        assert!(dec_def_fac_args.flags.is_empty()); + +        Ok(()) +    } + +    #[test] +    fn can_parse_with_interface_and_single_flag() -> Result<(), Box<dyn Error>> +    { +        let input_args = quote! { +            dyn IBar, threadsafe = true +        }; + +        let dec_def_fac_args = parse2::<DeclareDefaultFactoryMacroArgs>(input_args)?; + +        assert_eq!( +            dec_def_fac_args.interface, +            Type::TraitObject(TypeTraitObject { +                dyn_token: Some(Dyn::default()), +                bounds: Punctuated::from_iter(vec![TypeParamBound::Trait(TraitBound { +                    paren_token: None, +                    modifier: TraitBoundModifier::None, +                    lifetimes: None, +                    path: Path { +                        leading_colon: None, +                        segments: Punctuated::from_iter(vec![PathSegment { +                            ident: format_ident!("IBar"), +                            arguments: PathArguments::None +                        }]) +                    } +                })]) +            }) +        ); + +        assert_eq!( +            dec_def_fac_args.flags, +            Punctuated::from_iter(vec![MacroFlag { +                flag: format_ident!("threadsafe"), +                is_on: syn::LitBool::new(true, Span::call_site()) +            }]) +        ); + +        Ok(()) +    } + +    #[test] +    fn can_parse_with_interface_and_multiple_flags() -> Result<(), Box<dyn Error>> +    { +        let input_args = quote! { +            dyn IBar, threadsafe = true, async = false +        }; + +        let dec_def_fac_args = parse2::<DeclareDefaultFactoryMacroArgs>(input_args)?; + +        assert_eq!( +            dec_def_fac_args.interface, +            Type::TraitObject(TypeTraitObject { +                dyn_token: Some(Dyn::default()), +                bounds: Punctuated::from_iter(vec![TypeParamBound::Trait(TraitBound { +                    paren_token: None, +                    modifier: TraitBoundModifier::None, +                    lifetimes: None, +                    path: Path { +                        leading_colon: None, +                        segments: Punctuated::from_iter(vec![PathSegment { +                            ident: format_ident!("IBar"), +                            arguments: PathArguments::None +                        }]) +                    } +                })]) +            }) +        ); + +        assert_eq!( +            dec_def_fac_args.flags, +            Punctuated::from_iter(vec![ +                MacroFlag { +                    flag: format_ident!("threadsafe"), +                    is_on: syn::LitBool::new(true, Span::call_site()) +                }, +                MacroFlag { +                    flag: format_ident!("async"), +                    is_on: syn::LitBool::new(false, Span::call_site()) +                } +            ]) +        ); + +        Ok(()) +    } + +    #[test] +    fn cannot_parse_with_interface_and_invalid_flag() +    { +        let input_args = quote! { +            dyn IBar, async = true, foo = false +        }; + +        assert!(matches!( +            parse2::<DeclareDefaultFactoryMacroArgs>(input_args), +            Err(_) +        )); +    } + +    #[test] +    fn cannot_parse_with_interface_and_duplicate_flag() +    { +        assert!(matches!( +            parse2::<DeclareDefaultFactoryMacroArgs>(quote! { +                dyn IBar, async = true, threadsafe = false, async = true +            }), +            Err(_) +        )); + +        assert!(matches!( +            parse2::<DeclareDefaultFactoryMacroArgs>(quote! { +                dyn IBar, async = true, threadsafe = false, async = false +            }), +            Err(_) +        )); +    } +} | 
