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 result['traceback'] = content.Content(
51 content_type.ContentType("text", "x-traceback"),
52 lambda:[self._message])
58 result[name] = content.Content(
59 content_type.ContentType("text", "plain"),
60 lambda:[self._message])
63 def get_message(self):
67 class MultipartDetailsParser(DetailsParser):
68 """Parser for multi-part [] surrounded MIME typed chunked details."""
70 def __init__(self, state):
73 self._parse_state = self._look_for_content
75 def _look_for_content(self, line):
77 self._state.endDetails()
80 field, value = line[:-1].split(' ', 1)
81 main, sub = value.split('/')
82 self._content_type = content_type.ContentType(main, sub)
83 self._parse_state = self._get_name
85 def _get_name(self, line):
86 self._name = line[:-1]
87 self._body = StringIO()
88 self._chunk_parser = chunked.Decoder(self._body)
89 self._parse_state = self._feed_chunks
91 def _feed_chunks(self, line):
92 residue = self._chunk_parser.write(line)
93 if residue is not None:
94 # Line based use always ends on no residue.
97 self._details[self._name] = content.Content(
98 self._content_type, lambda:[body.getvalue()])
99 self._chunk_parser.close()
100 self._parse_state = self._look_for_content
102 def get_details(self, for_skip=False):
105 def get_message(self):
108 def lineReceived(self, line):
109 self._parse_state(line)