@@ -149,35 +149,54 @@ pub fn span_derive(attr: TokenStream, input: TokenStream) -> TokenStream {
149149 TokenStream :: from ( output)
150150}
151151
152- /// Proc macro to automatically generate tests for all .desc files in examples/core/
152+ /// Proc macro to automatically generate tests for all .desc files in a specified folder
153+ /// Usage: generate_desc_tests!(folder_path, should_panic)
154+ /// Example: generate_desc_tests!("examples/core", false)
155+ /// Example: generate_desc_tests!("examples/error-examples", true)
153156#[ proc_macro]
154- pub fn generate_desc_tests ( _input : TokenStream ) -> TokenStream {
155- // Use include_dir! as a fallback for compile-time file inclusion
156- // This ensures the files are available even if the directory structure changes
157- let dir = include_dir:: include_dir!( "$CARGO_MANIFEST_DIR/../examples/core" ) ;
157+ pub fn generate_desc_tests ( input : TokenStream ) -> TokenStream {
158+ let input_str = input. to_string ( ) ;
159+ let parts: Vec < & str > = input_str. split ( ',' ) . map ( |s| s. trim ( ) ) . collect ( ) ;
160+
161+ if parts. len ( ) != 2 {
162+ panic ! (
163+ "generate_desc_tests! macro expects exactly 2 parameters: folder_path and should_panic"
164+ ) ;
165+ }
166+
167+ let folder_path = parts[ 0 ] . trim_matches ( '"' ) ;
168+ let should_panic = parts[ 1 ] . trim ( ) == "true" ;
169+
170+ // Since include_dir! doesn't support dynamic paths, we need to handle specific folders
171+ let dir = match folder_path {
172+ "examples/core" => include_dir:: include_dir!( "$CARGO_MANIFEST_DIR/../examples/core" ) ,
173+ "examples/error-examples" => include_dir:: include_dir!( "$CARGO_MANIFEST_DIR/../examples/error-examples" ) ,
174+ _ => panic ! ( "Unsupported folder path: {}. Currently supported: examples/core, examples/error-examples" , folder_path) ,
175+ } ;
158176
159177 let mut test_functions = Vec :: new ( ) ;
160178
161179 for file in dir. files ( ) {
162180 if let Some ( extension) = file. path ( ) . extension ( ) {
163181 if extension == "desc" {
164- let file_name = file
182+ let file_stem = file
165183 . path ( )
166184 . file_stem ( )
167185 . and_then ( |s| s. to_str ( ) )
168186 . unwrap_or ( "unknown" ) ;
169187
170188 // Use the original file path from the filesystem, not the embedded path
171189 let full_path = format ! (
172- "examples/core/{}" ,
190+ "{}/{}" ,
191+ folder_path,
173192 file. path( )
174193 . file_name( )
175194 . and_then( |s| s. to_str( ) )
176195 . unwrap_or( "unknown.desc" )
177196 ) ;
178197
179198 // Convert file name to valid Rust identifier
180- let test_name = file_name . replace ( "-" , "_" ) . replace ( "." , "_" ) ;
199+ let test_name = file_stem . replace ( "-" , "_" ) . replace ( "." , "_" ) ;
181200
182201 // Handle Rust keywords and match existing snapshot names
183202 let test_name = match test_name. as_str ( ) {
@@ -206,14 +225,24 @@ pub fn generate_desc_tests(_input: TokenStream) -> TokenStream {
206225 let test_name_ident = Ident :: new ( & test_name, proc_macro2:: Span :: call_site ( ) ) ;
207226 let file_path_lit = proc_macro2:: Literal :: string ( & full_path) ;
208227
209- test_functions. push ( quote ! {
210- #[ test]
211- fn #test_name_ident( ) -> Result <( ) , descend:: error:: ErrorReported > {
212- let output = descend:: compile( #file_path_lit) ?. 0 ;
213- insta:: assert_snapshot!( output) ;
214- Ok ( ( ) )
215- }
216- } ) ;
228+ if should_panic {
229+ test_functions. push ( quote ! {
230+ #[ test]
231+ #[ should_panic]
232+ fn #test_name_ident( ) {
233+ descend:: compile( #file_path_lit) . unwrap( ) ;
234+ }
235+ } ) ;
236+ } else {
237+ test_functions. push ( quote ! {
238+ #[ test]
239+ fn #test_name_ident( ) -> Result <( ) , descend:: error:: ErrorReported > {
240+ let output = descend:: compile( #file_path_lit) ?. 0 ;
241+ insta:: assert_snapshot!( output) ;
242+ Ok ( ( ) )
243+ }
244+ } ) ;
245+ }
217246 }
218247 }
219248 }
0 commit comments