@@ -553,8 +553,8 @@ def __init__(self, completekey: str = 'tab', stdin=None, stdout=None, persistent
553553 # This boolean flag determines whether or not the cmd2 application can interact with the clipboard
554554 self .can_clip = can_clip
555555
556- # This determines if a non-zero exit code should be used when exiting the application
557- self .exit_code = None
556+ # This determines the value returned by cmdloop() when exiting the application
557+ self .exit_code = 0
558558
559559 # This lock should be acquired before doing any asynchronous changes to the terminal to
560560 # ensure the updates to the terminal don't interfere with the input being typed or output
@@ -3683,8 +3683,24 @@ class TestMyAppCase(Cmd2TestCase):
36833683 self .__class__ .testfiles = callargs
36843684 sys .argv = [sys .argv [0 ]] # the --test argument upsets unittest.main()
36853685 testcase = TestMyAppCase ()
3686- runner = unittest .TextTestRunner ()
3687- runner .run (testcase )
3686+ stream = utils .StdSim (sys .stderr )
3687+ runner = unittest .TextTestRunner (stream = stream )
3688+ test_results = runner .run (testcase )
3689+ if test_results .wasSuccessful ():
3690+ self .decolorized_write (sys .stderr , stream .read ())
3691+ self .poutput ('Tests passed' , color = Fore .LIGHTGREEN_EX )
3692+ else :
3693+ # Strip off the initial trackeback which isn't particularly useful for end users
3694+ error_str = stream .read ()
3695+ end_of_trace = error_str .find ('AssertionError:' )
3696+ file_offset = error_str [end_of_trace :].find ('File ' )
3697+ start = end_of_trace + file_offset
3698+
3699+ # But print the transcript file name and line number followed by what was expected and what was observed
3700+ self .perror (error_str [start :], traceback_war = False )
3701+
3702+ # Return a failure error code to support automated transcript-based testing
3703+ self .exit_code = - 1
36883704
36893705 def async_alert (self , alert_msg : str , new_prompt : Optional [str ] = None ) -> None : # pragma: no cover
36903706 """
@@ -3932,14 +3948,15 @@ def _report_disabled_command_usage(self, *args, message_to_print: str, **kwargs)
39323948 """
39333949 self .decolorized_write (sys .stderr , "{}\n " .format (message_to_print ))
39343950
3935- def cmdloop (self , intro : Optional [str ] = None ) -> None :
3951+ def cmdloop (self , intro : Optional [str ] = None ) -> int :
39363952 """This is an outer wrapper around _cmdloop() which deals with extra features provided by cmd2.
39373953
39383954 _cmdloop() provides the main loop equivalent to cmd.cmdloop(). This is a wrapper around that which deals with
39393955 the following extra features provided by cmd2:
39403956 - commands at invocation
39413957 - transcript testing
39423958 - intro banner
3959+ - exit code
39433960
39443961 :param intro: if provided this overrides self.intro and serves as the intro banner printed once at start
39453962 """
@@ -4002,8 +4019,7 @@ def cmdloop(self, intro: Optional[str] = None) -> None:
40024019 # Restore the original signal handler
40034020 signal .signal (signal .SIGINT , original_sigint_handler )
40044021
4005- if self .exit_code is not None :
4006- sys .exit (self .exit_code )
4022+ return self .exit_code
40074023
40084024 ###
40094025 #
0 commit comments