Mercurial > python-cmd2
changeset 104:bd91925d813c
having a hard time capturing stdout
author | catherine@dellzilla |
---|---|
date | Fri, 24 Oct 2008 13:29:22 -0400 |
parents | e4daf715fc31 |
children | 130340609e19 |
files | cmd2/cmd2.py |
diffstat | 1 files changed, 85 insertions(+), 1 deletions(-) [+] |
line wrap: on
line diff
--- a/cmd2/cmd2.py Tue Oct 14 15:28:37 2008 -0400 +++ b/cmd2/cmd2.py Fri Oct 24 13:29:22 2008 -0400 @@ -22,7 +22,7 @@ As of 0.3.0, options should be specified as `optparse` options. See README.txt. flagReader.py options are still supported for backward compatibility """ -import cmd, re, os, sys, optparse, subprocess, tempfile, pyparsing, doctest +import cmd, re, os, sys, optparse, subprocess, tempfile, pyparsing, doctest, unittest from optparse import make_option __version__ = '0.3.7' @@ -676,5 +676,89 @@ for attrib in self.attribs: 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, *a, **k) + 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.''' + old_stdout = sys.stdout + def __init__(self): + #self.old_stdout = sys.stdout + self.trap = tempfile.TemporaryFile() + sys.stdout = self.trap + def dump(self): + 'Reads trapped stdout output.' + self.trap.seek(0) + result = self.trap.read() + self.trap.close() + self.trap = tempfile.TemporaryFile() + sys.stdout = self.trap + return result + def tearDown(self): + sys.stdout = self.old_stdout + +class TranscriptReader(object): + def __init__(self, cmdapp, filename='test_cmd2.txt'): + self.cmdapp = cmdapp + try: + tfile = open(filename) + self.transcript = tfile.read() + tfile.close() + except IOError: + self.transcript = '' + self.bookmark = 0 + def refreshCommandFinder(self): + prompt = pyparsing.Suppress(pyparsing.lineStart + self.cmdapp.prompt) + continuationPrompt = pyparsing.Suppress(pyparsing.lineStart + self.cmdapp.continuationPrompt) + self.cmdtxtPattern = (prompt + pyparsing.restOfLine + pyparsing.ZeroOrMore( + pyparsing.lineEnd + continuationPrompt + pyparsing.restOfLine))("command") + def inputGenerator(self): + while True: + self.refreshCommandFinder() + (thiscmd, startpos, endpos) = self.cmdtxtPattern.scanString(self.transcript[self.bookmark:], maxMatches=1).next() + lineNum = self.transcript.count('\n', 0, self.bookmark+startpos) + 2 + self.bookmark += endpos + yield (''.join(thiscmd.command), lineNum) + def nextExpected(self): + self.refreshCommandFinder() + try: + (thiscmd, startpos, endpos) = self.cmdtxtPattern.scanString(self.transcript[self.bookmark:], maxMatches=1).next() + result = self.transcript[self.bookmark:self.bookmark+startpos] + self.bookmark += startpos + return result + except StopIteration: + return self.transcript[self.bookmark:] + +class Cmd2TestCase(unittest.TestCase): + '''Subclass this, setting CmdApp and transcriptFileName, to make a unittest.TestCase class + that will execute the commands in transcriptFileName and expect the results shown.''' + # problem: this (raw) case gets called by unittest.main - we don't want it to be. hmm + CmdApp = None + transcriptFileName = '' + def setUp(self): + if self.CmdApp: + self.cmdapp = self.CmdApp() + self.outputTrap = OutputTrap() + self.transcriptReader = TranscriptReader(self.cmdapp, self.transcriptFileName) + def testall(self): + if self.CmdApp: + for (cmdInput, lineNum) in self.transcriptReader.inputGenerator(): + self.cmdapp.onecmd(cmdInput) + result = self.outputTrap.dump() + expected = self.transcriptReader.nextExpected() + self.assertEqual(result.strip(), expected.strip(), + '\nFile %s, line %d\nCommand was:\n%s\nExpected:\n%s\nGot:\n%s\n' % + (self.transcriptFileName, lineNum, cmdInput, expected, result)) + def tearDown(self): + if self.CmdApp: + self.outputTrap.tearDown() + if __name__ == '__main__': doctest.testmod()