aboutsummaryrefslogtreecommitdiff
path: root/macros
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2022-11-11 13:42:32 +0100
committerHampusM <hampus@hampusmat.com>2022-11-11 13:42:32 +0100
commit9ed051d56ef14290e532be2716b6f4fe6924b935 (patch)
tree1f0976fde21e06b7de9ee269b0d0ed35cbe20585 /macros
parent3a0432e690f2ad7af4fb7ccf98ccfba6b3d49705 (diff)
test: add unit tests for parsing declare_default_factory macro args
Diffstat (limited to 'macros')
-rw-r--r--macros/Cargo.toml1
-rw-r--r--macros/src/factory/declare_default_args.rs178
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(_)
+ ));
+ }
+}