@@ -323,9 +323,14 @@ def on_atexit() -> None:
323323 # Main thread did not set an exit code. Assume a bug.
324324 exit_code = 1 # default error exit code
325325
326- # Exit process immediately, without bothering to run garbage collection
327- # or other cleanup processes that can take a long time
328- os ._exit (exit_code )
326+ from crystal .util .xos import is_coverage
327+ if is_coverage ():
328+ # Exit process normally, so that coverage results are written to disk
329+ pass
330+ else :
331+ # Exit process immediately, without bothering to run garbage collection
332+ # or other cleanup processes that can take a long time
333+ os ._exit (exit_code )
329334 atexit .register (on_atexit )
330335
331336 # Set headless mode, before anybody tries to call fg_call_later
@@ -564,6 +569,8 @@ def _on_end_session(self, event: wx.CloseEvent) -> None:
564569 # before starting bg_task() on background thread
565570 from crystal .tests .index import run_tests
566571 from crystal .util .bulkheads import capture_crashes_to_stderr
572+ from crystal .util .xos import is_coverage
573+ from crystal .util .xthreading import fg_call_and_wait
567574
568575 # NOTE: Any unhandled exception will probably call os._exit(1)
569576 # before reaching this decorator.
@@ -579,7 +586,16 @@ def bg_task():
579586 is_ok = run_tests (parsed_args .test )
580587 finally :
581588 exit_code = 0 if is_ok else 1
582- os ._exit (exit_code )
589+ if is_coverage ():
590+ # Exit app normally,
591+ # so that coverage results are written to disk
592+ def close_all_windows () -> None :
593+ for w in list (wx .GetTopLevelWindows ()):
594+ w .Close ()
595+ fg_call_and_wait (close_all_windows )
596+ else :
597+ # Exit app immediately
598+ os ._exit (exit_code )
583599 bg_call_later (bg_task )
584600
585601 # 1. Run main loop
0 commit comments