Rev 2: Start of refactoring to make sure commands are called with appropriate parameters. in http://bzr.arbash-meinel.com/branches/bzr/extra/moin_graphviz
John Arbash Meinel
john at arbash-meinel.com
Tue Apr 3 00:07:59 BST 2007
At http://bzr.arbash-meinel.com/branches/bzr/extra/moin_graphviz
------------------------------------------------------------
revno: 2
revision-id: john at arbash-meinel.com-20070402230756-hdm8969fymtxsn2z
parent: john at arbash-meinel.com-20070402222501-lxijfcuog91nqbj2
committer: John Arbash Meinel <john at arbash-meinel.com>
branch nick: moin_graphviz
timestamp: Mon 2007-04-02 18:07:56 -0500
message:
Start of refactoring to make sure commands are called with appropriate parameters.
added:
test_graphviz.py test_graphviz.py-20070402223544-kez8ooyxqh1wx5w0-1
modified:
graphviz.py graphviz.py-20070402222439-3qloodrjtlsuaz1o-1
-------------- next part --------------
=== added file 'test_graphviz.py'
--- a/test_graphviz.py 1970-01-01 00:00:00 +0000
+++ b/test_graphviz.py 2007-04-02 23:07:56 +0000
@@ -0,0 +1,130 @@
+"""A test suite for the graphviz Moin plugin."""
+
+import unittest
+
+import graphviz
+
+
+class MockRequest(object):
+ """A Request object which conforms to what we need."""
+
+ def __init__(self):
+ self._actions = []
+ self.form = None
+
+ def write(self, txt):
+ self._actions.append(('write', txt))
+
+ def getText(self, txt): # Wrapper for i18n
+ self._actions.append(('getText', txt))
+ return txt
+
+
+class MockFormatter(object):
+ """A formatter which implements the basic functionality."""
+
+ def __init__(self):
+ self._actions = []
+
+ def escapedText(self, txt):
+ self._actions(('escapedText', txt))
+
+ def rawHTML(self, txt):
+ self._actions(('rawHTML', txt))
+
+
+class ParserWithCommand(graphviz.Parser):
+ """A class which overrides self._dot_command for easier testing."""
+
+ _command = ['dot', '-Tpng']
+
+ def _dot_command(self):
+ return self._command
+
+
+class TestCaseWithParser(unittest.TestCase):
+ """A simple class with convenience functions."""
+
+ def get_formatter(self):
+ return MockFormatter()
+
+ def get_request(self):
+ return MockRequest()
+
+ def get_parser(self, raw='', request=None):
+ if request is None:
+ request = self.get_request()
+ return graphviz.Parser(raw, request)
+
+
+class TestParser(TestCaseWithParser):
+
+ def test_can_get_parser(self):
+ self.get_parser()
+
+ def test__dot_command(self):
+ """We should be able to configure a custom dot program.
+
+ But we also don't want commands to accidentally have a side effect
+ of changing which dot program we use.
+ """
+ # Test that we can force a different dot command
+ orig_val = graphviz.Parser._dot
+ try:
+ graphviz.Parser._dot = '/path/to/dot'
+ p = self.get_parser()
+ self.assertEqual(['/path/to/dot', '-Tpng'], p._dot_command())
+
+ graphviz.Parser._dot = '/alt/path/to/dot'
+ self.assertEqual(['/alt/path/to/dot', '-Tpng'], p._dot_command())
+
+ # But it shouldn't be effected by Parser._dot
+ p._dot = '/hacked/dot/path'
+ self.assertEqual(['/alt/path/to/dot', '-Tpng'], p._dot_command())
+ finally:
+ graphviz.Parser._dot = orig_val
+
+ def test_ParserWithCommand(self):
+ p = ParserWithCommand('', self.get_request())
+ self.assertEqual(['dot', '-Tpng'], p._dot_command())
+ # You can force the command by setting p._command
+ p._command = ['custom', 'command']
+ self.assertEqual(['custom', 'command'], p._dot_command())
+
+ def test__spawn_dot_args(self):
+ """Test that we spawn a subprocess"""
+ orig_val = graphviz.Parser._dot
+ try:
+ graphviz.Parser._dot = 'echo'
+ p = self.get_parser()
+ sub = p._spawn_dot()
+ # Check the arguments
+ out, err = sub.communicate()
+ self.assertEqual('-Tpng\n', out)
+ finally:
+ graphviz.Parser._dot = orig_val
+
+ def test__spawn_dot_pipe(self):
+ """Test that when spawning we properly pipe everything"""
+ p = ParserWithCommand('', self.get_request())
+ p._command = ['cat']
+
+ sub = p._spawn_dot()
+ out, err = sub.communicate()
+ self.assertEqual('', out)
+ self.assertEqual(None, err)
+
+ sub = p._spawn_dot()
+ out, err = sub.communicate('some text\n')
+ self.assertEqual('some text\n', out)
+ self.assertEqual(None, err)
+
+ def test__spawn_bad_command(self):
+ """Check the error when 'dot' doesn't exist."""
+ orig_val = graphviz.Parser._dot
+ try:
+ graphviz.Parser._dot = '/this/command/doesnt/exist'
+ p = self.get_parser()
+ self.assertRaises(OSError, p._spawn_dot)
+ finally:
+ graphviz.Parser._dot = orig_val
=== modified file 'graphviz.py'
--- a/graphviz.py 2007-04-02 22:25:01 +0000
+++ b/graphviz.py 2007-04-02 23:07:56 +0000
@@ -1,35 +1,66 @@
# -*- coding: iso-8859-1 -*-
-"""
- MoinMoin - Plain Text Parser
+"""MoinMoin - Parse graphviz statements into PNG images.
- @copyright: 2006, Jeff Bailey <jbailey at raspberryginger.com>
- @license: GNU GPL, see COPYING for details.
+ at copyright: 2006, Jeff Bailey <jbailey at raspberryginger.com>
+ 2007, John Arbash Meinel <john at arbash-meinel.com>
+ at license: GNU GPL, see COPYING for details.
"""
from subprocess import Popen, PIPE
from base64 import b64encode
+
Dependencies = []
-class Parser:
- """
- Parse the output through graphviz to generate output.
- """
-
+
+class Parser(object):
+ """Parse the output through graphviz to generate output."""
+
+ _dot = "/usr/bin/dot"
extensions = 'graphviz'
Dependencies = []
-
+
def __init__(self, raw, request, **kw):
self.raw = raw
self.request = request
self.form = request.form
+ # Used for i18n
self._ = request.getText
+ def _create_png(self):
+ """Create the PNG image from the raw text."""
+ fd = self._spawn_dot()
+ (myout, myerr) = fd.communicate(self.raw)
+ return myout
+
+ def _dot_command(self):
+ return [Parser._dot, "-Tpng"]
+
+ def _spawn_dot(self):
+ return Popen(self._dot_command(), stdin=PIPE, stdout=PIPE)
+
def format(self, formatter):
""" Send the text. """
- fd = Popen(["/usr/bin/dot","-Tpng"], stdin=PIPE, stdout=PIPE)
- (myout, myerr) = fd.communicate(self.raw)
+ myout = self._create_png()
encoded = b64encode(myout)
self.request.write('<img src="data:image/png;base64,')
self.request.write(encoded)
self.request.write('" alt="Graphviz Image" />')
+
+
+def test_suite():
+ import unittest
+ import test_graphviz
+
+ return unittest.TestLoader().loadTestsFromModule(test_graphviz)
+
+
+def _test():
+ import unittest
+
+ runner = unittest.TextTestRunner()
+ runner.run(test_suite())
+
+
+if __name__ == '__main__':
+ _test()
More information about the bazaar-commits
mailing list