66//! benchmarks themselves) should be done via the `#[test]` and
77//! `#[bench]` attributes.
88//!
9- //! See the [Testing Chapter](../book/ch11-00-testing.html) of the book for more details.
9+ //! See the [Testing Chapter](../book/ch11-00-testing.html) of the book for more
10+ //! details.
1011
1112// Currently, not much of this is meant for users. It is intended to
1213// support the simplest interface possible for representing and
@@ -76,6 +77,7 @@ mod types;
7677#[ cfg( test) ]
7778mod tests;
7879
80+ use core:: any:: Any ;
7981use event:: { CompletedTest , TestEvent } ;
8082use helpers:: concurrency:: get_concurrency;
8183use helpers:: exit_code:: get_exit_code;
@@ -175,17 +177,20 @@ fn make_owned_test(test: &&TestDescAndFn) -> TestDescAndFn {
175177 }
176178}
177179
178- /// Invoked when unit tests terminate. Should panic if the unit
179- /// Tests is considered a failure. By default, invokes `report()`
180- /// and checks for a `0` result.
181- pub fn assert_test_result < T : Termination > ( result : T ) {
180+ /// Invoked when unit tests terminate. Returns `Result::Err` if the test is
181+ /// considered a failure. By default, invokes `report() and checks for a `0 `
182+ /// result.
183+ pub fn assert_test_result < T : Termination > ( result : T ) -> Result < ( ) , String > {
182184 let code = result. report ( ) . to_i32 ( ) ;
183- assert_eq ! (
184- code, 0 ,
185- "the test returned a termination value with a non-zero status code ({}) \
186- which indicates a failure",
187- code
188- ) ;
185+ if code == 0 {
186+ Ok ( ( ) )
187+ } else {
188+ Err ( format ! (
189+ "the test returned a termination value with a non-zero status code \
190+ ({}) which indicates a failure",
191+ code
192+ ) )
193+ }
189194}
190195
191196pub fn run_tests < F > (
@@ -478,7 +483,7 @@ pub fn run_test(
478483 id : TestId ,
479484 desc : TestDesc ,
480485 monitor_ch : Sender < CompletedTest > ,
481- testfn : Box < dyn FnOnce ( ) + Send > ,
486+ testfn : Box < dyn FnOnce ( ) -> Result < ( ) , String > + Send > ,
482487 opts : TestRunOpts ,
483488 ) -> Option < thread:: JoinHandle < ( ) > > {
484489 let concurrency = opts. concurrency ;
@@ -567,19 +572,19 @@ pub fn run_test(
567572
568573/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`.
569574#[ inline( never) ]
570- fn __rust_begin_short_backtrace < F : FnOnce ( ) > ( f : F ) {
571- f ( ) ;
575+ fn __rust_begin_short_backtrace < T , F : FnOnce ( ) -> T > ( f : F ) -> T {
576+ let result = f ( ) ;
572577
573578 // prevent this frame from being tail-call optimised away
574- black_box ( ( ) ) ;
579+ black_box ( result )
575580}
576581
577582fn run_test_in_process (
578583 id : TestId ,
579584 desc : TestDesc ,
580585 nocapture : bool ,
581586 report_time : bool ,
582- testfn : Box < dyn FnOnce ( ) + Send > ,
587+ testfn : Box < dyn FnOnce ( ) -> Result < ( ) , String > + Send > ,
583588 monitor_ch : Sender < CompletedTest > ,
584589 time_opts : Option < time:: TestTimeOptions > ,
585590) {
@@ -591,7 +596,7 @@ fn run_test_in_process(
591596 }
592597
593598 let start = report_time. then ( Instant :: now) ;
594- let result = catch_unwind ( AssertUnwindSafe ( testfn) ) ;
599+ let result = fold_err ( catch_unwind ( AssertUnwindSafe ( testfn) ) ) ;
595600 let exec_time = start. map ( |start| {
596601 let duration = start. elapsed ( ) ;
597602 TestExecTime ( duration)
@@ -608,6 +613,19 @@ fn run_test_in_process(
608613 monitor_ch. send ( message) . unwrap ( ) ;
609614}
610615
616+ fn fold_err < T , E > (
617+ result : Result < Result < T , E > , Box < dyn Any + Send > > ,
618+ ) -> Result < T , Box < dyn Any + Send > >
619+ where
620+ E : Send + ' static ,
621+ {
622+ match result {
623+ Ok ( Err ( e) ) => Err ( Box :: new ( e) ) ,
624+ Ok ( Ok ( v) ) => Ok ( v) ,
625+ Err ( e) => Err ( e) ,
626+ }
627+ }
628+
611629fn spawn_test_subprocess (
612630 id : TestId ,
613631 desc : TestDesc ,
@@ -663,7 +681,10 @@ fn spawn_test_subprocess(
663681 monitor_ch. send ( message) . unwrap ( ) ;
664682}
665683
666- fn run_test_in_spawned_subprocess ( desc : TestDesc , testfn : Box < dyn FnOnce ( ) + Send > ) -> ! {
684+ fn run_test_in_spawned_subprocess (
685+ desc : TestDesc ,
686+ testfn : Box < dyn FnOnce ( ) -> Result < ( ) , String > + Send > ,
687+ ) -> ! {
667688 let builtin_panic_hook = panic:: take_hook ( ) ;
668689 let record_result = Arc :: new ( move |panic_info : Option < & ' _ PanicInfo < ' _ > > | {
669690 let test_result = match panic_info {
@@ -689,7 +710,9 @@ fn run_test_in_spawned_subprocess(desc: TestDesc, testfn: Box<dyn FnOnce() + Sen
689710 } ) ;
690711 let record_result2 = record_result. clone ( ) ;
691712 panic:: set_hook ( Box :: new ( move |info| record_result2 ( Some ( & info) ) ) ) ;
692- testfn ( ) ;
713+ if let Err ( message) = testfn ( ) {
714+ panic ! ( "{}" , message) ;
715+ }
693716 record_result ( None ) ;
694717 unreachable ! ( "panic=abort callback should have exited the process" )
695718}
0 commit comments