summaryrefslogtreecommitdiff
path: root/python
diff options
context:
space:
mode:
authorRobert Collins <robertc@robertcollins.net>2009-10-13 12:46:15 +1100
committerRobert Collins <robertc@robertcollins.net>2009-10-13 12:46:15 +1100
commit129250bcfcdd915a1c8e71348efacdfda73d0594 (patch)
tree0d00d904d55d83ef5a09693666fe3b275d49fa96 /python
parent31a6e9bb2dcce48fe6aabe1cf6cd6bc566820b2f (diff)
downloadsubunit-git-129250bcfcdd915a1c8e71348efacdfda73d0594.tar.gz
Move details parsing into a separate class.
Diffstat (limited to 'python')
-rw-r--r--python/subunit/__init__.py36
-rw-r--r--python/subunit/details.py58
-rw-r--r--python/subunit/tests/__init__.py2
-rw-r--r--python/subunit/tests/test_details.py62
-rw-r--r--python/subunit/tests/test_test_protocol.py18
5 files changed, 158 insertions, 18 deletions
diff --git a/python/subunit/__init__.py b/python/subunit/__init__.py
index c7edf6e..b4150a3 100644
--- a/python/subunit/__init__.py
+++ b/python/subunit/__init__.py
@@ -126,7 +126,7 @@ import unittest
import iso8601
-import chunked, content, content_type
+import chunked, content, content_type, details
PROGRESS_SET = 0
@@ -256,11 +256,11 @@ class _InTest(_ParserState):
self.parser._current_test = None
elif self.parser.current_test_description + " [" == line[offset:-1]:
self.parser._state = details_state
- self.parser._message = ""
+ details_state.set_simple()
elif self.parser.current_test_description + " [ multipart" == \
line[offset:-1]:
self.parser._state = details_state
- self.parser._message = ""
+ details_state.set_multipart()
else:
self.parser.stdOutLineReceived(line)
@@ -330,7 +330,7 @@ class _OutSideTest(_ParserState):
class _ReadingDetails(_ParserState):
"""Common logic for readin state details."""
- def _endQuote(self, line):
+ def endDetails(self):
"""The end of a details section has been reached."""
self.parser._state = self.parser._outside_test
self.parser.current_test_description = None
@@ -339,9 +339,7 @@ class _ReadingDetails(_ParserState):
def lineReceived(self, line):
"""a line has been received."""
- if line == "]\n":
- self._endQuote(line)
- self.parser._appendMessage(line)
+ self.details_parser.lineReceived(line)
def lostConnection(self):
"""Connection lost."""
@@ -352,13 +350,21 @@ class _ReadingDetails(_ParserState):
"""The label to describe this outcome."""
raise NotImplementedError(self._outcome_label)
+ def set_simple(self):
+ """Start a simple details parser."""
+ self.details_parser = details.SimpleDetailsParser(self)
+
+ def set_multipart(self):
+ """Start a multipart details parser."""
+ self.details_parser = details.MultipartDetailsParser(self)
+
class _ReadingFailureDetails(_ReadingDetails):
"""State for the subunit parser when reading failure details."""
def _report_outcome(self):
self.parser.client.addFailure(self.parser._current_test,
- RemoteError(self.parser._message))
+ RemoteError(self.details_parser.get_message()))
def _outcome_label(self):
return "failure"
@@ -369,7 +375,7 @@ class _ReadingErrorDetails(_ReadingDetails):
def _report_outcome(self):
self.parser.client.addError(self.parser._current_test,
- RemoteError(self.parser._message))
+ RemoteError(self.details_parser.get_message()))
def _outcome_label(self):
return "error"
@@ -381,7 +387,8 @@ class _ReadingExpectedFailureDetails(_ReadingDetails):
def _report_outcome(self):
xfail = getattr(self.parser.client, 'addExpectedFailure', None)
if callable(xfail):
- xfail(self.parser._current_test, RemoteError(self.parser._message))
+ xfail(self.parser._current_test,
+ RemoteError(self.details_parser.get_message()))
else:
self.parser.client.addSuccess(self.parser._current_test)
@@ -393,7 +400,7 @@ class _ReadingSkipDetails(_ReadingDetails):
"""State for the subunit parser when reading skip details."""
def _report_outcome(self):
- self.parser._skip_or_error(self.parser._message)
+ self.parser._skip_or_error(self.details_parser.get_message())
def _outcome_label(self):
return "skip"
@@ -449,13 +456,6 @@ class TestProtocolServer(object):
message = "No reason given"
addSkip(self._current_test, message)
- def _appendMessage(self, line):
- if line[0:2] == " ]":
- # quoted ] start
- self._message += line[1:]
- else:
- self._message += line
-
def _handleProgress(self, offset, line):
"""Process a progress directive."""
line = line[offset:].strip()
diff --git a/python/subunit/details.py b/python/subunit/details.py
new file mode 100644
index 0000000..4f121cc
--- /dev/null
+++ b/python/subunit/details.py
@@ -0,0 +1,58 @@
+#
+# subunit: extensions to Python unittest to get test results from subprocesses.
+# Copyright (C) 2005 Robert Collins <robertc@robertcollins.net>
+#
+# Licensed under either the Apache License, Version 2.0 or the BSD 3-clause
+# license at the users choice. A copy of both licenses are available in the
+# project source as Apache-2.0 and BSD. You may not use this file except in
+# compliance with one of these two licences.
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# license you chose for the specific language governing permissions and
+# limitations under that license.
+#
+
+"""Handlers for outcome details."""
+
+class DetailsParser(object):
+ """Base class/API reference for details parsing."""
+
+
+class SimpleDetailsParser(DetailsParser):
+ """Parser for single-part [] delimited details."""
+
+ def __init__(self, state):
+ self._message = ""
+ self._state = state
+
+ def lineReceived(self, line):
+ if line == "]\n":
+ self._state.endDetails()
+ return
+ if line[0:2] == " ]":
+ # quoted ] start
+ self._message += line[1:]
+ else:
+ self._message += line
+
+ def get_details(self):
+ return None
+
+ def get_message(self):
+ return self._message
+
+
+class MultipartDetailsParser(DetailsParser):
+ """Parser for multi-part [] surrounded MIME typed chunked details."""
+
+ def __init__(self, state):
+ self._state = state
+ self._details = {}
+
+ def get_details(self):
+ return self._details
+
+ def get_message(self):
+ return None
diff --git a/python/subunit/tests/__init__.py b/python/subunit/tests/__init__.py
index 8869425..fa31d68 100644
--- a/python/subunit/tests/__init__.py
+++ b/python/subunit/tests/__init__.py
@@ -19,6 +19,7 @@ from subunit.tests import (
test_chunked,
test_content_type,
test_content,
+ test_details,
test_progress_model,
test_subunit_filter,
test_subunit_stats,
@@ -33,6 +34,7 @@ def test_suite():
result.addTest(test_chunked.test_suite())
result.addTest(test_content_type.test_suite())
result.addTest(test_content.test_suite())
+ result.addTest(test_details.test_suite())
result.addTest(test_progress_model.test_suite())
result.addTest(test_test_results.test_suite())
result.addTest(test_test_protocol.test_suite())
diff --git a/python/subunit/tests/test_details.py b/python/subunit/tests/test_details.py
new file mode 100644
index 0000000..bc0930a
--- /dev/null
+++ b/python/subunit/tests/test_details.py
@@ -0,0 +1,62 @@
+#
+# subunit: extensions to python unittest to get test results from subprocesses.
+# Copyright (C) 2005 Robert Collins <robertc@robertcollins.net>
+#
+# Licensed under either the Apache License, Version 2.0 or the BSD 3-clause
+# license at the users choice. A copy of both licenses are available in the
+# project source as Apache-2.0 and BSD. You may not use this file except in
+# compliance with one of these two licences.
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# license you chose for the specific language governing permissions and
+# limitations under that license.
+#
+
+from cStringIO import StringIO
+import unittest
+
+import subunit.tests
+from subunit import details
+
+
+def test_suite():
+ loader = subunit.tests.TestUtil.TestLoader()
+ result = loader.loadTestsFromName(__name__)
+ return result
+
+
+class TestSimpleDetails(unittest.TestCase):
+
+ def test_lineReceived(self):
+ parser = details.SimpleDetailsParser(None)
+ parser.lineReceived("foo\n")
+ parser.lineReceived("bar\n")
+ self.assertEqual("foo\nbar\n", parser._message)
+
+ def test_lineReceived_escaped_bracket(self):
+ parser = details.SimpleDetailsParser(None)
+ parser.lineReceived("foo\n")
+ parser.lineReceived(" ]are\n")
+ parser.lineReceived("bar\n")
+ self.assertEqual("foo\n]are\nbar\n", parser._message)
+
+ def test_get_message(self):
+ parser = details.SimpleDetailsParser(None)
+ self.assertEqual("", parser.get_message())
+
+ def test_get_details_is_None(self):
+ parser = details.SimpleDetailsParser(None)
+ self.assertEqual(None, parser.get_details())
+
+
+class TestMultipartDetails(unittest.TestCase):
+
+ def test_get_message_is_None(self):
+ parser = details.MultipartDetailsParser(None)
+ self.assertEqual(None, parser.get_message())
+
+ def test_get_details(self):
+ parser = details.MultipartDetailsParser(None)
+ self.assertEqual({}, parser.get_details())
diff --git a/python/subunit/tests/test_test_protocol.py b/python/subunit/tests/test_test_protocol.py
index ac8733d..0994c54 100644
--- a/python/subunit/tests/test_test_protocol.py
+++ b/python/subunit/tests/test_test_protocol.py
@@ -453,6 +453,24 @@ class TestTestProtocolServerLostConnection(unittest.TestCase):
self.do_connection_lost("xfail", "[ multipart\n")
+class TestInTestMultipart(unittest.TestCase):
+
+ def setUp(self):
+ self.client = MockTestProtocolServerClient()
+ self.protocol = subunit.TestProtocolServer(self.client)
+ self.protocol.lineReceived("test mcdonalds farm\n")
+ self.test = subunit.RemotedTestCase("mcdonalds farm")
+
+ def test__outcome_sets_details_parser(self):
+ self.protocol._reading_success_details.details_parser = None
+ self.protocol._state._outcome(0, "mcdonalds farm [ multipart\n",
+ None, self.protocol._reading_success_details)
+ parser = self.protocol._reading_success_details.details_parser
+ self.assertNotEqual(None, parser)
+ self.assertTrue(isinstance(parser,
+ subunit.details.MultipartDetailsParser))
+
+
class TestTestProtocolServerAddError(unittest.TestCase):
def setUp(self):