2
# subunit: extensions to Python unittest to get test results from subprocesses.
3
# Copyright (C) 2005 Robert Collins <robertc@robertcollins.net>
5
# Licensed under either the Apache License, Version 2.0 or the BSD 3-clause
6
# license at the users choice. A copy of both licenses are available in the
7
# project source as Apache-2.0 and BSD. You may not use this file except in
8
# compliance with one of these two licences.
10
# Unless required by applicable law or agreed to in writing, software
11
# distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT
12
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13
# license you chose for the specific language governing permissions and
14
# limitations under that license.
17
"""Handlers for outcome details."""
19
from cStringIO import StringIO
21
from testtools import content, content_type
26
class DetailsParser(object):
27
"""Base class/API reference for details parsing."""
30
class SimpleDetailsParser(DetailsParser):
31
"""Parser for single-part [] delimited details."""
33
def __init__(self, state):
37
def lineReceived(self, line):
39
self._state.endDetails()
43
self._message += line[1:]
47
def get_details(self, style=None):
50
# We know that subunit/testtools serialise [] formatted
51
# tracebacks as utf8, but perhaps we need a ReplacingContent
52
# or something like that.
53
result['traceback'] = content.Content(
54
content_type.ContentType("text", "x-traceback",
56
lambda:[self._message])
62
result[name] = content.Content(
63
content_type.ContentType("text", "plain"),
64
lambda:[self._message])
67
def get_message(self):
71
class MultipartDetailsParser(DetailsParser):
72
"""Parser for multi-part [] surrounded MIME typed chunked details."""
74
def __init__(self, state):
77
self._parse_state = self._look_for_content
79
def _look_for_content(self, line):
81
self._state.endDetails()
84
field, value = line[:-1].split(' ', 1)
85
main, sub = value.split('/')
86
self._content_type = content_type.ContentType(main, sub)
87
self._parse_state = self._get_name
89
def _get_name(self, line):
90
self._name = line[:-1]
91
self._body = StringIO()
92
self._chunk_parser = chunked.Decoder(self._body)
93
self._parse_state = self._feed_chunks
95
def _feed_chunks(self, line):
96
residue = self._chunk_parser.write(line)
97
if residue is not None:
98
# Line based use always ends on no residue.
99
assert residue == '', 'residue: %r' % (residue,)
101
self._details[self._name] = content.Content(
102
self._content_type, lambda:[body.getvalue()])
103
self._chunk_parser.close()
104
self._parse_state = self._look_for_content
106
def get_details(self, for_skip=False):
109
def get_message(self):
112
def lineReceived(self, line):
113
self._parse_state(line)