s3: Fix Coverity ID 242725 Uninitialized scalar variable
[Samba/gebeck_regimport.git] / lib / subunit / python / subunit / details.py
blob9e5e005864c907d01de6bc497534c7f6553ff263
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.
9 #
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 testtools import content, content_type
20 from testtools.compat import _b, BytesIO
22 from subunit import chunked
24 end_marker = _b("]\n")
25 quoted_marker = _b(" ]")
26 empty = _b('')
29 class DetailsParser(object):
30 """Base class/API reference for details parsing."""
33 class SimpleDetailsParser(DetailsParser):
34 """Parser for single-part [] delimited details."""
36 def __init__(self, state):
37 self._message = _b("")
38 self._state = state
40 def lineReceived(self, line):
41 if line == end_marker:
42 self._state.endDetails()
43 return
44 if line[0:2] == quoted_marker:
45 # quoted ] start
46 self._message += line[1:]
47 else:
48 self._message += line
50 def get_details(self, style=None):
51 result = {}
52 if not style:
53 # We know that subunit/testtools serialise [] formatted
54 # tracebacks as utf8, but perhaps we need a ReplacingContent
55 # or something like that.
56 result['traceback'] = content.Content(
57 content_type.ContentType("text", "x-traceback",
58 {"charset": "utf8"}),
59 lambda:[self._message])
60 else:
61 if style == 'skip':
62 name = 'reason'
63 else:
64 name = 'message'
65 result[name] = content.Content(
66 content_type.ContentType("text", "plain"),
67 lambda:[self._message])
68 return result
70 def get_message(self):
71 return self._message
74 class MultipartDetailsParser(DetailsParser):
75 """Parser for multi-part [] surrounded MIME typed chunked details."""
77 def __init__(self, state):
78 self._state = state
79 self._details = {}
80 self._parse_state = self._look_for_content
82 def _look_for_content(self, line):
83 if line == end_marker:
84 self._state.endDetails()
85 return
86 # TODO error handling
87 field, value = line[:-1].decode('utf8').split(' ', 1)
88 try:
89 main, sub = value.split('/')
90 except ValueError:
91 raise ValueError("Invalid MIME type %r" % value)
92 self._content_type = content_type.ContentType(main, sub)
93 self._parse_state = self._get_name
95 def _get_name(self, line):
96 self._name = line[:-1].decode('utf8')
97 self._body = BytesIO()
98 self._chunk_parser = chunked.Decoder(self._body)
99 self._parse_state = self._feed_chunks
101 def _feed_chunks(self, line):
102 residue = self._chunk_parser.write(line)
103 if residue is not None:
104 # Line based use always ends on no residue.
105 assert residue == empty, 'residue: %r' % (residue,)
106 body = self._body
107 self._details[self._name] = content.Content(
108 self._content_type, lambda:[body.getvalue()])
109 self._chunk_parser.close()
110 self._parse_state = self._look_for_content
112 def get_details(self, for_skip=False):
113 return self._details
115 def get_message(self):
116 return None
118 def lineReceived(self, line):
119 self._parse_state(line)