use macro_tools ::generic_params;
use quote ::quote;
use syn ::parse_quote;
#[ test ]
fn test_decompose_no_trailing_commas()
{
let generics: syn ::Generics = syn ::parse_quote! { < 'a, T: Clone > };
let (_, impl_gen, ty_gen, _) = generic_params ::decompose(&generics);
assert!(!impl_gen.trailing_punct());
assert!(!ty_gen.trailing_punct());
assert_eq!(impl_gen.len(), 2);
let impl_code = quote! { impl< #impl_gen > MyTrait for MyStruct };
let expected_impl = quote! { impl< 'a, T: Clone > MyTrait for MyStruct };
assert_eq!(impl_code.to_string(), expected_impl.to_string());
let type_code = quote! { MyStruct< #ty_gen > };
let expected_type = quote! { MyStruct< 'a, T > };
assert_eq!(type_code.to_string(), expected_type.to_string());
}
#[ test ]
fn test_decompose_empty_generics()
{
let generics: syn ::Generics = syn ::parse_quote! { };
let (_, impl_gen, ty_gen, _) = generic_params ::decompose(&generics);
assert!(impl_gen.is_empty());
assert!(ty_gen.is_empty());
let impl_code = quote! { impl MyTrait for MyStruct };
let type_code = quote! { MyStruct };
assert_eq!(impl_code.to_string(), "impl MyTrait for MyStruct");
assert_eq!(type_code.to_string(), "MyStruct");
}
#[ test ]
fn test_decompose_single_lifetime()
{
let generics: syn ::Generics = syn ::parse_quote! { < 'a > };
let (_, impl_gen, ty_gen, _) = generic_params ::decompose(&generics);
assert!(!impl_gen.trailing_punct());
assert!(!ty_gen.trailing_punct());
assert_eq!(impl_gen.len(), 1);
assert_eq!(ty_gen.len(), 1);
let impl_code = quote! { impl< #impl_gen > MyTrait for MyStruct };
let expected_impl = quote! { impl< 'a > MyTrait for MyStruct };
assert_eq!(impl_code.to_string(), expected_impl.to_string());
}
#[ test ]
fn test_decompose_multiple_lifetimes()
{
let generics: syn ::Generics = syn ::parse_quote! { < 'a, 'b, 'c > };
let (_, impl_gen, ty_gen, _) = generic_params ::decompose(&generics);
assert!(!impl_gen.trailing_punct());
assert!(!ty_gen.trailing_punct());
assert_eq!(impl_gen.len(), 3);
assert_eq!(ty_gen.len(), 3);
let impl_code = quote! { impl< #impl_gen > MyTrait for MyStruct };
let expected_impl = quote! { impl< 'a, 'b, 'c > MyTrait for MyStruct };
assert_eq!(impl_code.to_string(), expected_impl.to_string());
}
#[ test ]
fn test_decompose_mixed_generics()
{
let generics: syn ::Generics = syn ::parse_quote! { < 'a, T, const N: usize > };
let (_, impl_gen, ty_gen, _) = generic_params ::decompose(&generics);
assert!(!impl_gen.trailing_punct());
assert!(!ty_gen.trailing_punct());
let impl_code = quote! { impl< #impl_gen > MyTrait for MyStruct };
let expected_impl = quote! { impl< 'a, T, const N: usize > MyTrait for MyStruct };
assert_eq!(impl_code.to_string(), expected_impl.to_string());
let type_code = quote! { MyStruct< #ty_gen > };
let expected_type = quote! { MyStruct< 'a, T, const N: usize > };
assert_eq!(type_code.to_string(), expected_type.to_string());
}
#[ test ]
fn test_decompose_complex_bounds()
{
let generics: syn ::Generics = syn ::parse_quote! { < T: Clone + Send + 'static > };
let (_, impl_gen, ty_gen, _) = generic_params ::decompose(&generics);
assert!(!impl_gen.trailing_punct());
assert!(!ty_gen.trailing_punct());
let impl_code = quote! { impl< #impl_gen > MyTrait for MyStruct };
assert!(impl_code.to_string().contains("Clone + Send + 'static"));
let type_code = quote! { MyStruct< #ty_gen > };
let expected_type = quote! { MyStruct< T > };
assert_eq!(type_code.to_string(), expected_type.to_string());
}
#[ test ]
fn test_decompose_with_defaults()
{
let generics: syn ::Generics = syn ::parse_quote! { < T = String, const N: usize = 10 > };
let (with_defaults, impl_gen, ty_gen, _) = generic_params ::decompose(&generics);
assert!(with_defaults.trailing_punct());
assert!(!impl_gen.trailing_punct());
assert!(!ty_gen.trailing_punct());
let with_defaults_code = quote! { #with_defaults };
assert!(with_defaults_code.to_string().contains("= String"));
assert!(with_defaults_code.to_string().contains("= 10"));
let impl_code = quote! { impl< #impl_gen > MyTrait for MyStruct };
assert!(!impl_code.to_string().contains("= String"));
assert!(!impl_code.to_string().contains("= 10"));
}
#[ test ]
fn test_decompose_with_where_clause()
{
let item: syn ::ItemStruct = parse_quote! {
struct Test< T, U > where T: Clone, U: Send
{
field: T,
field2: U,
}
};
let generics = item.generics;
let (_, impl_gen, ty_gen, where_clause) = generic_params ::decompose(&generics);
assert!(!impl_gen.trailing_punct());
assert!(!ty_gen.trailing_punct());
assert!(where_clause.trailing_punct());
let where_code = quote! { where #where_clause };
assert!(where_code.to_string().contains("T : Clone"));
assert!(where_code.to_string().contains("U : Send"));
}
#[ test ]
fn test_decompose_single_const_param()
{
let generics: syn ::Generics = syn ::parse_quote! { < const N: usize > };
let (_, impl_gen, ty_gen, _) = generic_params ::decompose(&generics);
assert!(!impl_gen.trailing_punct());
assert!(!ty_gen.trailing_punct());
let impl_code = quote! { impl< #impl_gen > MyTrait for MyStruct };
let expected_impl = quote! { impl< const N: usize > MyTrait for MyStruct };
assert_eq!(impl_code.to_string(), expected_impl.to_string());
}
#[ test ]
fn test_decompose_lifetime_bounds()
{
let generics: syn ::Generics = syn ::parse_quote! { < 'a: 'b, 'b > };
let (_, impl_gen, ty_gen, _) = generic_params ::decompose(&generics);
assert!(!impl_gen.trailing_punct());
assert!(!ty_gen.trailing_punct());
let impl_code = quote! { impl< #impl_gen > MyTrait for MyStruct };
assert!(impl_code.to_string().contains("'a : 'b"));
let type_code = quote! { MyStruct< #ty_gen > };
let expected_type = quote! { MyStruct< 'a, 'b > };
assert_eq!(type_code.to_string(), expected_type.to_string());
}