@@ -83,14 +83,14 @@ impl Harness<StateArgs> {
8383pub struct StateParsed {
8484 start : std:: time:: Instant ,
8585 opts : libtest_lexarg:: TestOpts ,
86- notifier : Box < dyn notify:: Notifier > ,
86+ notifier : notify:: ArcNotifier ,
8787}
8888impl HarnessState for StateParsed { }
8989impl sealed:: _HarnessState_is_Sealed for StateParsed { }
9090
9191impl Harness < StateParsed > {
9292 pub fn discover (
93- mut self ,
93+ self ,
9494 cases : impl IntoIterator < Item = impl Case + ' static > ,
9595 ) -> std:: io:: Result < Harness < StateDiscovered > > {
9696 self . state . notifier . notify (
@@ -144,22 +144,22 @@ impl Harness<StateParsed> {
144144pub struct StateDiscovered {
145145 start : std:: time:: Instant ,
146146 opts : libtest_lexarg:: TestOpts ,
147- notifier : Box < dyn notify:: Notifier > ,
147+ notifier : notify:: ArcNotifier ,
148148 cases : Vec < Box < dyn Case > > ,
149149}
150150impl HarnessState for StateDiscovered { }
151151impl sealed:: _HarnessState_is_Sealed for StateDiscovered { }
152152
153153impl Harness < StateDiscovered > {
154- pub fn run ( mut self ) -> std:: io:: Result < bool > {
154+ pub fn run ( self ) -> std:: io:: Result < bool > {
155155 if self . state . opts . list {
156156 Ok ( true )
157157 } else {
158158 run (
159159 & self . state . start ,
160160 & self . state . opts ,
161161 self . state . cases ,
162- self . state . notifier . as_mut ( ) ,
162+ self . state . notifier ,
163163 )
164164 }
165165 }
@@ -252,16 +252,16 @@ fn parse<'p>(parser: &mut cli::Parser<'p>) -> Result<libtest_lexarg::TestOpts, c
252252 Ok ( opts)
253253}
254254
255- fn notifier ( opts : & libtest_lexarg:: TestOpts ) -> Box < dyn notify:: Notifier > {
255+ fn notifier ( opts : & libtest_lexarg:: TestOpts ) -> notify:: ArcNotifier {
256256 #[ cfg( feature = "color" ) ]
257257 let stdout = anstream:: stdout ( ) ;
258258 #[ cfg( not( feature = "color" ) ) ]
259259 let stdout = std:: io:: stdout ( ) ;
260260 match opts. format {
261- OutputFormat :: Json => Box :: new ( notify:: JsonNotifier :: new ( stdout) ) ,
262- _ if opts. list => Box :: new ( notify:: TerseListNotifier :: new ( stdout) ) ,
263- OutputFormat :: Pretty => Box :: new ( notify:: PrettyRunNotifier :: new ( stdout) ) ,
264- OutputFormat :: Terse => Box :: new ( notify:: TerseRunNotifier :: new ( stdout) ) ,
261+ OutputFormat :: Json => notify :: ArcNotifier :: new ( notify:: JsonNotifier :: new ( stdout) ) ,
262+ _ if opts. list => notify :: ArcNotifier :: new ( notify:: TerseListNotifier :: new ( stdout) ) ,
263+ OutputFormat :: Pretty => notify :: ArcNotifier :: new ( notify:: PrettyRunNotifier :: new ( stdout) ) ,
264+ OutputFormat :: Terse => notify :: ArcNotifier :: new ( notify:: TerseRunNotifier :: new ( stdout) ) ,
265265 }
266266}
267267
@@ -292,7 +292,7 @@ fn run(
292292 start : & std:: time:: Instant ,
293293 opts : & libtest_lexarg:: TestOpts ,
294294 cases : Vec < Box < dyn Case > > ,
295- notifier : & mut dyn notify:: Notifier ,
295+ notifier : notify:: ArcNotifier ,
296296) -> std:: io:: Result < bool > {
297297 notifier. notify (
298298 notify:: event:: RunStart {
@@ -316,7 +316,6 @@ fn run(
316316
317317 let threads = opts. test_threads . map ( |t| t. get ( ) ) . unwrap_or ( 1 ) ;
318318
319- let mut context = TestContext :: new ( ) ;
320319 let run_ignored = match opts. run_ignored {
321320 libtest_lexarg:: RunIgnored :: Yes | libtest_lexarg:: RunIgnored :: Only => true ,
322321 libtest_lexarg:: RunIgnored :: No => false ,
@@ -331,9 +330,13 @@ fn run(
331330 ( false , true ) => RunMode :: Bench ,
332331 ( false , false ) => unreachable ! ( "libtest-lexarg` should always ensure at least one is set" ) ,
333332 } ;
334- context. set_mode ( mode) ;
335- context. set_run_ignored ( run_ignored) ;
336- let context = std:: sync:: Arc :: new ( context) ;
333+ let context = TestContext {
334+ start : * start,
335+ mode,
336+ run_ignored,
337+ notifier,
338+ test_name : String :: new ( ) ,
339+ } ;
337340
338341 let mut success = true ;
339342
@@ -345,88 +348,49 @@ fn run(
345348 . partition :: < Vec < _ > , _ > ( |c| c. exclusive ( & context) )
346349 } ;
347350 if !concurrent_cases. is_empty ( ) {
348- notifier. threaded ( true ) ;
349- struct RunningTest {
350- join_handle : std:: thread:: JoinHandle < ( ) > ,
351- }
352-
353- impl RunningTest {
354- fn join (
355- self ,
356- start : & std:: time:: Instant ,
357- event : & notify:: event:: CaseComplete ,
358- notifier : & mut dyn notify:: Notifier ,
359- ) -> std:: io:: Result < ( ) > {
360- if self . join_handle . join ( ) . is_err ( ) {
361- let kind = notify:: MessageKind :: Error ;
362- let message = Some ( "panicked after reporting success" . to_owned ( ) ) ;
363- notifier. notify (
364- notify:: event:: CaseMessage {
365- name : event. name . clone ( ) ,
366- kind,
367- message,
368- elapsed_s : Some ( notify:: Elapsed ( start. elapsed ( ) ) ) ,
369- }
370- . into ( ) ,
371- ) ?;
372- }
373- Ok ( ( ) )
374- }
375- }
351+ context. notifier ( ) . threaded ( true ) ;
376352
377353 // Use a deterministic hasher
378354 type TestMap = std:: collections:: HashMap <
379355 String ,
380- RunningTest ,
356+ std :: thread :: JoinHandle < std :: io :: Result < bool > > ,
381357 std:: hash:: BuildHasherDefault < std:: collections:: hash_map:: DefaultHasher > ,
382358 > ;
383359
384360 let sync_success = std:: sync:: Arc :: new ( std:: sync:: atomic:: AtomicBool :: new ( success) ) ;
385- let mut running_tests: TestMap = Default :: default ( ) ;
386- let mut pending = 0 ;
387- let ( tx, rx) = std:: sync:: mpsc:: channel :: < notify:: Event > ( ) ;
361+ let mut running: TestMap = Default :: default ( ) ;
362+ let ( tx, rx) = std:: sync:: mpsc:: channel :: < String > ( ) ;
388363 let mut remaining = std:: collections:: VecDeque :: from ( concurrent_cases) ;
389- while pending > 0 || !remaining. is_empty ( ) {
390- while pending < threads && !remaining. is_empty ( ) {
364+ while !running . is_empty ( ) || !remaining. is_empty ( ) {
365+ while running . len ( ) < threads && !remaining. is_empty ( ) {
391366 let case = remaining. pop_front ( ) . unwrap ( ) ;
367+ let case = std:: sync:: Arc :: new ( case) ;
392368 let name = case. name ( ) . to_owned ( ) ;
393369
394370 let cfg = std:: thread:: Builder :: new ( ) . name ( name. clone ( ) ) ;
395- let start = * start;
396- let tx = tx. clone ( ) ;
397- let case = std:: sync:: Arc :: new ( case) ;
398- let case_fallback = case. clone ( ) ;
399- let context = context. clone ( ) ;
400- let context_fallback = context. clone ( ) ;
401- let sync_success = sync_success. clone ( ) ;
402- let sync_success_fallback = sync_success. clone ( ) ;
371+ let thread_tx = tx. clone ( ) ;
372+ let thread_case = case. clone ( ) ;
373+ let mut thread_context = context. clone ( ) ;
374+ thread_context. test_name = name. clone ( ) ;
375+ let thread_sync_success = sync_success. clone ( ) ;
403376 let join_handle = cfg. spawn ( move || {
404- let mut notifier = SenderNotifier { tx : tx. clone ( ) } ;
405- let case_success =
406- run_case ( & start, case. as_ref ( ) . as_ref ( ) , & context, & mut notifier)
407- . expect ( "`SenderNotifier` is infallible" ) ;
408- if !case_success {
409- sync_success. store ( case_success, std:: sync:: atomic:: Ordering :: Relaxed ) ;
377+ let status = run_case ( thread_case. as_ref ( ) . as_ref ( ) , & thread_context) ;
378+ if !matches ! ( status, Ok ( true ) ) {
379+ thread_sync_success. store ( false , std:: sync:: atomic:: Ordering :: Relaxed ) ;
410380 }
381+ let _ = thread_tx. send ( thread_case. name ( ) . to_owned ( ) ) ;
382+ status
411383 } ) ;
412384 match join_handle {
413385 Ok ( join_handle) => {
414- running_tests. insert ( name. clone ( ) , RunningTest { join_handle } ) ;
415- pending += 1 ;
386+ running. insert ( name. clone ( ) , join_handle) ;
416387 }
417388 Err ( e) if e. kind ( ) == std:: io:: ErrorKind :: WouldBlock => {
418389 // `ErrorKind::WouldBlock` means hitting the thread limit on some
419390 // platforms, so run the test synchronously here instead.
420- let case_success = run_case (
421- & start,
422- case_fallback. as_ref ( ) . as_ref ( ) ,
423- & context_fallback,
424- notifier,
425- )
426- . expect ( "`SenderNotifier` is infallible" ) ;
391+ let case_success = run_case ( case. as_ref ( ) . as_ref ( ) , & context) ?;
427392 if !case_success {
428- sync_success_fallback
429- . store ( case_success, std:: sync:: atomic:: Ordering :: Relaxed ) ;
393+ sync_success. store ( case_success, std:: sync:: atomic:: Ordering :: Relaxed ) ;
430394 }
431395 }
432396 Err ( e) => {
@@ -435,13 +399,9 @@ fn run(
435399 }
436400 }
437401
438- let event = rx. recv ( ) . unwrap ( ) ;
439- if let notify:: Event :: CaseComplete ( event) = & event {
440- let running_test = running_tests. remove ( & event. name ) . unwrap ( ) ;
441- running_test. join ( start, event, notifier) ?;
442- pending -= 1 ;
443- }
444- notifier. notify ( event) ?;
402+ let test_name = rx. recv ( ) . unwrap ( ) ;
403+ let running_test = running. remove ( & test_name) . unwrap ( ) ;
404+ let _ = running_test. join ( ) ;
445405 success &= sync_success. load ( std:: sync:: atomic:: Ordering :: SeqCst ) ;
446406 if !success && opts. fail_fast {
447407 break ;
@@ -450,16 +410,16 @@ fn run(
450410 }
451411
452412 if !exclusive_cases. is_empty ( ) {
453- notifier. threaded ( false ) ;
413+ context . notifier ( ) . threaded ( false ) ;
454414 for case in exclusive_cases {
455- success &= run_case ( start , case. as_ref ( ) , & context, notifier ) ?;
415+ success &= run_case ( case. as_ref ( ) , & context) ?;
456416 if !success && opts. fail_fast {
457417 break ;
458418 }
459419 }
460420 }
461421
462- notifier. notify (
422+ context . notifier ( ) . notify (
463423 notify:: event:: RunComplete {
464424 elapsed_s : Some ( notify:: Elapsed ( start. elapsed ( ) ) ) ,
465425 }
@@ -469,16 +429,11 @@ fn run(
469429 Ok ( success)
470430}
471431
472- fn run_case (
473- start : & std:: time:: Instant ,
474- case : & dyn Case ,
475- context : & TestContext ,
476- notifier : & mut dyn notify:: Notifier ,
477- ) -> std:: io:: Result < bool > {
478- notifier. notify (
432+ fn run_case ( case : & dyn Case , context : & TestContext ) -> std:: io:: Result < bool > {
433+ context. notifier ( ) . notify (
479434 notify:: event:: CaseStart {
480435 name : case. name ( ) . to_owned ( ) ,
481- elapsed_s : Some ( notify :: Elapsed ( start . elapsed ( ) ) ) ,
436+ elapsed_s : Some ( context . elapased_s ( ) ) ,
482437 }
483438 . into ( ) ,
484439 ) ?;
@@ -507,21 +462,21 @@ fn run_case(
507462 let kind = err. status ( ) ;
508463 case_status = Some ( kind) ;
509464 let message = err. cause ( ) . map ( |c| c. to_string ( ) ) ;
510- notifier. notify (
465+ context . notifier ( ) . notify (
511466 notify:: event:: CaseMessage {
512467 name : case. name ( ) . to_owned ( ) ,
513468 kind,
514469 message,
515- elapsed_s : Some ( notify :: Elapsed ( start . elapsed ( ) ) ) ,
470+ elapsed_s : Some ( context . elapased_s ( ) ) ,
516471 }
517472 . into ( ) ,
518473 ) ?;
519474 }
520475
521- notifier. notify (
476+ context . notifier ( ) . notify (
522477 notify:: event:: CaseComplete {
523478 name : case. name ( ) . to_owned ( ) ,
524- elapsed_s : Some ( notify :: Elapsed ( start . elapsed ( ) ) ) ,
479+ elapsed_s : Some ( context . elapased_s ( ) ) ,
525480 }
526481 . into ( ) ,
527482 ) ?;
@@ -537,16 +492,3 @@ fn __rust_begin_short_backtrace<T, F: FnOnce() -> T>(f: F) -> T {
537492 // prevent this frame from being tail-call optimised away
538493 std:: hint:: black_box ( result)
539494}
540-
541- #[ derive( Clone , Debug ) ]
542- struct SenderNotifier {
543- tx : std:: sync:: mpsc:: Sender < notify:: Event > ,
544- }
545-
546- impl notify:: Notifier for SenderNotifier {
547- fn notify ( & mut self , event : notify:: Event ) -> std:: io:: Result < ( ) > {
548- // If the sender doesn't care, neither do we
549- let _ = self . tx . send ( event) ;
550- Ok ( ( ) )
551- }
552- }
0 commit comments