1
1
use proc_macro2:: TokenStream ;
2
2
use quote:: { quote, ToTokens } ;
3
- use syn:: { parse_str , spanned:: Spanned , Attribute , Ident , ItemFn , PatType } ;
3
+ use syn:: { parse_quote , spanned:: Spanned , Attribute , Ident , ItemFn } ;
4
4
5
- use super :: { options:: Options , utils:: strip_args} ;
5
+ use super :: {
6
+ options:: Options ,
7
+ utils:: { strip_args, Argument } ,
8
+ } ;
6
9
10
+ mod arbitrary;
7
11
mod test_body;
8
12
9
13
/// Generate the modified test function
@@ -20,17 +24,18 @@ pub(super) fn generate(item_fn: ItemFn, options: Options) -> TokenStream {
20
24
let ( mut argless_fn, args) = strip_args ( item_fn) ;
21
25
22
26
let struct_tokens = generate_struct ( & argless_fn. sig . ident , & args) ;
23
- let arb_tokens = generate_arbitrary_impl ( & argless_fn. sig . ident , & args) ;
27
+ let arb_tokens =
28
+ arbitrary:: gen_arbitrary_impl ( & argless_fn. sig . ident , & args) ;
24
29
25
- let struct_and_tokens = quote ! {
30
+ let struct_and_arb = quote ! {
26
31
#struct_tokens
27
32
#arb_tokens
28
33
} ;
29
34
30
35
let new_body = test_body:: body (
31
36
* argless_fn. block ,
32
37
& args,
33
- struct_and_tokens ,
38
+ struct_and_arb ,
34
39
& argless_fn. sig . ident ,
35
40
& argless_fn. sig . output ,
36
41
& options,
@@ -43,12 +48,12 @@ pub(super) fn generate(item_fn: ItemFn, options: Options) -> TokenStream {
43
48
}
44
49
45
50
/// Generate the inner struct that represents the arguments of the function
46
- fn generate_struct ( fn_name : & Ident , args : & [ PatType ] ) -> TokenStream {
51
+ fn generate_struct ( fn_name : & Ident , args : & [ Argument ] ) -> TokenStream {
47
52
let struct_name = struct_name ( fn_name) ;
48
53
49
54
let fields = args. iter ( ) . enumerate ( ) . map ( |( index, arg) | {
50
- let field_name = nth_field_name ( & arg. pat , index) ;
51
- let ty = & arg. ty ;
55
+ let field_name = nth_field_name ( & arg. pat_ty . pat , index) ;
56
+ let ty = & arg. pat_ty . ty ;
52
57
53
58
quote ! { #field_name: #ty, }
54
59
} ) ;
@@ -61,37 +66,6 @@ fn generate_struct(fn_name: &Ident, args: &[PatType]) -> TokenStream {
61
66
}
62
67
}
63
68
64
- /// Generate the arbitrary impl for the struct
65
- fn generate_arbitrary_impl ( fn_name : & Ident , args : & [ PatType ] ) -> TokenStream {
66
- let struct_name = struct_name ( fn_name) ;
67
-
68
- let arg_types = args. iter ( ) . map ( |arg| {
69
- let ty = & arg. ty ;
70
- quote ! ( #ty, )
71
- } ) ;
72
-
73
- let arg_types = quote ! { #( #arg_types) * } ;
74
-
75
- let arg_names = args. iter ( ) . enumerate ( ) . map ( |( index, ty) | {
76
- let name = nth_field_name ( ty. span ( ) , index) ;
77
- quote ! ( #name, )
78
- } ) ;
79
-
80
- let arg_names = quote ! { #( #arg_names) * } ;
81
-
82
- quote ! {
83
- impl :: proptest:: prelude:: Arbitrary for #struct_name {
84
- type Parameters = ( ) ;
85
- type Strategy = :: proptest:: strategy:: Map <:: proptest:: arbitrary:: StrategyFor <( #arg_types) >, fn ( ( #arg_types) ) -> Self >;
86
-
87
- fn arbitrary_with( ( ) : Self :: Parameters ) -> Self :: Strategy {
88
- use :: proptest:: strategy:: Strategy ;
89
- :: proptest:: prelude:: any:: <( #arg_types) >( ) . prop_map( |( #arg_names) | Self { #arg_names } )
90
- }
91
- }
92
- }
93
- }
94
-
95
69
/// Convert the name of a function to the name of a struct representing its args
96
70
///
97
71
/// E.g. `some_function` -> `SomeFunctionArgs`
@@ -111,19 +85,14 @@ fn nth_field_name(span: impl Spanned, index: usize) -> Ident {
111
85
Ident :: new ( & format ! ( "field{index}" ) , span. span ( ) )
112
86
}
113
87
114
- /// I couldn't find a better way to get just the `#[test]` attribute since [`syn::Attribute`]
115
- /// doesn't implement `Parse`
116
88
fn test_attr ( ) -> Attribute {
117
- let mut f: ItemFn = parse_str ( "#[test] fn foo() {}" ) . unwrap ( ) ;
118
- f. attrs . pop ( ) . unwrap ( )
89
+ parse_quote ! { #[ test] }
119
90
}
120
91
121
92
#[ cfg( test) ]
122
93
mod tests {
123
- use quote:: ToTokens ;
124
- use syn:: { parse2, parse_str, ItemStruct } ;
125
-
126
94
use super :: * ;
95
+ use syn:: { parse2, parse_quote, parse_str, ItemStruct } ;
127
96
128
97
/// Simple helper that parses a function, and validates that the struct name and fields are
129
98
/// correct
@@ -180,31 +149,18 @@ mod tests {
180
149
181
150
#[ test]
182
151
fn generates_arbitrary_impl ( ) {
183
- let f: ItemFn = parse_str ( " fn foo(x: i32, y: u8) {}" ) . unwrap ( ) ;
152
+ let f: ItemFn = parse_quote ! { fn foo( x: i32 , y: u8 ) { } } ;
184
153
let ( f, args) = strip_args ( f) ;
185
- let arb = generate_arbitrary_impl ( & f. sig . ident , & args) ;
186
-
187
- let expected = quote ! {
188
- impl :: proptest:: prelude:: Arbitrary for FooArgs {
189
- type Parameters = ( ) ;
190
- type Strategy = :: proptest:: strategy:: Map <:: proptest:: arbitrary:: StrategyFor <( i32 , u8 , ) >, fn ( ( i32 , u8 , ) ) -> Self >;
191
-
192
- fn arbitrary_with( ( ) : Self :: Parameters ) -> Self :: Strategy {
193
- use :: proptest:: strategy:: Strategy ;
194
-
195
- :: proptest:: prelude:: any:: <( i32 , u8 , ) >( ) . prop_map( |( field0, field1, ) | Self { field0, field1, } )
196
- }
197
-
198
- }
199
- } ;
154
+ let arb = arbitrary:: gen_arbitrary_impl ( & f. sig . ident , & args) ;
200
155
201
- assert_eq ! ( arb. to_string ( ) , expected . to_string( ) ) ;
156
+ insta :: assert_snapshot !( arb. to_string( ) ) ;
202
157
}
203
158
}
204
159
205
160
#[ cfg( test) ]
206
161
mod snapshot_tests {
207
162
use super :: * ;
163
+ use syn:: parse_str;
208
164
209
165
macro_rules! snapshot_test {
210
166
( $name: ident) => {
0 commit comments