@@ -132,7 +132,8 @@ pub fn run_tests(config: Config) -> Result<()> {
132
132
} ;
133
133
134
134
run_tests_generic (
135
- config,
135
+ vec ! [ config] ,
136
+ std:: thread:: available_parallelism ( ) . unwrap ( ) ,
136
137
args,
137
138
default_file_filter,
138
139
default_per_file_config,
@@ -142,7 +143,7 @@ pub fn run_tests(config: Config) -> Result<()> {
142
143
143
144
/// The filter used by `run_tests` to only run on `.rs` files
144
145
/// and those specified in the command line args.
145
- pub fn default_file_filter ( path : & Path , args : & Args ) -> bool {
146
+ pub fn default_file_filter ( path : & Path , args : & Args , _config : & Config ) -> bool {
146
147
path. extension ( ) . is_some_and ( |ext| ext == "rs" ) && default_filter_by_arg ( path, args)
147
148
}
148
149
@@ -156,13 +157,11 @@ pub fn default_filter_by_arg(path: &Path, args: &Args) -> bool {
156
157
}
157
158
158
159
/// The default per-file config used by `run_tests`.
159
- pub fn default_per_file_config ( config : & Config , path : & Path ) -> Option < Config > {
160
- let mut config = config. clone ( ) ;
160
+ pub fn default_per_file_config ( config : & mut Config , file_contents : & [ u8 ] ) {
161
161
// Heuristic:
162
162
// * if the file contains `#[test]`, automatically pass `--cfg test`.
163
163
// * if the file does not contain `fn main()` or `#[start]`, automatically pass `--crate-type=lib`.
164
164
// This avoids having to spam `fn main() {}` in almost every test.
165
- let file_contents = std:: fs:: read ( path) . unwrap ( ) ;
166
165
if file_contents. find ( b"#[proc_macro" ) . is_some ( ) {
167
166
config. program . args . push ( "--crate-type=proc-macro" . into ( ) )
168
167
} else if file_contents. find ( b"#[test]" ) . is_some ( ) {
@@ -172,7 +171,6 @@ pub fn default_per_file_config(config: &Config, path: &Path) -> Option<Config> {
172
171
{
173
172
config. program . args . push ( "--crate-type=lib" . into ( ) ) ;
174
173
}
175
- Some ( config)
176
174
}
177
175
178
176
/// Create a command for running a single file, with the settings from the `config` argument.
@@ -220,24 +218,29 @@ struct TestRun {
220
218
221
219
/// A version of `run_tests` that allows more fine-grained control over running tests.
222
220
pub fn run_tests_generic (
223
- mut config : Config ,
221
+ mut configs : Vec < Config > ,
222
+ num_threads : NonZeroUsize ,
224
223
args : Args ,
225
- file_filter : impl Fn ( & Path , & Args ) -> bool + Sync ,
226
- per_file_config : impl Fn ( & Config , & Path ) -> Option < Config > + Sync ,
224
+ file_filter : impl Fn ( & Path , & Args , & Config ) -> bool + Sync ,
225
+ per_file_config : impl Fn ( & mut Config , & [ u8 ] ) + Sync ,
227
226
status_emitter : impl StatusEmitter + Send ,
228
227
) -> Result < ( ) > {
229
- config. fill_host_and_target ( ) ?;
228
+ for config in & mut configs {
229
+ config. fill_host_and_target ( ) ?;
230
+ }
230
231
231
232
let build_manager = BuildManager :: new ( & status_emitter) ;
232
233
233
234
let mut results = vec ! [ ] ;
234
235
235
236
run_and_collect (
236
- config . num_test_threads . get ( ) ,
237
+ num_threads ,
237
238
|submit| {
238
239
let mut todo = VecDeque :: new ( ) ;
239
- todo. push_back ( config. root_dir . clone ( ) ) ;
240
- while let Some ( path) = todo. pop_front ( ) {
240
+ for config in configs {
241
+ todo. push_back ( ( config. root_dir . clone ( ) , config) ) ;
242
+ }
243
+ while let Some ( ( path, config) ) = todo. pop_front ( ) {
241
244
if path. is_dir ( ) {
242
245
if path. file_name ( ) . unwrap ( ) == "auxiliary" {
243
246
continue ;
@@ -250,28 +253,22 @@ pub fn run_tests_generic(
250
253
. unwrap ( ) ;
251
254
entries. sort_by_key ( |e| e. file_name ( ) ) ;
252
255
for entry in entries {
253
- todo. push_back ( entry. path ( ) ) ;
256
+ todo. push_back ( ( entry. path ( ) , config . clone ( ) ) ) ;
254
257
}
255
- } else if file_filter ( & path, & args) {
258
+ } else if file_filter ( & path, & args, & config ) {
256
259
let status = status_emitter. register_test ( path) ;
257
260
// Forward .rs files to the test workers.
258
- submit. send ( status) . unwrap ( ) ;
261
+ submit. send ( ( status, config ) ) . unwrap ( ) ;
259
262
}
260
263
}
261
264
} ,
262
265
|receive, finished_files_sender| -> Result < ( ) > {
263
- for status in receive {
266
+ for ( status, mut config ) in receive {
264
267
let path = status. path ( ) ;
265
- let maybe_config;
266
- let config = match per_file_config ( & config, path) {
267
- None => & config,
268
- Some ( config) => {
269
- maybe_config = config;
270
- & maybe_config
271
- }
272
- } ;
268
+ let file_contents = std:: fs:: read ( path) . unwrap ( ) ;
269
+ per_file_config ( & mut config, & file_contents) ;
273
270
let result = match std:: panic:: catch_unwind ( || {
274
- parse_and_test_file ( & build_manager, & status, config)
271
+ parse_and_test_file ( & build_manager, & status, & config, file_contents )
275
272
} ) {
276
273
Ok ( Ok ( res) ) => res,
277
274
Ok ( Err ( err) ) => {
@@ -351,7 +348,7 @@ pub fn run_tests_generic(
351
348
/// A generic multithreaded runner that has a thread for producing work,
352
349
/// a thread for collecting work, and `num_threads` threads for doing the work.
353
350
pub fn run_and_collect < SUBMISSION : Send , RESULT : Send > (
354
- num_threads : usize ,
351
+ num_threads : NonZeroUsize ,
355
352
submitter : impl FnOnce ( Sender < SUBMISSION > ) + Send ,
356
353
runner : impl Sync + Fn ( & Receiver < SUBMISSION > , Sender < RESULT > ) -> Result < ( ) > ,
357
354
collector : impl FnOnce ( Receiver < RESULT > ) + Send ,
@@ -373,7 +370,7 @@ pub fn run_and_collect<SUBMISSION: Send, RESULT: Send>(
373
370
let mut threads = vec ! [ ] ;
374
371
375
372
// Create N worker threads that receive files to test.
376
- for _ in 0 ..num_threads {
373
+ for _ in 0 ..num_threads. get ( ) {
377
374
let finished_files_sender = finished_files_sender. clone ( ) ;
378
375
threads. push ( s. spawn ( || runner ( & receive, finished_files_sender) ) ) ;
379
376
}
@@ -389,8 +386,9 @@ fn parse_and_test_file(
389
386
build_manager : & BuildManager < ' _ > ,
390
387
status : & dyn TestStatus ,
391
388
config : & Config ,
389
+ file_contents : Vec < u8 > ,
392
390
) -> Result < Vec < TestRun > , Errored > {
393
- let comments = parse_comments_in_file ( status . path ( ) ) ?;
391
+ let comments = parse_comments ( & file_contents ) ?;
394
392
// Run the test for all revisions
395
393
let revisions = comments
396
394
. revisions
@@ -413,19 +411,14 @@ fn parse_and_test_file(
413
411
. collect ( ) )
414
412
}
415
413
416
- fn parse_comments_in_file ( path : & Path ) -> Result < Comments , Errored > {
417
- match Comments :: parse_file ( path ) {
418
- Ok ( Ok ( comments) ) => Ok ( comments) ,
419
- Ok ( Err ( errors) ) => Err ( Errored {
414
+ fn parse_comments ( file_contents : & [ u8 ] ) -> Result < Comments , Errored > {
415
+ match Comments :: parse ( file_contents ) {
416
+ Ok ( comments) => Ok ( comments) ,
417
+ Err ( errors) => Err ( Errored {
420
418
command : Command :: new ( "parse comments" ) ,
421
419
errors,
422
420
stderr : vec ! [ ] ,
423
421
} ) ,
424
- Err ( err) => Err ( Errored {
425
- command : Command :: new ( "parse comments" ) ,
426
- errors : vec ! [ ] ,
427
- stderr : format ! ( "{err:?}" ) . into ( ) ,
428
- } ) ,
429
422
}
430
423
}
431
424
@@ -467,7 +460,8 @@ fn build_aux(
467
460
config : & Config ,
468
461
build_manager : & BuildManager < ' _ > ,
469
462
) -> std:: result:: Result < Vec < OsString > , Errored > {
470
- let comments = parse_comments_in_file ( aux_file) ?;
463
+ let file_contents = std:: fs:: read ( aux_file) . unwrap ( ) ;
464
+ let comments = parse_comments ( & file_contents) ?;
471
465
assert_eq ! (
472
466
comments. revisions, None ,
473
467
"aux builds cannot specify revisions"
@@ -495,7 +489,7 @@ fn build_aux(
495
489
}
496
490
} ) ;
497
491
498
- let mut config = default_per_file_config ( & config, aux_file ) . unwrap ( ) ;
492
+ default_per_file_config ( & mut config, & file_contents ) ;
499
493
500
494
// Put aux builds into a separate directory per path so that multiple aux files
501
495
// from different directories (but with the same file name) don't collide.
@@ -615,7 +609,12 @@ impl dyn TestStatus {
615
609
. stdout ( Stdio :: piped ( ) )
616
610
. stdin ( Stdio :: null ( ) )
617
611
. spawn ( )
618
- . unwrap_or_else ( |err| panic ! ( "could not execute {cmd:?}: {err}" ) ) ;
612
+ . unwrap_or_else ( |err| {
613
+ panic ! (
614
+ "could not spawn `{:?}` as a process: {err}" ,
615
+ cmd. get_program( )
616
+ )
617
+ } ) ;
619
618
620
619
let stdout = ReadHelper :: from ( child. stdout . take ( ) . unwrap ( ) ) ;
621
620
let mut stderr = ReadHelper :: from ( child. stderr . take ( ) . unwrap ( ) ) ;
0 commit comments