Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 20 additions & 43 deletions cmd2.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -1691,7 +1691,7 @@ def run_transcript_tests(self, callargs):
: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()
Expand Down Expand Up @@ -1731,12 +1731,12 @@ def cmdloop(self, intro=None):
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
Expand All @@ -1754,8 +1754,8 @@ def cmdloop(self, intro=None):
if not stop:
self._cmdloop()

# Run the postloop() no matter what
self.postloop()
# Run the postloop() no matter what
self.postloop()


class HistoryItem(str):
Expand Down Expand Up @@ -1960,25 +1960,11 @@ def restore(self):
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.
Expand All @@ -1996,17 +1982,12 @@ def read(self):
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)
Expand All @@ -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())
Expand All @@ -2025,17 +2006,15 @@ def fetchTranscripts(self):
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)
Expand Down Expand Up @@ -2071,7 +2050,7 @@ def _test_transcript(self, fname, transcript):
# 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' % \
Expand All @@ -2098,11 +2077,9 @@ def _test_transcript(self, fname, transcript):
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=('', '')):
Expand Down
4 changes: 2 additions & 2 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
default_file_name: command.txt
echo: False
editor: vim
feedback_to_output: False
feedback_to_output: True
locals_in_py: True
prompt: (Cmd)
quiet: False
Expand All @@ -75,7 +75,7 @@
default_file_name: command.txt # for ``save``, ``load``, etc.
echo: False # Echo command issued into output
editor: vim # Program used by ``edit``
feedback_to_output: False # include nonessentials in `|`, `>` results
feedback_to_output: True # include nonessentials in `|`, `>` results
locals_in_py: True # Allow access to your application in py via self
prompt: (Cmd) # The prompt issued to solicit input
quiet: False # Don't print nonessential feedback
Expand Down
18 changes: 8 additions & 10 deletions tests/test_cmd2.py
Original file line number Diff line number Diff line change
Expand Up @@ -266,16 +266,15 @@ def test_base_relative_load(base_app, request):
assert out == expected


def test_base_save(base_app, capsys):
def test_base_save(base_app):
# TODO: Use a temporary directory for the file
filename = 'deleteme.txt'
run_cmd(base_app, 'help')
run_cmd(base_app, 'help save')

# Test the * form of save which saves all commands from history
run_cmd(base_app, 'save * {}'.format(filename))
out, err = capsys.readouterr()
assert out == 'Saved to {}\n'.format(filename)
out = run_cmd(base_app, 'save * {}'.format(filename))
assert out == normalize('Saved to {}\n'.format(filename))
expected = normalize("""
help

Expand All @@ -288,18 +287,16 @@ def test_base_save(base_app, capsys):
assert content == expected

# Test the N form of save which saves a numbered command from history
run_cmd(base_app, 'save 1 {}'.format(filename))
out, err = capsys.readouterr()
assert out == 'Saved to {}\n'.format(filename)
out = run_cmd(base_app, 'save 1 {}'.format(filename))
assert out == normalize('Saved to {}\n'.format(filename))
expected = normalize('help')
with open(filename) as f:
content = normalize(f.read())
assert content == expected

# Test the blank form of save which saves the most recent command from history
run_cmd(base_app, 'save {}'.format(filename))
out, err = capsys.readouterr()
assert out == 'Saved to {}\n'.format(filename)
out = run_cmd(base_app, 'save {}'.format(filename))
assert out == normalize('Saved to {}\n'.format(filename))
expected = normalize('save 1 {}'.format(filename))
with open(filename) as f:
content = normalize(f.read())
Expand Down Expand Up @@ -397,6 +394,7 @@ def test_send_to_paste_buffer(base_app):


def test_base_timing(base_app, capsys):
base_app.feedback_to_output = False
out = run_cmd(base_app, 'set timing True')
expected = normalize("""timing - was: False
now: True
Expand Down
1 change: 1 addition & 0 deletions tests/test_transcript.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ def test_base_with_transcript(_cmdline_app):
-------------------------[6]
say -ps --repeat=5 goodnight, Gracie
(Cmd) run 4
say -ps --repeat=5 goodnight, Gracie
OODNIGHT, GRACIEGAY
OODNIGHT, GRACIEGAY
OODNIGHT, GRACIEGAY
Expand Down
2 changes: 1 addition & 1 deletion tests/transcript_regex.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ debug: False
default_file_name: command.txt
echo: False
editor: /([^\s]+)/
feedback_to_output: False
feedback_to_output: True
locals_in_py: True
maxrepeats: 3
prompt: (Cmd)
Expand Down