summaryrefslogtreecommitdiff
path: root/cmd2.py
diff options
context:
space:
mode:
authorTodd Leonhardt <tleonhardt@gmail.com>2017-04-26 15:47:17 -0400
committerTodd Leonhardt <tleonhardt@gmail.com>2017-04-26 15:47:17 -0400
commitf3fa2265442b5c263f7f7f9a99da80142d9a3fd4 (patch)
treef9181f73a3b7edbc940fd63553c85a98af7fdc23 /cmd2.py
parent90330f29a7fd1ebf03ef2b639f8bc44caf5c379a (diff)
downloadcmd2-git-f3fa2265442b5c263f7f7f9a99da80142d9a3fd4.tar.gz
Fixed transcript testing issues
Transcript testing no longer creates an unnecessary 2nd instance of the class derived from cmd2.Cmd. This dramatically simplifies transcript testing for derived classes which have required parameters during construction. As a side effect the, feedback_to_output attribute now defaults to false. This had some minor ripple effects on various unit tests.
Diffstat (limited to 'cmd2.py')
-rwxr-xr-xcmd2.py63
1 files changed, 20 insertions, 43 deletions
diff --git a/cmd2.py b/cmd2.py
index d14c36f8..e2201632 100755
--- a/cmd2.py
+++ b/cmd2.py
@@ -618,7 +618,7 @@ class Cmd(cmd.Cmd):
for editor in ['vim', 'vi', 'emacs', 'nano', 'pico', 'gedit', 'kate', 'subl', 'geany', 'atom']:
if _which(editor):
break
- feedback_to_output = False # Do include nonessentials in >, | output
+ feedback_to_output = True # Do include nonessentials in >, | output
locals_in_py = True
quiet = False # Do not suppress nonessential output
timing = False # Prints elapsed time for each command
@@ -1691,7 +1691,7 @@ Script should contain one command per line, just like command would be typed in
:param callargs: List[str] - list of transcript test file names
"""
class TestMyAppCase(Cmd2TestCase):
- CmdApp = self.__class__
+ cmdapp = self
self.__class__.testfiles = callargs
sys.argv = [sys.argv[0]] # the --test argument upsets unittest.main()
@@ -1731,12 +1731,12 @@ Script should contain one command per line, just like command would be typed in
if callopts.test:
self._transcript_files = callargs
+ # Always run the preloop first
+ self.preloop()
+
if self._transcript_files is not None:
self.run_transcript_tests(self._transcript_files)
else:
- # Always run the preloop first
- self.preloop()
-
# If an intro was supplied in the method call, allow it to override the default
if intro is not None:
self.intro = intro
@@ -1754,8 +1754,8 @@ Script should contain one command per line, just like command would be typed in
if not stop:
self._cmdloop()
- # Run the postloop() no matter what
- self.postloop()
+ # Run the postloop() no matter what
+ self.postloop()
class HistoryItem(str):
@@ -1960,25 +1960,11 @@ class Statekeeper(object):
setattr(self.obj, attrib, getattr(self, attrib))
-class Borg(object):
- """All instances of any Borg subclass will share state.
- from Python Cookbook, 2nd Ed., recipe 6.16"""
- _shared_state = {}
-
- def __new__(cls, *a, **k):
- obj = object.__new__(cls)
- obj.__dict__ = cls._shared_state
- return obj
-
-
-class OutputTrap(Borg):
- """Instantiate an OutputTrap to divert/capture ALL stdout output. For use in unit testing.
- Call `tearDown()` to return to normal output."""
+class OutputTrap(object):
+ """Instantiate an OutputTrap to divert/capture ALL stdout output. For use in transcript testing."""
def __init__(self):
self.contents = ''
- self.old_stdout = sys.stdout
- sys.stdout = self
def write(self, txt):
"""Add text to the internal contents.
@@ -1996,17 +1982,12 @@ class OutputTrap(Borg):
self.contents = ''
return result
- def tear_down(self):
- """Restores normal output."""
- sys.stdout = self.old_stdout
- self.contents = ''
-
class Cmd2TestCase(unittest.TestCase):
"""Subclass this, setting CmdApp, to make a unittest.TestCase class
that will execute the commands in a transcript file and expect the results shown.
See example.py"""
- CmdApp = None
+ cmdapp = None
regexPattern = pyparsing.QuotedString(quoteChar=r'/', escChar='\\', multiline=True, unquoteResults=True)
regexPattern.ignore(pyparsing.cStyleComment)
notRegexPattern = pyparsing.Word(pyparsing.printables)
@@ -2016,7 +1997,7 @@ class Cmd2TestCase(unittest.TestCase):
def fetchTranscripts(self):
self.transcripts = {}
- for fileset in self.CmdApp.testfiles:
+ for fileset in self.cmdapp.testfiles:
for fname in glob.glob(fileset):
tfile = open(fname)
self.transcripts[fname] = iter(tfile.readlines())
@@ -2025,17 +2006,15 @@ class Cmd2TestCase(unittest.TestCase):
raise Exception("No test files found - nothing to test.")
def setUp(self):
- if self.CmdApp:
- self.outputTrap = OutputTrap()
- self.cmdapp = self.CmdApp()
+ if self.cmdapp:
self.fetchTranscripts()
- # Make sure any required initialization gets done and flush the output buffer
- self.cmdapp.preloop()
- self.outputTrap.read()
+ # Trap stdout
+ self._orig_stdout = self.cmdapp.stdout
+ self.cmdapp.stdout = OutputTrap()
def runTest(self): # was testall
- if self.CmdApp:
+ if self.cmdapp:
its = sorted(self.transcripts.items())
for (fname, transcript) in its:
self._test_transcript(fname, transcript)
@@ -2071,7 +2050,7 @@ class Cmd2TestCase(unittest.TestCase):
# Send the command into the application and capture the resulting output
# TODO: Should we get the return value and act if stop == True?
self.cmdapp.onecmd_plus_hooks(command)
- result = self.outputTrap.read()
+ result = self.cmdapp.stdout.read()
# Read the expected result from transcript
if line.startswith(self.cmdapp.prompt):
message = '\nFile %s, line %d\nCommand was:\n%r\nExpected: (nothing)\nGot:\n%r\n' % \
@@ -2098,11 +2077,9 @@ class Cmd2TestCase(unittest.TestCase):
self.assertTrue(re.match(expected, result, re.MULTILINE | re.DOTALL), message)
def tearDown(self):
- if self.CmdApp:
- # Make sure any required cleanup gets done
- self.cmdapp.postloop()
-
- self.outputTrap.tear_down()
+ if self.cmdapp:
+ # Restore stdout
+ self.cmdapp.stdout = self._orig_stdout
def namedtuple_with_two_defaults(typename, field_names, default_values=('', '')):