@@ -92,6 +92,7 @@ use time::TestExecTime;
9292const ERROR_EXIT_CODE : i32 = 101 ;
9393
9494const SECONDARY_TEST_INVOKER_VAR : & str = "__RUST_TEST_INVOKE" ;
95+ const SECONDARY_TEST_BENCH_BENCHMARKS_VAR : & str = "__RUST_TEST_BENCH_BENCHMARKS" ;
9596
9697// The default console test runner. It accepts the command line
9798// arguments and a vector of test_descs.
@@ -171,18 +172,32 @@ pub fn test_main_static_abort(tests: &[&TestDescAndFn]) {
171172 // will then exit the process.
172173 if let Ok ( name) = env:: var ( SECONDARY_TEST_INVOKER_VAR ) {
173174 env:: remove_var ( SECONDARY_TEST_INVOKER_VAR ) ;
175+
176+ // Convert benchmarks to tests if we're not benchmarking.
177+ let mut tests = tests. iter ( ) . map ( make_owned_test) . collect :: < Vec < _ > > ( ) ;
178+ if env:: var ( SECONDARY_TEST_BENCH_BENCHMARKS_VAR ) . is_ok ( ) {
179+ env:: remove_var ( SECONDARY_TEST_BENCH_BENCHMARKS_VAR ) ;
180+ } else {
181+ tests = convert_benchmarks_to_tests ( tests) ;
182+ } ;
183+
174184 let test = tests
175- . iter ( )
185+ . into_iter ( )
176186 . filter ( |test| test. desc . name . as_slice ( ) == name)
177- . map ( make_owned_test)
178187 . next ( )
179188 . unwrap_or_else ( || panic ! ( "couldn't find a test with the provided name '{name}'" ) ) ;
180189 let TestDescAndFn { desc, testfn } = test;
181- let testfn = match testfn {
182- StaticTestFn ( f) => f,
183- _ => panic ! ( "only static tests are supported" ) ,
184- } ;
185- run_test_in_spawned_subprocess ( desc, Box :: new ( testfn) ) ;
190+ match testfn. into_runnable ( ) {
191+ Runnable :: Test ( runnable_test) => {
192+ if runnable_test. is_dynamic ( ) {
193+ panic ! ( "only static tests are supported" ) ;
194+ }
195+ run_test_in_spawned_subprocess ( desc, runnable_test) ;
196+ }
197+ Runnable :: Bench ( _) => {
198+ panic ! ( "benchmarks should not be executed into child processes" )
199+ }
200+ }
186201 }
187202
188203 let args = env:: args ( ) . collect :: < Vec < _ > > ( ) ;
@@ -234,16 +249,6 @@ impl FilteredTests {
234249 self . tests . push ( ( TestId ( self . next_id ) , test) ) ;
235250 self . next_id += 1 ;
236251 }
237- fn add_bench_as_test (
238- & mut self ,
239- desc : TestDesc ,
240- benchfn : impl Fn ( & mut Bencher ) -> Result < ( ) , String > + Send + ' static ,
241- ) {
242- let testfn = DynTestFn ( Box :: new ( move || {
243- bench:: run_once ( |b| __rust_begin_short_backtrace ( || benchfn ( b) ) )
244- } ) ) ;
245- self . add_test ( desc, testfn) ;
246- }
247252 fn total_len ( & self ) -> usize {
248253 self . tests . len ( ) + self . benches . len ( )
249254 }
@@ -301,14 +306,14 @@ where
301306 if opts. bench_benchmarks {
302307 filtered. add_bench ( desc, DynBenchFn ( benchfn) ) ;
303308 } else {
304- filtered. add_bench_as_test ( desc, benchfn) ;
309+ filtered. add_test ( desc, DynBenchAsTestFn ( benchfn) ) ;
305310 }
306311 }
307312 StaticBenchFn ( benchfn) => {
308313 if opts. bench_benchmarks {
309314 filtered. add_bench ( desc, StaticBenchFn ( benchfn) ) ;
310315 } else {
311- filtered. add_bench_as_test ( desc, benchfn) ;
316+ filtered. add_test ( desc, StaticBenchAsTestFn ( benchfn) ) ;
312317 }
313318 }
314319 testfn => {
@@ -519,12 +524,8 @@ pub fn convert_benchmarks_to_tests(tests: Vec<TestDescAndFn>) -> Vec<TestDescAnd
519524 . into_iter ( )
520525 . map ( |x| {
521526 let testfn = match x. testfn {
522- DynBenchFn ( benchfn) => DynTestFn ( Box :: new ( move || {
523- bench:: run_once ( |b| __rust_begin_short_backtrace ( || benchfn ( b) ) )
524- } ) ) ,
525- StaticBenchFn ( benchfn) => DynTestFn ( Box :: new ( move || {
526- bench:: run_once ( |b| __rust_begin_short_backtrace ( || benchfn ( b) ) )
527- } ) ) ,
527+ DynBenchFn ( benchfn) => DynBenchAsTestFn ( benchfn) ,
528+ StaticBenchFn ( benchfn) => StaticBenchAsTestFn ( benchfn) ,
528529 f => f,
529530 } ;
530531 TestDescAndFn { desc : x. desc , testfn }
@@ -553,99 +554,69 @@ pub fn run_test(
553554 return None ;
554555 }
555556
556- struct TestRunOpts {
557- pub strategy : RunStrategy ,
558- pub nocapture : bool ,
559- pub time : Option < time:: TestTimeOptions > ,
560- }
557+ match testfn. into_runnable ( ) {
558+ Runnable :: Test ( runnable_test) => {
559+ if runnable_test. is_dynamic ( ) {
560+ match strategy {
561+ RunStrategy :: InProcess => ( ) ,
562+ _ => panic ! ( "Cannot run dynamic test fn out-of-process" ) ,
563+ } ;
564+ }
561565
562- fn run_test_inner (
563- id : TestId ,
564- desc : TestDesc ,
565- monitor_ch : Sender < CompletedTest > ,
566- testfn : Box < dyn FnOnce ( ) -> Result < ( ) , String > + Send > ,
567- opts : TestRunOpts ,
568- ) -> Option < thread:: JoinHandle < ( ) > > {
569- let name = desc. name . clone ( ) ;
570-
571- let runtest = move || match opts. strategy {
572- RunStrategy :: InProcess => run_test_in_process (
573- id,
574- desc,
575- opts. nocapture ,
576- opts. time . is_some ( ) ,
577- testfn,
578- monitor_ch,
579- opts. time ,
580- ) ,
581- RunStrategy :: SpawnPrimary => spawn_test_subprocess (
582- id,
583- desc,
584- opts. nocapture ,
585- opts. time . is_some ( ) ,
586- monitor_ch,
587- opts. time ,
588- ) ,
589- } ;
566+ let name = desc. name . clone ( ) ;
567+ let nocapture = opts. nocapture ;
568+ let time_options = opts. time_options ;
569+ let bench_benchmarks = opts. bench_benchmarks ;
570+
571+ let runtest = move || match strategy {
572+ RunStrategy :: InProcess => run_test_in_process (
573+ id,
574+ desc,
575+ nocapture,
576+ time_options. is_some ( ) ,
577+ runnable_test,
578+ monitor_ch,
579+ time_options,
580+ ) ,
581+ RunStrategy :: SpawnPrimary => spawn_test_subprocess (
582+ id,
583+ desc,
584+ nocapture,
585+ time_options. is_some ( ) ,
586+ monitor_ch,
587+ time_options,
588+ bench_benchmarks,
589+ ) ,
590+ } ;
590591
591- // If the platform is single-threaded we're just going to run
592- // the test synchronously, regardless of the concurrency
593- // level.
594- let supports_threads = !cfg ! ( target_os = "emscripten" ) && !cfg ! ( target_family = "wasm" ) ;
595- if supports_threads {
596- let cfg = thread:: Builder :: new ( ) . name ( name. as_slice ( ) . to_owned ( ) ) ;
597- let mut runtest = Arc :: new ( Mutex :: new ( Some ( runtest) ) ) ;
598- let runtest2 = runtest. clone ( ) ;
599- match cfg. spawn ( move || runtest2. lock ( ) . unwrap ( ) . take ( ) . unwrap ( ) ( ) ) {
600- Ok ( handle) => Some ( handle) ,
601- Err ( e) if e. kind ( ) == io:: ErrorKind :: WouldBlock => {
602- // `ErrorKind::WouldBlock` means hitting the thread limit on some
603- // platforms, so run the test synchronously here instead.
604- Arc :: get_mut ( & mut runtest) . unwrap ( ) . get_mut ( ) . unwrap ( ) . take ( ) . unwrap ( ) ( ) ;
605- None
592+ // If the platform is single-threaded we're just going to run
593+ // the test synchronously, regardless of the concurrency
594+ // level.
595+ let supports_threads = !cfg ! ( target_os = "emscripten" ) && !cfg ! ( target_family = "wasm" ) ;
596+ if supports_threads {
597+ let cfg = thread:: Builder :: new ( ) . name ( name. as_slice ( ) . to_owned ( ) ) ;
598+ let mut runtest = Arc :: new ( Mutex :: new ( Some ( runtest) ) ) ;
599+ let runtest2 = runtest. clone ( ) ;
600+ match cfg. spawn ( move || runtest2. lock ( ) . unwrap ( ) . take ( ) . unwrap ( ) ( ) ) {
601+ Ok ( handle) => Some ( handle) ,
602+ Err ( e) if e. kind ( ) == io:: ErrorKind :: WouldBlock => {
603+ // `ErrorKind::WouldBlock` means hitting the thread limit on some
604+ // platforms, so run the test synchronously here instead.
605+ Arc :: get_mut ( & mut runtest) . unwrap ( ) . get_mut ( ) . unwrap ( ) . take ( ) . unwrap ( ) ( ) ;
606+ None
607+ }
608+ Err ( e) => panic ! ( "failed to spawn thread to run test: {e}" ) ,
606609 }
607- Err ( e) => panic ! ( "failed to spawn thread to run test: {e}" ) ,
610+ } else {
611+ runtest ( ) ;
612+ None
608613 }
609- } else {
610- runtest ( ) ;
611- None
612614 }
613- }
614-
615- let test_run_opts =
616- TestRunOpts { strategy, nocapture : opts. nocapture , time : opts. time_options } ;
617-
618- match testfn {
619- DynBenchFn ( benchfn) => {
615+ Runnable :: Bench ( runnable_bench) => {
620616 // Benchmarks aren't expected to panic, so we run them all in-process.
621- crate :: bench :: benchmark ( id, desc, monitor_ch, opts. nocapture , benchfn ) ;
617+ runnable_bench . run ( id, & desc, & monitor_ch, opts. nocapture ) ;
622618 None
623619 }
624- StaticBenchFn ( benchfn) => {
625- // Benchmarks aren't expected to panic, so we run them all in-process.
626- crate :: bench:: benchmark ( id, desc, monitor_ch, opts. nocapture , benchfn) ;
627- None
628- }
629- DynTestFn ( f) => {
630- match strategy {
631- RunStrategy :: InProcess => ( ) ,
632- _ => panic ! ( "Cannot run dynamic test fn out-of-process" ) ,
633- } ;
634- run_test_inner (
635- id,
636- desc,
637- monitor_ch,
638- Box :: new ( move || __rust_begin_short_backtrace ( f) ) ,
639- test_run_opts,
640- )
641- }
642- StaticTestFn ( f) => run_test_inner (
643- id,
644- desc,
645- monitor_ch,
646- Box :: new ( move || __rust_begin_short_backtrace ( f) ) ,
647- test_run_opts,
648- ) ,
649620 }
650621}
651622
@@ -663,7 +634,7 @@ fn run_test_in_process(
663634 desc : TestDesc ,
664635 nocapture : bool ,
665636 report_time : bool ,
666- testfn : Box < dyn FnOnce ( ) -> Result < ( ) , String > + Send > ,
637+ runnable_test : RunnableTest ,
667638 monitor_ch : Sender < CompletedTest > ,
668639 time_opts : Option < time:: TestTimeOptions > ,
669640) {
@@ -675,7 +646,7 @@ fn run_test_in_process(
675646 }
676647
677648 let start = report_time. then ( Instant :: now) ;
678- let result = fold_err ( catch_unwind ( AssertUnwindSafe ( testfn ) ) ) ;
649+ let result = fold_err ( catch_unwind ( AssertUnwindSafe ( || runnable_test . run ( ) ) ) ) ;
679650 let exec_time = start. map ( |start| {
680651 let duration = start. elapsed ( ) ;
681652 TestExecTime ( duration)
@@ -712,13 +683,17 @@ fn spawn_test_subprocess(
712683 report_time : bool ,
713684 monitor_ch : Sender < CompletedTest > ,
714685 time_opts : Option < time:: TestTimeOptions > ,
686+ bench_benchmarks : bool ,
715687) {
716688 let ( result, test_output, exec_time) = ( || {
717689 let args = env:: args ( ) . collect :: < Vec < _ > > ( ) ;
718690 let current_exe = & args[ 0 ] ;
719691
720692 let mut command = Command :: new ( current_exe) ;
721693 command. env ( SECONDARY_TEST_INVOKER_VAR , desc. name . as_slice ( ) ) ;
694+ if bench_benchmarks {
695+ command. env ( SECONDARY_TEST_BENCH_BENCHMARKS_VAR , "1" ) ;
696+ }
722697 if nocapture {
723698 command. stdout ( process:: Stdio :: inherit ( ) ) ;
724699 command. stderr ( process:: Stdio :: inherit ( ) ) ;
@@ -760,10 +735,7 @@ fn spawn_test_subprocess(
760735 monitor_ch. send ( message) . unwrap ( ) ;
761736}
762737
763- fn run_test_in_spawned_subprocess (
764- desc : TestDesc ,
765- testfn : Box < dyn FnOnce ( ) -> Result < ( ) , String > + Send > ,
766- ) -> ! {
738+ fn run_test_in_spawned_subprocess ( desc : TestDesc , runnable_test : RunnableTest ) -> ! {
767739 let builtin_panic_hook = panic:: take_hook ( ) ;
768740 let record_result = Arc :: new ( move |panic_info : Option < & ' _ PanicInfo < ' _ > > | {
769741 let test_result = match panic_info {
@@ -789,7 +761,7 @@ fn run_test_in_spawned_subprocess(
789761 } ) ;
790762 let record_result2 = record_result. clone ( ) ;
791763 panic:: set_hook ( Box :: new ( move |info| record_result2 ( Some ( info) ) ) ) ;
792- if let Err ( message) = testfn ( ) {
764+ if let Err ( message) = runnable_test . run ( ) {
793765 panic ! ( "{}" , message) ;
794766 }
795767 record_result ( None ) ;
0 commit comments