Mercurial > python-cmd2
comparison cmd2/cmd2.py @ 104:bd91925d813c
having a hard time capturing stdout
author | catherine@dellzilla |
---|---|
date | Fri, 24 Oct 2008 13:29:22 -0400 |
parents | e4daf715fc31 |
children | 130340609e19 |
comparison
equal
deleted
inserted
replaced
103:e4daf715fc31 | 104:bd91925d813c |
---|---|
20 | 20 |
21 CHANGES: | 21 CHANGES: |
22 As of 0.3.0, options should be specified as `optparse` options. See README.txt. | 22 As of 0.3.0, options should be specified as `optparse` options. See README.txt. |
23 flagReader.py options are still supported for backward compatibility | 23 flagReader.py options are still supported for backward compatibility |
24 """ | 24 """ |
25 import cmd, re, os, sys, optparse, subprocess, tempfile, pyparsing, doctest | 25 import cmd, re, os, sys, optparse, subprocess, tempfile, pyparsing, doctest, unittest |
26 from optparse import make_option | 26 from optparse import make_option |
27 __version__ = '0.3.7' | 27 __version__ = '0.3.7' |
28 | 28 |
29 class OptionParser(optparse.OptionParser): | 29 class OptionParser(optparse.OptionParser): |
30 def exit(self, status=0, msg=None): | 30 def exit(self, status=0, msg=None): |
674 setattr(self, attrib, getattr(self.obj, attrib)) | 674 setattr(self, attrib, getattr(self.obj, attrib)) |
675 def restore(self): | 675 def restore(self): |
676 for attrib in self.attribs: | 676 for attrib in self.attribs: |
677 setattr(self.obj, attrib, getattr(self, attrib)) | 677 setattr(self.obj, attrib, getattr(self, attrib)) |
678 | 678 |
679 class Borg(object): | |
680 '''All instances of any Borg subclass will share state. | |
681 from Python Cookbook, 2nd Ed., recipe 6.16''' | |
682 _shared_state = {} | |
683 def __new__(cls, *a, **k): | |
684 obj = object.__new__(cls, *a, **k) | |
685 obj.__dict__ = cls._shared_state | |
686 return obj | |
687 | |
688 class OutputTrap(Borg): | |
689 '''Instantiate an OutputTrap to divert/capture ALL stdout output. For use in unit testing. | |
690 Call `tearDown()` to return to normal output.''' | |
691 old_stdout = sys.stdout | |
692 def __init__(self): | |
693 #self.old_stdout = sys.stdout | |
694 self.trap = tempfile.TemporaryFile() | |
695 sys.stdout = self.trap | |
696 def dump(self): | |
697 'Reads trapped stdout output.' | |
698 self.trap.seek(0) | |
699 result = self.trap.read() | |
700 self.trap.close() | |
701 self.trap = tempfile.TemporaryFile() | |
702 sys.stdout = self.trap | |
703 return result | |
704 def tearDown(self): | |
705 sys.stdout = self.old_stdout | |
706 | |
707 class TranscriptReader(object): | |
708 def __init__(self, cmdapp, filename='test_cmd2.txt'): | |
709 self.cmdapp = cmdapp | |
710 try: | |
711 tfile = open(filename) | |
712 self.transcript = tfile.read() | |
713 tfile.close() | |
714 except IOError: | |
715 self.transcript = '' | |
716 self.bookmark = 0 | |
717 def refreshCommandFinder(self): | |
718 prompt = pyparsing.Suppress(pyparsing.lineStart + self.cmdapp.prompt) | |
719 continuationPrompt = pyparsing.Suppress(pyparsing.lineStart + self.cmdapp.continuationPrompt) | |
720 self.cmdtxtPattern = (prompt + pyparsing.restOfLine + pyparsing.ZeroOrMore( | |
721 pyparsing.lineEnd + continuationPrompt + pyparsing.restOfLine))("command") | |
722 def inputGenerator(self): | |
723 while True: | |
724 self.refreshCommandFinder() | |
725 (thiscmd, startpos, endpos) = self.cmdtxtPattern.scanString(self.transcript[self.bookmark:], maxMatches=1).next() | |
726 lineNum = self.transcript.count('\n', 0, self.bookmark+startpos) + 2 | |
727 self.bookmark += endpos | |
728 yield (''.join(thiscmd.command), lineNum) | |
729 def nextExpected(self): | |
730 self.refreshCommandFinder() | |
731 try: | |
732 (thiscmd, startpos, endpos) = self.cmdtxtPattern.scanString(self.transcript[self.bookmark:], maxMatches=1).next() | |
733 result = self.transcript[self.bookmark:self.bookmark+startpos] | |
734 self.bookmark += startpos | |
735 return result | |
736 except StopIteration: | |
737 return self.transcript[self.bookmark:] | |
738 | |
739 class Cmd2TestCase(unittest.TestCase): | |
740 '''Subclass this, setting CmdApp and transcriptFileName, to make a unittest.TestCase class | |
741 that will execute the commands in transcriptFileName and expect the results shown.''' | |
742 # problem: this (raw) case gets called by unittest.main - we don't want it to be. hmm | |
743 CmdApp = None | |
744 transcriptFileName = '' | |
745 def setUp(self): | |
746 if self.CmdApp: | |
747 self.cmdapp = self.CmdApp() | |
748 self.outputTrap = OutputTrap() | |
749 self.transcriptReader = TranscriptReader(self.cmdapp, self.transcriptFileName) | |
750 def testall(self): | |
751 if self.CmdApp: | |
752 for (cmdInput, lineNum) in self.transcriptReader.inputGenerator(): | |
753 self.cmdapp.onecmd(cmdInput) | |
754 result = self.outputTrap.dump() | |
755 expected = self.transcriptReader.nextExpected() | |
756 self.assertEqual(result.strip(), expected.strip(), | |
757 '\nFile %s, line %d\nCommand was:\n%s\nExpected:\n%s\nGot:\n%s\n' % | |
758 (self.transcriptFileName, lineNum, cmdInput, expected, result)) | |
759 def tearDown(self): | |
760 if self.CmdApp: | |
761 self.outputTrap.tearDown() | |
762 | |
679 if __name__ == '__main__': | 763 if __name__ == '__main__': |
680 doctest.testmod() | 764 doctest.testmod() |