test_builder/
lib.rs

1#![deny(rustdoc::invalid_rust_codeblocks)]
2#![feature(let_chains)]
3#![feature(proc_macro_diagnostic)]
4#![recursion_limit = "256"]
5#![allow(unused)]
6
7use proc_macro::{Diagnostic, TokenStream};
8use quote::quote;
9use syn::{
10    parse::Parse, parse_macro_input, spanned::Spanned, FnArg, GenericParam, Generics, Ident,
11    ImplItem, ImplItemFn, ItemImpl, PatType, Receiver, ReturnType, TypeParam,
12};
13
14const FUNCTION_TEST_DATA_ATTRIBUTE_NAME: &str = "test_data";
15
16fn get_generics(generics: Generics) -> Vec<TypeParam> {
17    generics
18        .params
19        .into_iter()
20        .filter_map(|generic| {
21            if let GenericParam::Type(function) = generic {
22                Some(function)
23            } else {
24                None
25            }
26        })
27        .collect()
28}
29
30#[derive(Debug)]
31struct TestedFns {
32    generics: Vec<TypeParam>,
33    functions: Vec<ImplItemFn>,
34}
35
36impl Parse for TestedFns {
37    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
38        let tested_impl_block: ItemImpl = input.parse()?;
39        let generics = get_generics(tested_impl_block.generics);
40
41        let functions = tested_impl_block
42            .items
43            .into_iter()
44            .filter_map(|item| {
45                if let ImplItem::Fn(function) = item
46                    && function
47                        .attrs
48                        .iter()
49                        .all(|attr| attr.path().is_ident(FUNCTION_TEST_DATA_ATTRIBUTE_NAME))
50                {
51                    Some(function)
52                } else {
53                    None
54                }
55            })
56            .collect();
57
58        Ok(TestedFns {
59            generics,
60            functions,
61        })
62    }
63}
64
65#[derive(Debug)]
66enum TestedMethod {
67    StaticMethod {
68        name: Ident,
69        generics: Vec<TypeParam>,
70        args: Result<Vec<PatType>, Diagnostic>,
71        return_type: ReturnType,
72    },
73    InstanceMethod {
74        name: Ident,
75        generics: Vec<TypeParam>,
76        self_type: Receiver,
77        args: Result<Vec<PatType>, Diagnostic>,
78        return_type: ReturnType,
79    },
80}
81
82impl From<TestedFns> for Vec<TestedMethod> {
83    fn from(mut value: TestedFns) -> Self {
84        println!("{:#?}", &value);
85        value
86            .functions
87            .into_iter()
88            .map(|function| function.sig)
89            .map(|mut signature| {
90                let name = signature.ident.clone();
91                let mut generics = get_generics(signature.generics.clone());
92                generics.append(&mut value.generics);
93                let return_type = signature.output.clone();
94
95                if let Some(self_type) = signature.receiver() {
96                    TestedMethod::InstanceMethod {
97                        name,
98                        generics,
99                        self_type: self_type.clone(),
100                        args: {
101                            signature.inputs.pop();
102                            signature
103                                .inputs
104                                .clone()
105                                .into_iter()
106                                .map(|arg| {
107                                    if let FnArg::Receiver(_) = arg {
108                                        Err(signature.span().unwrap().error(
109                                            "An instance method cannot have 2 or more self parameters",
110                                        ))
111                                    } else if let FnArg::Typed(arg_type) = arg {
112                                        Ok(arg_type)
113                                    } else {
114                                        unreachable!(
115                                            "Fnarg is either `Receiver` or `Typed`, not something else"
116                                        );
117                                    }
118                                })
119                                .collect()
120                        },
121                        return_type,
122                    }
123                } else {
124                    TestedMethod::StaticMethod {
125                        name,
126                        generics,
127                        args: signature
128                            .inputs
129                            .clone()
130                            .into_iter()
131                            .map(|arg| {
132                                if let FnArg::Typed(arg_type) = arg {
133                                    Ok(arg_type)
134                                } else {
135                                    Err(signature
136                                        .span()
137                                        .unwrap()
138                                        .error("Cannot have a self type in a static method."))
139                                }
140                            })
141                            .collect(),
142                        return_type,
143                    }
144                }
145            })
146            .collect()
147    }
148}
149
150#[proc_macro_attribute]
151pub fn test_builder(attr: TokenStream, item: TokenStream) -> TokenStream {
152    let all_method: Vec<TestedMethod> = parse_macro_input!(item as TestedFns).into();
153
154    println!("{all_method:#?}");
155
156    // let all_expanded = all_method
157    //     .iter()
158    //     .map(|tested_method| match tested_method {
159    //         TestedMethod::StaticMethod {
160    //             name,
161    //             generics,
162    //             args,
163    //             return_type,
164    //         } => {
165    //             let test_method_name = quote! {
166    //                 test_for_ #name _for_type_
167    //             };
168    //         }
169    //         TestedMethod::InstanceMethod {
170    //             name,
171    //             generics,
172    //             self_type,
173    //             args,
174    //             return_type,
175    //         } => todo!(),
176    //     })
177    //     .collect::<Vec<TokenStream>>();
178
179    // let expanded = quote! {};
180
181    // TokenStream::from(expanded)
182    TokenStream::new()
183}
184
185mod sequence;
186
187// // #[cfg(test)]
188// mod tests {
189//     #![allow(unused_imports)]
190//     use crate::{test_builder, SequenceType};
191//     use eager::eager;
192
193//     //compile_error!(
194
195//     //);
196
197//     test_builder!(
198//         @static_method SequenceType => new_arithmetic;
199//         input_types = [
200//             [u8] -> [SequenceType<u8>], [u16] -> [SequenceType<u16>],
201//             [u32] -> [SequenceType<u32>], [u64] -> [SequenceType<u64>],
202//             [u128] -> [SequenceType<u128>], [usize] -> [SequenceType<usize>],
203//             [i8] -> [SequenceType<i8>], [i16] -> [SequenceType<i16>],
204//             [i32] -> [SequenceType<i32>], [i64] -> [SequenceType<i64>],
205//             [i128] -> [SequenceType<i128>], [isize] -> [SequenceType<isize>],
206//             [f32] -> [SequenceType<f32>], [f64] -> [SequenceType<f64>]
207//         ];
208//         [
209//             input_values = [1, 10, 6, 200];
210//             expected_output_values = [
211//                 // 1, 2, 3, 4
212//                 // eager! { instance_of_type!(SequenceType::Arithmetic [1, 10, 6, 200]) }
213//                 SequenceType::Arithmetic { reason: 1 },
214//                 SequenceType::Arithmetic { reason: 10 },
215//                 SequenceType::Arithmetic { reason: 6 },
216//                 SequenceType::Arithmetic { reason: 200 }
217//             ];
218//         ]
219//     );
220// }