use darling::{ util::{Override, SpannedValue}, FromAttributes, }; use quote::quote; use syn::{parse::Parser, Attribute, Lit}; use Override::{Explicit, Inherit}; #[derive(FromAttributes, Default)] #[darling(attributes(test_attr))] struct SpannedValueOverPrimitive { string: SpannedValue, optional_int: Option>, override_literal: Override>, optional_override_char: Option>>, } macro_rules! test_cases { ($( $name:ident : #[test_attr($($tok:tt)*)] => $result:ident $( { string: $string:expr, int: $int:expr, literal: $literal:pat, char: $char:expr, } )?; )*) => {$( #[test] fn $name() { let quoted = quote! { #[test_attr( $($tok)* )] }; let attrs = Attribute::parse_outer .parse2(quoted) .expect("failed to parse tokens as an attribute list"); let result = SpannedValueOverPrimitive::from_attributes(&attrs); test_case_result!(result, $result $({ string: $string, int: $int, literal: $literal, char: $char, })?); } )*} } macro_rules! test_case_result { ($value:expr, Err) => { assert!($value.is_err()) }; ($value:expr, Ok{ string: $string:expr, int: $int:expr, literal: $literal:pat, char: $char:expr, }) => {{ let out = $value.expect("failed to parse with from_attributes"); assert_eq!(out.string.as_ref(), $string); assert_eq!(out.optional_int.map(|i| *i.as_ref()), $int); assert!(matches!(out.override_literal, $literal)); assert_eq!( out.optional_override_char.map(|c| match c { Inherit => Inherit, Explicit(value) => Explicit(*value.as_ref()), }), $char ) }}; } test_cases! { basic: #[test_attr( string = "Hello", optional_int = 23, override_literal = "foo", optional_override_char = 'c' )] => Ok{ string: "Hello", int: Some(23), literal: Explicit(_), char: Some(Override::Explicit('c')), }; omit_optionals: #[test_attr( string = "Hello", override_literal = "foo", )] => Ok{ string: "Hello", int: None, literal: Explicit(_), char: None, }; omit_overrides: #[test_attr( string = "Hello", override_literal, optional_override_char, )] => Ok{ string: "Hello", int: None, literal: Inherit, char: Some(Inherit), }; }