Merge lp:~laurynas-biveinis/percona-server/bug1282599-5.5 into lp:percona-server/5.5

Proposed by Laurynas Biveinis
Status: Merged
Approved by: Laurynas Biveinis
Approved revision: no longer in the source branch.
Merged at revision: 712
Proposed branch: lp:~laurynas-biveinis/percona-server/bug1282599-5.5
Merge into: lp:percona-server/5.5
Diff against target: 16856 lines (+0/-16518)
66 files modified
python-for-subunit2junitxml/BytesIO.py (+0/-136)
python-for-subunit2junitxml/iso8601/LICENSE (+0/-20)
python-for-subunit2junitxml/iso8601/README (+0/-26)
python-for-subunit2junitxml/iso8601/README.subunit (+0/-5)
python-for-subunit2junitxml/iso8601/setup.py (+0/-58)
python-for-subunit2junitxml/iso8601/test_iso8601.py (+0/-111)
python-for-subunit2junitxml/junitxml/__init__.py (+0/-221)
python-for-subunit2junitxml/junitxml/tests/__init__.py (+0/-16)
python-for-subunit2junitxml/junitxml/tests/test_junitxml.py (+0/-327)
python-for-subunit2junitxml/subunit/__init__.py (+0/-1250)
python-for-subunit2junitxml/subunit/chunked.py (+0/-185)
python-for-subunit2junitxml/subunit/details.py (+0/-119)
python-for-subunit2junitxml/subunit/iso8601.py (+0/-133)
python-for-subunit2junitxml/subunit/progress_model.py (+0/-106)
python-for-subunit2junitxml/subunit/run.py (+0/-73)
python-for-subunit2junitxml/subunit/test_results.py (+0/-492)
python-for-subunit2junitxml/subunit/tests/TestUtil.py (+0/-80)
python-for-subunit2junitxml/subunit/tests/__init__.py (+0/-41)
python-for-subunit2junitxml/subunit/tests/sample-script.py (+0/-21)
python-for-subunit2junitxml/subunit/tests/sample-two-script.py (+0/-7)
python-for-subunit2junitxml/subunit/tests/test_chunked.py (+0/-152)
python-for-subunit2junitxml/subunit/tests/test_details.py (+0/-112)
python-for-subunit2junitxml/subunit/tests/test_progress_model.py (+0/-118)
python-for-subunit2junitxml/subunit/tests/test_subunit_filter.py (+0/-208)
python-for-subunit2junitxml/subunit/tests/test_subunit_stats.py (+0/-84)
python-for-subunit2junitxml/subunit/tests/test_subunit_tags.py (+0/-69)
python-for-subunit2junitxml/subunit/tests/test_tap2subunit.py (+0/-445)
python-for-subunit2junitxml/subunit/tests/test_test_protocol.py (+0/-1299)
python-for-subunit2junitxml/subunit/tests/test_test_results.py (+0/-300)
python-for-subunit2junitxml/testtools/__init__.py (+0/-80)
python-for-subunit2junitxml/testtools/_spinner.py (+0/-316)
python-for-subunit2junitxml/testtools/compat.py (+0/-286)
python-for-subunit2junitxml/testtools/content.py (+0/-238)
python-for-subunit2junitxml/testtools/content_type.py (+0/-33)
python-for-subunit2junitxml/testtools/deferredruntest.py (+0/-335)
python-for-subunit2junitxml/testtools/distutilscmd.py (+0/-62)
python-for-subunit2junitxml/testtools/helpers.py (+0/-64)
python-for-subunit2junitxml/testtools/matchers.py (+0/-785)
python-for-subunit2junitxml/testtools/monkey.py (+0/-97)
python-for-subunit2junitxml/testtools/run.py (+0/-332)
python-for-subunit2junitxml/testtools/runtest.py (+0/-200)
python-for-subunit2junitxml/testtools/testcase.py (+0/-724)
python-for-subunit2junitxml/testtools/testresult/__init__.py (+0/-19)
python-for-subunit2junitxml/testtools/testresult/doubles.py (+0/-111)
python-for-subunit2junitxml/testtools/testresult/real.py (+0/-621)
python-for-subunit2junitxml/testtools/tests/__init__.py (+0/-44)
python-for-subunit2junitxml/testtools/tests/helpers.py (+0/-72)
python-for-subunit2junitxml/testtools/tests/test_compat.py (+0/-257)
python-for-subunit2junitxml/testtools/tests/test_content.py (+0/-223)
python-for-subunit2junitxml/testtools/tests/test_content_type.py (+0/-46)
python-for-subunit2junitxml/testtools/tests/test_deferredruntest.py (+0/-738)
python-for-subunit2junitxml/testtools/tests/test_distutilscmd.py (+0/-90)
python-for-subunit2junitxml/testtools/tests/test_fixturesupport.py (+0/-79)
python-for-subunit2junitxml/testtools/tests/test_helpers.py (+0/-106)
python-for-subunit2junitxml/testtools/tests/test_matchers.py (+0/-695)
python-for-subunit2junitxml/testtools/tests/test_monkey.py (+0/-167)
python-for-subunit2junitxml/testtools/tests/test_run.py (+0/-77)
python-for-subunit2junitxml/testtools/tests/test_runtest.py (+0/-300)
python-for-subunit2junitxml/testtools/tests/test_spinner.py (+0/-332)
python-for-subunit2junitxml/testtools/tests/test_testresult.py (+0/-1372)
python-for-subunit2junitxml/testtools/tests/test_testsuite.py (+0/-53)
python-for-subunit2junitxml/testtools/tests/test_testtools.py (+0/-1143)
python-for-subunit2junitxml/testtools/tests/test_with_with.py (+0/-42)
python-for-subunit2junitxml/testtools/testsuite.py (+0/-87)
python-for-subunit2junitxml/testtools/utils.py (+0/-13)
subunit2junitxml (+0/-65)
To merge this branch: bzr merge lp:~laurynas-biveinis/percona-server/bug1282599-5.5
Reviewer Review Type Date Requested Status
Laurynas Biveinis (community) Approve
Review via email: mp+239008@code.launchpad.net

Description of the change

Fix bug 1282599 (python-for-subunit2junitxml should be removed from
source tree) by removing the subunit2junitxml script and
python-for-subunit2junitxml directory.

http://jenkins.percona.com/job/percona-server-5.5-param/1061/

To post a comment you must log in.
Revision history for this message
Laurynas Biveinis (laurynas-biveinis) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== removed directory 'python-for-subunit2junitxml'
2=== removed file 'python-for-subunit2junitxml/BytesIO.py'
3--- python-for-subunit2junitxml/BytesIO.py 2013-05-27 13:46:13 +0000
4+++ python-for-subunit2junitxml/BytesIO.py 1970-01-01 00:00:00 +0000
5@@ -1,136 +0,0 @@
6-
7-# http://wiki.python.org/moin/BytesIO
8-#
9-# A skeleton one used for systems that don't have BytesIO.
10-#
11-# It's enough for subunit at least....
12-
13-class BytesIO(object):
14- """ A file-like API for reading and writing bytes objects.
15-
16- Mostly like StringIO, but write() calls modify the underlying
17- bytes object.
18-
19- >>> b = bytes()
20- >>> f = BytesIO(b, 'w')
21- >>> f.write(bytes.fromhex('ca fe ba be'))
22- >>> f.write(bytes.fromhex('57 41 56 45'))
23- >>> b
24- bytes([202, 254, 186, 190, 87, 65, 86, 69])
25- """
26-
27- def __init__(self, buf, mode='r'):
28- """ Create a new BytesIO for reading or writing the given buffer.
29-
30- buf - Back-end buffer for this BytesIO. A bytes object.
31- Actually, anything that supports len(), slice-assignment,
32- and += will work.
33- mode - One of 'r', 'w', 'a'.
34- An optional 'b' is also allowed, but it doesn't do anything.
35- """
36- # XXX many 'mode' possibilities aren't allowed yet: 'rw+Ut'
37- if len(mode) == 2 and mode[-1] == 'b':
38- mode = mode[:-1] # binary mode goes without saying
39- if mode not in ('r', 'w', 'a'):
40- raise ValueError("mode must be 'r', 'w', or 'a'")
41-
42- self._buf = buf
43- self.mode = mode
44- self.closed = False
45- if self.mode == 'w':
46- del buf[:]
47- self._point = 0
48- elif self.mode == 'r':
49- self._point = 0
50- else: # 'a'
51- self._point = len(buf)
52-
53- def close(self):
54- self.closed = True
55-
56- def _check_closed(self):
57- if self.closed:
58- raise ValueError("file is closed")
59-
60- def flush(self):
61- self._check_closed()
62-
63- def next(self):
64- line = self.readline()
65- if len(line) == 0:
66- raise StopIteration
67- return line
68-
69- def read(self, size=None):
70- self._check_closed()
71- if size is None:
72- e = len(self._buf)
73- else:
74- e = min(self._point + size, len(self._buf))
75- r = self._buf[self._point:e]
76- self._point = e
77- return r
78-
79- def readline(self, size=None):
80- self._check_closed()
81- die # XXX TODO - assume ascii and read a line
82-
83- def readlines(self, sizehint=None):
84- # XXX TODO handle sizehint
85- return list(self)
86-
87- def seek(self, offset, whence=0):
88- self._check_closed()
89-
90- if whence == 0:
91- self._point = offset
92- elif whence == 1:
93- self._point += offset
94- elif whence == 2:
95- self._point = len(self._buf) + offset
96- else:
97- raise ValueError("whence must be 0, 1, or 2")
98-
99- if self._point < 0:
100- self._point = 0 # XXX is this right?
101-
102- def tell(self):
103- self._check_closed()
104- return self._point
105-
106- def truncate(self, size=None):
107- self._check_closed()
108- if size is None:
109- size = self.tell()
110- del self._buf[size:]
111-
112- def write(self, data):
113- self._check_closed()
114- amt = len(data)
115- size = len(self._buf)
116- if self.mode == 'a':
117- self._point = size
118-
119- if self._point > size:
120- if isinstance(b, bytes):
121- blank = bytes([0])
122- else:
123- # Don't know what default value to insert, unfortunately
124- raise ValueError("can't write past the end of this object")
125- self._buf += blank * (self._point - size) + data
126- self._point = len(self._buf)
127- else:
128- p = self._point
129- self._buf[p:p + amt] = data
130- self._point = min(p + amt, len(self._buf))
131-
132- def writelines(self, seq):
133- for line in seq:
134- self.write(line)
135-
136- def __iter__(self):
137- return self
138-
139- @property
140- def name(self):
141- return repr(self)
142
143=== removed directory 'python-for-subunit2junitxml/iso8601'
144=== removed file 'python-for-subunit2junitxml/iso8601/LICENSE'
145--- python-for-subunit2junitxml/iso8601/LICENSE 2013-05-27 13:46:13 +0000
146+++ python-for-subunit2junitxml/iso8601/LICENSE 1970-01-01 00:00:00 +0000
147@@ -1,20 +0,0 @@
148-Copyright (c) 2007 Michael Twomey
149-
150-Permission is hereby granted, free of charge, to any person obtaining a
151-copy of this software and associated documentation files (the
152-"Software"), to deal in the Software without restriction, including
153-without limitation the rights to use, copy, modify, merge, publish,
154-distribute, sublicense, and/or sell copies of the Software, and to
155-permit persons to whom the Software is furnished to do so, subject to
156-the following conditions:
157-
158-The above copyright notice and this permission notice shall be included
159-in all copies or substantial portions of the Software.
160-
161-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
162-OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
163-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
164-IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
165-CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
166-TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
167-SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
168
169=== removed file 'python-for-subunit2junitxml/iso8601/README'
170--- python-for-subunit2junitxml/iso8601/README 2013-05-27 13:46:13 +0000
171+++ python-for-subunit2junitxml/iso8601/README 1970-01-01 00:00:00 +0000
172@@ -1,26 +0,0 @@
173-A simple package to deal with ISO 8601 date time formats.
174-
175-ISO 8601 defines a neutral, unambiguous date string format, which also
176-has the property of sorting naturally.
177-
178-e.g. YYYY-MM-DDTHH:MM:SSZ or 2007-01-25T12:00:00Z
179-
180-Currently this covers only the most common date formats encountered, not
181-all of ISO 8601 is handled.
182-
183-Currently the following formats are handled:
184-
185-* 2006-01-01T00:00:00Z
186-* 2006-01-01T00:00:00[+-]00:00
187-
188-I'll add more as I encounter them in my day to day life. Patches with
189-new formats and tests will be gratefully accepted of course :)
190-
191-References:
192-
193-* http://www.cl.cam.ac.uk/~mgk25/iso-time.html - simple overview
194-
195-* http://hydracen.com/dx/iso8601.htm - more detailed enumeration of
196- valid formats.
197-
198-See the LICENSE file for the license this package is released under.
199
200=== removed file 'python-for-subunit2junitxml/iso8601/README.subunit'
201--- python-for-subunit2junitxml/iso8601/README.subunit 2013-05-27 13:46:13 +0000
202+++ python-for-subunit2junitxml/iso8601/README.subunit 1970-01-01 00:00:00 +0000
203@@ -1,5 +0,0 @@
204-This is a [slightly rearranged] import of http://pypi.python.org/pypi/iso8601/
205-version 0.1.4. The OS X hidden files have been stripped, and the package
206-turned into a single module, to simplify installation. The remainder of the
207-source distribution is included in the subunit source tree at python/iso8601
208-for reference.
209
210=== removed file 'python-for-subunit2junitxml/iso8601/setup.py'
211--- python-for-subunit2junitxml/iso8601/setup.py 2013-05-27 13:46:13 +0000
212+++ python-for-subunit2junitxml/iso8601/setup.py 1970-01-01 00:00:00 +0000
213@@ -1,58 +0,0 @@
214-try:
215- from setuptools import setup
216-except ImportError:
217- from distutils import setup
218-
219-long_description="""Simple module to parse ISO 8601 dates
220-
221-This module parses the most common forms of ISO 8601 date strings (e.g.
222-2007-01-14T20:34:22+00:00) into datetime objects.
223-
224->>> import iso8601
225->>> iso8601.parse_date("2007-01-25T12:00:00Z")
226-datetime.datetime(2007, 1, 25, 12, 0, tzinfo=<iso8601.iso8601.Utc ...>)
227->>>
228-
229-Changes
230-=======
231-
232-0.1.4
233------
234-
235-* The default_timezone argument wasn't being passed through correctly,
236- UTC was being used in every case. Fixes issue 10.
237-
238-0.1.3
239------
240-
241-* Fixed the microsecond handling, the generated microsecond values were
242- way too small. Fixes issue 9.
243-
244-0.1.2
245------
246-
247-* Adding ParseError to __all__ in iso8601 module, allows people to import it.
248- Addresses issue 7.
249-* Be a little more flexible when dealing with dates without leading zeroes.
250- This violates the spec a little, but handles more dates as seen in the
251- field. Addresses issue 6.
252-* Allow date/time separators other than T.
253-
254-0.1.1
255------
256-
257-* When parsing dates without a timezone the specified default is used. If no
258- default is specified then UTC is used. Addresses issue 4.
259-"""
260-
261-setup(
262- name="iso8601",
263- version="0.1.4",
264- description=long_description.split("\n")[0],
265- long_description=long_description,
266- author="Michael Twomey",
267- author_email="micktwomey+iso8601@gmail.com",
268- url="http://code.google.com/p/pyiso8601/",
269- packages=["iso8601"],
270- license="MIT",
271-)
272
273=== removed file 'python-for-subunit2junitxml/iso8601/test_iso8601.py'
274--- python-for-subunit2junitxml/iso8601/test_iso8601.py 2013-05-27 13:46:13 +0000
275+++ python-for-subunit2junitxml/iso8601/test_iso8601.py 1970-01-01 00:00:00 +0000
276@@ -1,111 +0,0 @@
277-import iso8601
278-
279-def test_iso8601_regex():
280- assert iso8601.ISO8601_REGEX.match("2006-10-11T00:14:33Z")
281-
282-def test_timezone_regex():
283- assert iso8601.TIMEZONE_REGEX.match("+01:00")
284- assert iso8601.TIMEZONE_REGEX.match("+00:00")
285- assert iso8601.TIMEZONE_REGEX.match("+01:20")
286- assert iso8601.TIMEZONE_REGEX.match("-01:00")
287-
288-def test_parse_date():
289- d = iso8601.parse_date("2006-10-20T15:34:56Z")
290- assert d.year == 2006
291- assert d.month == 10
292- assert d.day == 20
293- assert d.hour == 15
294- assert d.minute == 34
295- assert d.second == 56
296- assert d.tzinfo == iso8601.UTC
297-
298-def test_parse_date_fraction():
299- d = iso8601.parse_date("2006-10-20T15:34:56.123Z")
300- assert d.year == 2006
301- assert d.month == 10
302- assert d.day == 20
303- assert d.hour == 15
304- assert d.minute == 34
305- assert d.second == 56
306- assert d.microsecond == 123000
307- assert d.tzinfo == iso8601.UTC
308-
309-def test_parse_date_fraction_2():
310- """From bug 6
311-
312- """
313- d = iso8601.parse_date("2007-5-7T11:43:55.328Z'")
314- assert d.year == 2007
315- assert d.month == 5
316- assert d.day == 7
317- assert d.hour == 11
318- assert d.minute == 43
319- assert d.second == 55
320- assert d.microsecond == 328000
321- assert d.tzinfo == iso8601.UTC
322-
323-def test_parse_date_tz():
324- d = iso8601.parse_date("2006-10-20T15:34:56.123+02:30")
325- assert d.year == 2006
326- assert d.month == 10
327- assert d.day == 20
328- assert d.hour == 15
329- assert d.minute == 34
330- assert d.second == 56
331- assert d.microsecond == 123000
332- assert d.tzinfo.tzname(None) == "+02:30"
333- offset = d.tzinfo.utcoffset(None)
334- assert offset.days == 0
335- assert offset.seconds == 60 * 60 * 2.5
336-
337-def test_parse_invalid_date():
338- try:
339- iso8601.parse_date(None)
340- except iso8601.ParseError:
341- pass
342- else:
343- assert 1 == 2
344-
345-def test_parse_invalid_date2():
346- try:
347- iso8601.parse_date("23")
348- except iso8601.ParseError:
349- pass
350- else:
351- assert 1 == 2
352-
353-def test_parse_no_timezone():
354- """issue 4 - Handle datetime string without timezone
355-
356- This tests what happens when you parse a date with no timezone. While not
357- strictly correct this is quite common. I'll assume UTC for the time zone
358- in this case.
359- """
360- d = iso8601.parse_date("2007-01-01T08:00:00")
361- assert d.year == 2007
362- assert d.month == 1
363- assert d.day == 1
364- assert d.hour == 8
365- assert d.minute == 0
366- assert d.second == 0
367- assert d.microsecond == 0
368- assert d.tzinfo == iso8601.UTC
369-
370-def test_parse_no_timezone_different_default():
371- tz = iso8601.FixedOffset(2, 0, "test offset")
372- d = iso8601.parse_date("2007-01-01T08:00:00", default_timezone=tz)
373- assert d.tzinfo == tz
374-
375-def test_space_separator():
376- """Handle a separator other than T
377-
378- """
379- d = iso8601.parse_date("2007-06-23 06:40:34.00Z")
380- assert d.year == 2007
381- assert d.month == 6
382- assert d.day == 23
383- assert d.hour == 6
384- assert d.minute == 40
385- assert d.second == 34
386- assert d.microsecond == 0
387- assert d.tzinfo == iso8601.UTC
388
389=== removed directory 'python-for-subunit2junitxml/junitxml'
390=== removed file 'python-for-subunit2junitxml/junitxml/__init__.py'
391--- python-for-subunit2junitxml/junitxml/__init__.py 2013-05-27 13:46:13 +0000
392+++ python-for-subunit2junitxml/junitxml/__init__.py 1970-01-01 00:00:00 +0000
393@@ -1,221 +0,0 @@
394-#
395-# junitxml: extensions to Python unittest to get output junitxml
396-# Copyright (C) 2009 Robert Collins <robertc@robertcollins.net>
397-#
398-# Copying permitted under the LGPL-3 licence, included with this library.
399-
400-"""unittest compatible JUnit XML output."""
401-
402-
403-import datetime
404-import re
405-import time
406-import unittest
407-
408-# same format as sys.version_info: "A tuple containing the five components of
409-# the version number: major, minor, micro, releaselevel, and serial. All
410-# values except releaselevel are integers; the release level is 'alpha',
411-# 'beta', 'candidate', or 'final'. The version_info value corresponding to the
412-# Python version 2.0 is (2, 0, 0, 'final', 0)." Additionally we use a
413-# releaselevel of 'dev' for unreleased under-development code.
414-#
415-# If the releaselevel is 'alpha' then the major/minor/micro components are not
416-# established at this point, and setup.py will use a version of next-$(revno).
417-# If the releaselevel is 'final', then the tarball will be major.minor.micro.
418-# Otherwise it is major.minor.micro~$(revno).
419-__version__ = (0, 7, 0, 'alpha', 0)
420-
421-
422-def test_suite():
423- import junitxml.tests
424- return junitxml.tests.test_suite()
425-
426-
427-class LocalTimezone(datetime.tzinfo):
428-
429- def __init__(self):
430- self._offset = None
431-
432- # It seems that the minimal possible implementation is to just return all
433- # None for every function, but then it breaks...
434- def utcoffset(self, dt):
435- if self._offset is None:
436- t = 1260423030 # arbitrary, but doesn't handle dst very well
437- dt = datetime.datetime
438- self._offset = (dt.fromtimestamp(t) - dt.utcfromtimestamp(t))
439- return self._offset
440-
441- def dst(self, dt):
442- return datetime.timedelta(0)
443-
444- def tzname(self, dt):
445- return None
446-
447-
448-def _error_name(eclass):
449- module = eclass.__module__
450- if module not in ("__main__", "builtins", "exceptions"):
451- return ".".join([module, eclass.__name__])
452- return eclass.__name__
453-
454-
455-_non_cdata = "[\0-\b\x0B-\x1F\uD800-\uDFFF\uFFFE\uFFFF]+"
456-if "\\u" in _non_cdata:
457- _non_cdata = _non_cdata.decode("unicode-escape")
458- def _strip_invalid_chars(s, _sub=re.compile(_non_cdata, re.UNICODE).sub):
459- if not isinstance(s, unicode):
460- try:
461- s = s.decode("utf-8")
462- except UnicodeDecodeError:
463- s = s.decode("ascii", "replace")
464- return _sub("", s).encode("utf-8")
465-else:
466- def _strip_invalid_chars(s, _sub=re.compile(_non_cdata, re.UNICODE).sub):
467- return _sub("", s)
468-def _escape_content(s):
469- return (_strip_invalid_chars(s)
470- .replace("&", "&amp;")
471- .replace("<", "&lt;")
472- .replace("]]>", "]]&gt;"))
473-def _escape_attr(s):
474- return (_strip_invalid_chars(s)
475- .replace("&", "&amp;")
476- .replace("<", "&lt;")
477- .replace("]]>", "]]&gt;")
478- .replace('"', "&quot;")
479- .replace("\t", "&#x9;")
480- .replace("\n", "&#xA;"))
481-
482-
483-class JUnitXmlResult(unittest.TestResult):
484- """A TestResult which outputs JUnit compatible XML."""
485-
486- def __init__(self, stream):
487- """Create a JUnitXmlResult.
488-
489- :param stream: A stream to write results to. Note that due to the
490- nature of JUnit XML output, nnothing will be written to the stream
491- until stopTestRun() is called.
492- """
493- self.__super = super(JUnitXmlResult, self)
494- self.__super.__init__()
495- # GZ 2010-09-03: We have a problem if passed a text stream in Python 3
496- # as really we want to write raw UTF-8 to ensure that
497- # the encoding is not mangled later
498- self._stream = stream
499- self._results = []
500- self._set_time = None
501- self._test_start = None
502- self._run_start = None
503- self._tz_info = None
504-
505- def startTestRun(self):
506- """Start a test run."""
507- self._run_start = self._now()
508-
509- def _get_tzinfo(self):
510- if self._tz_info is None:
511- self._tz_info = LocalTimezone()
512- return self._tz_info
513-
514- def _now(self):
515- if self._set_time is not None:
516- return self._set_time
517- else:
518- return datetime.datetime.now(self._get_tzinfo())
519-
520- def time(self, a_datetime):
521- self._set_time = a_datetime
522- if (self._run_start is not None and
523- self._run_start > a_datetime):
524- self._run_start = a_datetime
525-
526- def startTest(self, test):
527- self.__super.startTest(test)
528- self._test_start = self._now()
529-
530- def _duration(self, from_datetime):
531- try:
532- delta = self._now() - from_datetime
533- except TypeError:
534- n = self._now()
535- delta = datetime.timedelta(-1)
536- seconds = delta.days * 3600*24 + delta.seconds
537- return seconds + 0.000001 * delta.microseconds
538-
539- def _test_case_string(self, test):
540- duration = self._duration(self._test_start)
541- test_id = test.id()
542- # Split on the last dot not inside a parameter
543- class_end = test_id.rfind(".", 0, test_id.find("("))
544- if class_end == -1:
545- classname, name = "", test_id
546- else:
547- classname, name = test_id[:class_end], test_id[class_end+1:]
548- self._results.append('<testcase classname="%s" name="%s" '
549- 'time="%0.3f"' % (_escape_attr(classname), _escape_attr(name), duration))
550-
551- def stopTestRun(self):
552- """Stop a test run.
553-
554- This allows JUnitXmlResult to output the XML representation of the test
555- run.
556- """
557- duration = self._duration(self._run_start)
558- self._stream.write('<testsuite errors="%d" failures="%d" name="" '
559- 'tests="%d" time="%0.3f">\n' % (len(self.errors),
560- len(self.failures) + len(getattr(self, "unexpectedSuccesses", ())),
561- self.testsRun, duration))
562- self._stream.write(''.join(self._results))
563- self._stream.write('</testsuite>\n')
564-
565- def addError(self, test, error):
566- self.__super.addError(test, error)
567- self._test_case_string(test)
568- self._results.append('>\n')
569- self._results.append('<error type="%s">%s</error>\n</testcase>\n' % (
570- _escape_attr(_error_name(error[0])),
571- _escape_content(self._exc_info_to_string(error, test))))
572-
573- def addFailure(self, test, error):
574- self.__super.addFailure(test, error)
575- self._test_case_string(test)
576- self._results.append('>\n')
577- self._results.append('<failure type="%s">%s</failure>\n</testcase>\n' %
578- (_escape_attr(_error_name(error[0])),
579- _escape_content(self._exc_info_to_string(error, test))))
580-
581- def addSuccess(self, test):
582- self.__super.addSuccess(test)
583- self._test_case_string(test)
584- self._results.append('/>\n')
585-
586- def addSkip(self, test, reason):
587- try:
588- self.__super.addSkip(test, reason)
589- except AttributeError:
590- # Python < 2.7|3.1
591- pass
592- self._test_case_string(test)
593- self._results.append('>\n')
594- self._results.append('<skip>%s</skip>\n</testcase>\n'% _escape_attr(reason))
595-
596- def addUnexpectedSuccess(self, test):
597- try:
598- self.__super.addUnexpectedSuccess(test)
599- except AttributeError:
600- # Python < 2.7|3.1
601- pass
602- self._test_case_string(test)
603- self._results.append('>\n')
604- self._results.append('<failure type="unittest.case._UnexpectedSuccess"/>\n</testcase>\n')
605-
606- def addExpectedFailure(self, test, error):
607- try:
608- self.__super.addExpectedFailure(test, error)
609- except AttributeError:
610- # Python < 2.7|3.1
611- pass
612- self._test_case_string(test)
613- self._results.append('/>\n')
614-
615
616=== removed directory 'python-for-subunit2junitxml/junitxml/tests'
617=== removed file 'python-for-subunit2junitxml/junitxml/tests/__init__.py'
618--- python-for-subunit2junitxml/junitxml/tests/__init__.py 2013-05-27 13:46:13 +0000
619+++ python-for-subunit2junitxml/junitxml/tests/__init__.py 1970-01-01 00:00:00 +0000
620@@ -1,16 +0,0 @@
621-#
622-# junitxml: extensions to Python unittest to get output junitxml
623-# Copyright (C) 2009 Robert Collins <robertc@robertcollins.net>
624-#
625-# Copying permitted under the LGPL-3 licence, included with this library.
626-
627-import unittest
628-
629-from junitxml.tests import (
630- test_junitxml,
631- )
632-
633-def test_suite():
634- return unittest.TestLoader().loadTestsFromNames([
635- 'junitxml.tests.test_junitxml',
636- ])
637
638=== removed file 'python-for-subunit2junitxml/junitxml/tests/test_junitxml.py'
639--- python-for-subunit2junitxml/junitxml/tests/test_junitxml.py 2013-05-27 13:46:13 +0000
640+++ python-for-subunit2junitxml/junitxml/tests/test_junitxml.py 1970-01-01 00:00:00 +0000
641@@ -1,327 +0,0 @@
642-#
643-# junitxml: extensions to Python unittest to get output junitxml
644-# Copyright (C) 2009 Robert Collins <robertc@robertcollins.net>
645-#
646-# Copying permitted under the LGPL-3 licence, included with this library.
647-
648-
649-try:
650- from cStringIO import StringIO
651-except ImportError:
652- from io import StringIO
653-import datetime
654-import re
655-import sys
656-import unittest
657-import xml.dom.minidom
658-
659-import junitxml
660-
661-class TestImports(unittest.TestCase):
662-
663- def test_result(self):
664- from junitxml import JUnitXmlResult
665-
666-
667-class TestJUnitXmlResult__init__(unittest.TestCase):
668-
669- def test_with_stream(self):
670- result = junitxml.JUnitXmlResult(StringIO())
671-
672-
673-class TestJUnitXmlResult(unittest.TestCase):
674-
675- def setUp(self):
676- self.output = StringIO()
677- self.result = junitxml.JUnitXmlResult(self.output)
678-
679- def get_output(self):
680- output = self.output.getvalue()
681- # Collapse detailed regions into specific strings we can match on
682- return re.sub(r'(?s)<failure (.*?)>.*?</failure>',
683- r'<failure \1>failure</failure>', re.sub(
684- r'(?s)<error (.*?)>.*?</error>', r'<error \1>error</error>',
685- re.sub(r'time="\d+\.\d+"', 'time="0.000"', output)))
686-
687- def run_test_or_simulate(self, test, method_name, manual_method,
688- *manual_args):
689- if getattr(test, method_name, None):
690- test.run(self.result)
691- else:
692- # older python - manually execute
693- self.result.startTest(test)
694- manual_method(test, *manual_args)
695- self.result.stopTest(test)
696-
697- def test_run_duration_handles_datestamping_in_the_past(self):
698- # When used via subunit2junitxml, startTestRun is called before
699- # any tz info in the test stream has been seen.
700- # So, we use the earliest reported timestamp as the start time,
701- # replacing _test_start if needed.
702- self.result.startTestRun() # the time is now.
703- # Lose an hour (peeks inside, a little naughty but not very).
704- self.result.time(self.result._run_start - datetime.timedelta(0, 3600))
705- self.result.stopTestRun()
706- self.assertEqual("""<testsuite errors="0" failures="0" name="" tests="0" time="0.000">
707-</testsuite>
708-""", self.get_output())
709-
710- def test_startTestRun_no_output(self):
711- # startTestRun doesn't output anything, because JUnit wants an up-front
712- # summary.
713- self.result.startTestRun()
714- self.assertEqual('', self.get_output())
715-
716- def test_stopTestRun_outputs(self):
717- # When stopTestRun is called, everything is output.
718- self.result.startTestRun()
719- self.result.stopTestRun()
720- self.assertEqual("""<testsuite errors="0" failures="0" name="" tests="0" time="0.000">
721-</testsuite>
722-""", self.get_output())
723-
724- def test_test_count(self):
725- class Passes(unittest.TestCase):
726- def test_me(self):
727- pass
728- self.result.startTestRun()
729- Passes("test_me").run(self.result)
730- Passes("test_me").run(self.result)
731- self.result.stopTestRun()
732- # When tests are run, the number of tests is counted.
733- output = self.get_output()
734- self.assertTrue('tests="2"' in output)
735-
736- def test_test_id_with_parameter(self):
737- class Passes(unittest.TestCase):
738- def id(self):
739- return unittest.TestCase.id(self) + '(version_1.6)'
740- def test_me(self):
741- pass
742- self.result.startTestRun()
743- Passes("test_me").run(self.result)
744- self.result.stopTestRun()
745- output = self.get_output()
746- self.assertTrue('Passes" name="test_me(version_1.6)"' in output)
747-
748- def test_erroring_test(self):
749- class Errors(unittest.TestCase):
750- def test_me(self):
751- 1/0
752- self.result.startTestRun()
753- Errors("test_me").run(self.result)
754- self.result.stopTestRun()
755- self.assertEqual("""<testsuite errors="1" failures="0" name="" tests="1" time="0.000">
756-<testcase classname="junitxml.tests.test_junitxml.Errors" name="test_me" time="0.000">
757-<error type="ZeroDivisionError">error</error>
758-</testcase>
759-</testsuite>
760-""", self.get_output())
761-
762- def test_failing_test(self):
763- class Fails(unittest.TestCase):
764- def test_me(self):
765- self.fail()
766- self.result.startTestRun()
767- Fails("test_me").run(self.result)
768- self.result.stopTestRun()
769- self.assertEqual("""<testsuite errors="0" failures="1" name="" tests="1" time="0.000">
770-<testcase classname="junitxml.tests.test_junitxml.Fails" name="test_me" time="0.000">
771-<failure type="AssertionError">failure</failure>
772-</testcase>
773-</testsuite>
774-""", self.get_output())
775-
776- def test_successful_test(self):
777- class Passes(unittest.TestCase):
778- def test_me(self):
779- pass
780- self.result.startTestRun()
781- Passes("test_me").run(self.result)
782- self.result.stopTestRun()
783- self.assertEqual("""<testsuite errors="0" failures="0" name="" tests="1" time="0.000">
784-<testcase classname="junitxml.tests.test_junitxml.Passes" name="test_me" time="0.000"/>
785-</testsuite>
786-""", self.get_output())
787-
788- def test_skip_test(self):
789- class Skips(unittest.TestCase):
790- def test_me(self):
791- self.skipTest("yo")
792- self.result.startTestRun()
793- test = Skips("test_me")
794- self.run_test_or_simulate(test, 'skipTest', self.result.addSkip, 'yo')
795- self.result.stopTestRun()
796- output = self.get_output()
797- expected = """<testsuite errors="0" failures="0" name="" tests="1" time="0.000">
798-<testcase classname="junitxml.tests.test_junitxml.Skips" name="test_me" time="0.000">
799-<skip>yo</skip>
800-</testcase>
801-</testsuite>
802-"""
803- self.assertEqual(expected, output)
804-
805- def test_unexpected_success_test(self):
806- class Succeeds(unittest.TestCase):
807- def test_me(self):
808- pass
809- try:
810- test_me = unittest.expectedFailure(test_me)
811- except AttributeError:
812- pass # Older python - just let the test pass
813- self.result.startTestRun()
814- Succeeds("test_me").run(self.result)
815- self.result.stopTestRun()
816- output = self.get_output()
817- expected = """<testsuite errors="0" failures="1" name="" tests="1" time="0.000">
818-<testcase classname="junitxml.tests.test_junitxml.Succeeds" name="test_me" time="0.000">
819-<failure type="unittest.case._UnexpectedSuccess"/>
820-</testcase>
821-</testsuite>
822-"""
823- expected_old = """<testsuite errors="0" failures="0" name="" tests="1" time="0.000">
824-<testcase classname="junitxml.tests.test_junitxml.Succeeds" name="test_me" time="0.000"/>
825-</testsuite>
826-"""
827- if output != expected_old:
828- self.assertEqual(expected, output)
829-
830- def test_expected_failure_test(self):
831- expected_failure_support = [True]
832- class ExpectedFail(unittest.TestCase):
833- def test_me(self):
834- self.fail("fail")
835- try:
836- test_me = unittest.expectedFailure(test_me)
837- except AttributeError:
838- # Older python - just let the test fail
839- expected_failure_support[0] = False
840- self.result.startTestRun()
841- ExpectedFail("test_me").run(self.result)
842- self.result.stopTestRun()
843- output = self.get_output()
844- expected = """<testsuite errors="0" failures="0" name="" tests="1" time="0.000">
845-<testcase classname="junitxml.tests.test_junitxml.ExpectedFail" name="test_me" time="0.000"/>
846-</testsuite>
847-"""
848- expected_old = """<testsuite errors="0" failures="1" name="" tests="1" time="0.000">
849-<testcase classname="junitxml.tests.test_junitxml.ExpectedFail" name="test_me" time="0.000">
850-<failure type="AssertionError">failure</failure>
851-</testcase>
852-</testsuite>
853-"""
854- if expected_failure_support[0]:
855- self.assertEqual(expected, output)
856- else:
857- self.assertEqual(expected_old, output)
858-
859-
860-class TestWellFormedXml(unittest.TestCase):
861- """XML created should always be well formed even with odd test cases"""
862-
863- def _run_and_parse_test(self, case):
864- output = StringIO()
865- result = junitxml.JUnitXmlResult(output)
866- result.startTestRun()
867- case.run(result)
868- result.stopTestRun()
869- return xml.dom.minidom.parseString(output.getvalue())
870-
871- def test_failure_with_amp(self):
872- """Check the failure element content is escaped"""
873- class FailWithAmp(unittest.TestCase):
874- def runTest(self):
875- self.fail("& should be escaped as &amp;")
876- doc = self._run_and_parse_test(FailWithAmp())
877- self.assertTrue(
878- doc.getElementsByTagName("failure")[0].firstChild.nodeValue
879- .endswith("AssertionError: & should be escaped as &amp;\n"))
880-
881- def test_quotes_in_test_case_id(self):
882- """Check that quotes in an attribute are escaped"""
883- class QuoteId(unittest.TestCase):
884- def id(self):
885- return unittest.TestCase.id(self) + '("quotes")'
886- def runTest(self):
887- pass
888- doc = self._run_and_parse_test(QuoteId())
889- self.assertEqual('runTest("quotes")',
890- doc.getElementsByTagName("testcase")[0].getAttribute("name"))
891-
892- def test_skip_reason(self):
893- """Check the skip element content is escaped"""
894- class SkipWithLt(unittest.TestCase):
895- def runTest(self):
896- self.fail("version < 2.7")
897- try:
898- runTest = unittest.skip("2.7 <= version")(runTest)
899- except AttributeError:
900- self.has_skip = False
901- else:
902- self.has_skip = True
903- doc = self._run_and_parse_test(SkipWithLt())
904- if self.has_skip:
905- self.assertEqual('2.7 <= version',
906- doc.getElementsByTagName("skip")[0].firstChild.nodeValue)
907- else:
908- self.assertTrue(
909- doc.getElementsByTagName("failure")[0].firstChild.nodeValue
910- .endswith("AssertionError: version < 2.7\n"))
911-
912- def test_error_with_control_characters(self):
913- """Check C0 control characters are stripped rather than output"""
914- class ErrorWithC0(unittest.TestCase):
915- def runTest(self):
916- raise ValueError("\x1F\x0E\x0C\x0B\x08\x01\x00lost control")
917- doc = self._run_and_parse_test(ErrorWithC0())
918- self.assertTrue(
919- doc.getElementsByTagName("error")[0].firstChild.nodeValue
920- .endswith("ValueError: lost control\n"))
921-
922- def test_error_with_invalid_cdata(self):
923- """Check unicode outside the valid cdata range is stripped"""
924- if len("\uffff") == 1:
925- # Basic str type supports unicode
926- exception = ValueError("\ufffe\uffffEOF")
927- else:
928- class UTF8_Error(Exception):
929- def __unicode__(self):
930- return str(self).decode("UTF-8")
931- exception = UTF8_Error("\xef\xbf\xbe\xef\xbf\xbfEOF")
932- class ErrorWithBadUnicode(unittest.TestCase):
933- def runTest(self):
934- raise exception
935- doc = self._run_and_parse_test(ErrorWithBadUnicode())
936- self.assertTrue(
937- doc.getElementsByTagName("error")[0].firstChild.nodeValue
938- .endswith("Error: EOF\n"))
939-
940- def test_error_with_surrogates(self):
941- """Check unicode surrogates are handled properly, paired or otherwise
942-
943- This is a pain due to suboptimal unicode support in Python and the
944- various changes in Python 3. On UCS-2 builds there is no easy way of
945- getting rid of unpaired surrogates while leaving valid pairs alone, so
946- this test doesn't require astral characters are kept there.
947- """
948- if len("\uffff") == 1:
949- exception = ValueError("paired: \U000201a2"
950- " unpaired: "+chr(0xD800)+"-"+chr(0xDFFF))
951- astral_char = "\U000201a2"
952- else:
953- class UTF8_Error(Exception):
954- def __unicode__(self):
955- return str(self).decode("UTF-8")
956- exception = UTF8_Error("paired: \xf0\xa0\x86\xa2"
957- " unpaired: \xed\xa0\x80-\xed\xbf\xbf")
958- astral_char = "\U000201a2".decode("unicode-escape")
959- class ErrorWithSurrogates(unittest.TestCase):
960- def runTest(self):
961- raise exception
962- doc = self._run_and_parse_test(ErrorWithSurrogates())
963- traceback = doc.getElementsByTagName("error")[0].firstChild.nodeValue
964- if sys.maxunicode == 0xFFFF:
965- pass # would be nice to handle astral characters properly even so
966- else:
967- self.assertTrue(astral_char in traceback)
968- self.assertTrue(traceback.endswith(" unpaired: -\n"))
969
970=== removed directory 'python-for-subunit2junitxml/subunit'
971=== removed file 'python-for-subunit2junitxml/subunit/__init__.py'
972--- python-for-subunit2junitxml/subunit/__init__.py 2013-05-27 13:46:13 +0000
973+++ python-for-subunit2junitxml/subunit/__init__.py 1970-01-01 00:00:00 +0000
974@@ -1,1250 +0,0 @@
975-#
976-# subunit: extensions to Python unittest to get test results from subprocesses.
977-# Copyright (C) 2005 Robert Collins <robertc@robertcollins.net>
978-#
979-# Licensed under either the Apache License, Version 2.0 or the BSD 3-clause
980-# license at the users choice. A copy of both licenses are available in the
981-# project source as Apache-2.0 and BSD. You may not use this file except in
982-# compliance with one of these two licences.
983-#
984-# Unless required by applicable law or agreed to in writing, software
985-# distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT
986-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
987-# license you chose for the specific language governing permissions and
988-# limitations under that license.
989-#
990-
991-"""Subunit - a streaming test protocol
992-
993-Overview
994-++++++++
995-
996-The ``subunit`` Python package provides a number of ``unittest`` extensions
997-which can be used to cause tests to output Subunit, to parse Subunit streams
998-into test activity, perform seamless test isolation within a regular test
999-case and variously sort, filter and report on test runs.
1000-
1001-
1002-Key Classes
1003------------
1004-
1005-The ``subunit.TestProtocolClient`` class is a ``unittest.TestResult``
1006-extension which will translate a test run into a Subunit stream.
1007-
1008-The ``subunit.ProtocolTestCase`` class is an adapter between the Subunit wire
1009-protocol and the ``unittest.TestCase`` object protocol. It is used to translate
1010-a stream into a test run, which regular ``unittest.TestResult`` objects can
1011-process and report/inspect.
1012-
1013-Subunit has support for non-blocking usage too, for use with asyncore or
1014-Twisted. See the ``TestProtocolServer`` parser class for more details.
1015-
1016-Subunit includes extensions to the Python ``TestResult`` protocol. These are
1017-all done in a compatible manner: ``TestResult`` objects that do not implement
1018-the extension methods will not cause errors to be raised, instead the extension
1019-will either lose fidelity (for instance, folding expected failures to success
1020-in Python versions < 2.7 or 3.1), or discard the extended data (for extra
1021-details, tags, timestamping and progress markers).
1022-
1023-The test outcome methods ``addSuccess``, ``addError``, ``addExpectedFailure``,
1024-``addFailure``, ``addSkip`` take an optional keyword parameter ``details``
1025-which can be used instead of the usual python unittest parameter.
1026-When used the value of details should be a dict from ``string`` to
1027-``testtools.content.Content`` objects. This is a draft API being worked on with
1028-the Python Testing In Python mail list, with the goal of permitting a common
1029-way to provide additional data beyond a traceback, such as captured data from
1030-disk, logging messages etc. The reference for this API is in testtools (0.9.0
1031-and newer).
1032-
1033-The ``tags(new_tags, gone_tags)`` method is called (if present) to add or
1034-remove tags in the test run that is currently executing. If called when no
1035-test is in progress (that is, if called outside of the ``startTest``,
1036-``stopTest`` pair), the the tags apply to all sebsequent tests. If called
1037-when a test is in progress, then the tags only apply to that test.
1038-
1039-The ``time(a_datetime)`` method is called (if present) when a ``time:``
1040-directive is encountered in a Subunit stream. This is used to tell a TestResult
1041-about the time that events in the stream occured at, to allow reconstructing
1042-test timing from a stream.
1043-
1044-The ``progress(offset, whence)`` method controls progress data for a stream.
1045-The offset parameter is an int, and whence is one of subunit.PROGRESS_CUR,
1046-subunit.PROGRESS_SET, PROGRESS_PUSH, PROGRESS_POP. Push and pop operations
1047-ignore the offset parameter.
1048-
1049-
1050-Python test support
1051--------------------
1052-
1053-``subunit.run`` is a convenience wrapper to run a Python test suite via
1054-the command line, reporting via Subunit::
1055-
1056- $ python -m subunit.run mylib.tests.test_suite
1057-
1058-The ``IsolatedTestSuite`` class is a TestSuite that forks before running its
1059-tests, allowing isolation between the test runner and some tests.
1060-
1061-Similarly, ``IsolatedTestCase`` is a base class which can be subclassed to get
1062-tests that will fork() before that individual test is run.
1063-
1064-`ExecTestCase`` is a convenience wrapper for running an external
1065-program to get a Subunit stream and then report that back to an arbitrary
1066-result object::
1067-
1068- class AggregateTests(subunit.ExecTestCase):
1069-
1070- def test_script_one(self):
1071- './bin/script_one'
1072-
1073- def test_script_two(self):
1074- './bin/script_two'
1075-
1076- # Normally your normal test loading would take of this automatically,
1077- # It is only spelt out in detail here for clarity.
1078- suite = unittest.TestSuite([AggregateTests("test_script_one"),
1079- AggregateTests("test_script_two")])
1080- # Create any TestResult class you like.
1081- result = unittest._TextTestResult(sys.stdout)
1082- # And run your suite as normal, Subunit will exec each external script as
1083- # needed and report to your result object.
1084- suite.run(result)
1085-
1086-Utility modules
1087----------------
1088-
1089-* subunit.chunked contains HTTP chunked encoding/decoding logic.
1090-* subunit.test_results contains TestResult helper classes.
1091-"""
1092-
1093-import os
1094-import re
1095-import subprocess
1096-import sys
1097-import unittest
1098-
1099-from testtools import content, content_type, ExtendedToOriginalDecorator
1100-from testtools.compat import _b, _u, BytesIO, StringIO
1101-try:
1102- from testtools.testresult.real import _StringException
1103- RemoteException = _StringException
1104- # For testing: different pythons have different str() implementations.
1105- if sys.version_info > (3, 0):
1106- _remote_exception_str = "testtools.testresult.real._StringException"
1107- _remote_exception_str_chunked = "34\r\n" + _remote_exception_str
1108- else:
1109- _remote_exception_str = "_StringException"
1110- _remote_exception_str_chunked = "1A\r\n" + _remote_exception_str
1111-except ImportError:
1112- raise ImportError ("testtools.testresult.real does not contain "
1113- "_StringException, check your version.")
1114-from testtools import testresult
1115-
1116-from subunit import chunked, details, iso8601, test_results
1117-
1118-
1119-PROGRESS_SET = 0
1120-PROGRESS_CUR = 1
1121-PROGRESS_PUSH = 2
1122-PROGRESS_POP = 3
1123-
1124-
1125-def test_suite():
1126- import subunit.tests
1127- return subunit.tests.test_suite()
1128-
1129-
1130-def join_dir(base_path, path):
1131- """
1132- Returns an absolute path to C{path}, calculated relative to the parent
1133- of C{base_path}.
1134-
1135- @param base_path: A path to a file or directory.
1136- @param path: An absolute path, or a path relative to the containing
1137- directory of C{base_path}.
1138-
1139- @return: An absolute path to C{path}.
1140- """
1141- return os.path.join(os.path.dirname(os.path.abspath(base_path)), path)
1142-
1143-
1144-def tags_to_new_gone(tags):
1145- """Split a list of tags into a new_set and a gone_set."""
1146- new_tags = set()
1147- gone_tags = set()
1148- for tag in tags:
1149- if tag[0] == '-':
1150- gone_tags.add(tag[1:])
1151- else:
1152- new_tags.add(tag)
1153- return new_tags, gone_tags
1154-
1155-
1156-class DiscardStream(object):
1157- """A filelike object which discards what is written to it."""
1158-
1159- def write(self, bytes):
1160- pass
1161-
1162-
1163-class _ParserState(object):
1164- """State for the subunit parser."""
1165-
1166- def __init__(self, parser):
1167- self.parser = parser
1168- self._test_sym = (_b('test'), _b('testing'))
1169- self._colon_sym = _b(':')
1170- self._error_sym = (_b('error'),)
1171- self._failure_sym = (_b('failure'),)
1172- self._progress_sym = (_b('progress'),)
1173- self._skip_sym = _b('skip')
1174- self._success_sym = (_b('success'), _b('successful'))
1175- self._tags_sym = (_b('tags'),)
1176- self._time_sym = (_b('time'),)
1177- self._xfail_sym = (_b('xfail'),)
1178- self._uxsuccess_sym = (_b('uxsuccess'),)
1179- self._start_simple = _u(" [")
1180- self._start_multipart = _u(" [ multipart")
1181-
1182- def addError(self, offset, line):
1183- """An 'error:' directive has been read."""
1184- self.parser.stdOutLineReceived(line)
1185-
1186- def addExpectedFail(self, offset, line):
1187- """An 'xfail:' directive has been read."""
1188- self.parser.stdOutLineReceived(line)
1189-
1190- def addFailure(self, offset, line):
1191- """A 'failure:' directive has been read."""
1192- self.parser.stdOutLineReceived(line)
1193-
1194- def addSkip(self, offset, line):
1195- """A 'skip:' directive has been read."""
1196- self.parser.stdOutLineReceived(line)
1197-
1198- def addSuccess(self, offset, line):
1199- """A 'success:' directive has been read."""
1200- self.parser.stdOutLineReceived(line)
1201-
1202- def lineReceived(self, line):
1203- """a line has been received."""
1204- parts = line.split(None, 1)
1205- if len(parts) == 2 and line.startswith(parts[0]):
1206- cmd, rest = parts
1207- offset = len(cmd) + 1
1208- cmd = cmd.rstrip(self._colon_sym)
1209- if cmd in self._test_sym:
1210- self.startTest(offset, line)
1211- elif cmd in self._error_sym:
1212- self.addError(offset, line)
1213- elif cmd in self._failure_sym:
1214- self.addFailure(offset, line)
1215- elif cmd in self._progress_sym:
1216- self.parser._handleProgress(offset, line)
1217- elif cmd in self._skip_sym:
1218- self.addSkip(offset, line)
1219- elif cmd in self._success_sym:
1220- self.addSuccess(offset, line)
1221- elif cmd in self._tags_sym:
1222- self.parser._handleTags(offset, line)
1223- self.parser.subunitLineReceived(line)
1224- elif cmd in self._time_sym:
1225- self.parser._handleTime(offset, line)
1226- self.parser.subunitLineReceived(line)
1227- elif cmd in self._xfail_sym:
1228- self.addExpectedFail(offset, line)
1229- elif cmd in self._uxsuccess_sym:
1230- self.addUnexpectedSuccess(offset, line)
1231- else:
1232- self.parser.stdOutLineReceived(line)
1233- else:
1234- self.parser.stdOutLineReceived(line)
1235-
1236- def lostConnection(self):
1237- """Connection lost."""
1238- self.parser._lostConnectionInTest(_u('unknown state of '))
1239-
1240- def startTest(self, offset, line):
1241- """A test start command received."""
1242- self.parser.stdOutLineReceived(line)
1243-
1244-
1245-class _InTest(_ParserState):
1246- """State for the subunit parser after reading a test: directive."""
1247-
1248- def _outcome(self, offset, line, no_details, details_state):
1249- """An outcome directive has been read.
1250-
1251- :param no_details: Callable to call when no details are presented.
1252- :param details_state: The state to switch to for details
1253- processing of this outcome.
1254- """
1255- test_name = line[offset:-1].decode('utf8')
1256- if self.parser.current_test_description == test_name:
1257- self.parser._state = self.parser._outside_test
1258- self.parser.current_test_description = None
1259- no_details()
1260- self.parser.client.stopTest(self.parser._current_test)
1261- self.parser._current_test = None
1262- self.parser.subunitLineReceived(line)
1263- elif self.parser.current_test_description + self._start_simple == \
1264- test_name:
1265- self.parser._state = details_state
1266- details_state.set_simple()
1267- self.parser.subunitLineReceived(line)
1268- elif self.parser.current_test_description + self._start_multipart == \
1269- test_name:
1270- self.parser._state = details_state
1271- details_state.set_multipart()
1272- self.parser.subunitLineReceived(line)
1273- else:
1274- self.parser.stdOutLineReceived(line)
1275-
1276- def _error(self):
1277- self.parser.client.addError(self.parser._current_test,
1278- details={})
1279-
1280- def addError(self, offset, line):
1281- """An 'error:' directive has been read."""
1282- self._outcome(offset, line, self._error,
1283- self.parser._reading_error_details)
1284-
1285- def _xfail(self):
1286- self.parser.client.addExpectedFailure(self.parser._current_test,
1287- details={})
1288-
1289- def addExpectedFail(self, offset, line):
1290- """An 'xfail:' directive has been read."""
1291- self._outcome(offset, line, self._xfail,
1292- self.parser._reading_xfail_details)
1293-
1294- def _uxsuccess(self):
1295- self.parser.client.addUnexpectedSuccess(self.parser._current_test)
1296-
1297- def addUnexpectedSuccess(self, offset, line):
1298- """A 'uxsuccess:' directive has been read."""
1299- self._outcome(offset, line, self._uxsuccess,
1300- self.parser._reading_uxsuccess_details)
1301-
1302- def _failure(self):
1303- self.parser.client.addFailure(self.parser._current_test, details={})
1304-
1305- def addFailure(self, offset, line):
1306- """A 'failure:' directive has been read."""
1307- self._outcome(offset, line, self._failure,
1308- self.parser._reading_failure_details)
1309-
1310- def _skip(self):
1311- self.parser.client.addSkip(self.parser._current_test, details={})
1312-
1313- def addSkip(self, offset, line):
1314- """A 'skip:' directive has been read."""
1315- self._outcome(offset, line, self._skip,
1316- self.parser._reading_skip_details)
1317-
1318- def _succeed(self):
1319- self.parser.client.addSuccess(self.parser._current_test, details={})
1320-
1321- def addSuccess(self, offset, line):
1322- """A 'success:' directive has been read."""
1323- self._outcome(offset, line, self._succeed,
1324- self.parser._reading_success_details)
1325-
1326- def lostConnection(self):
1327- """Connection lost."""
1328- self.parser._lostConnectionInTest(_u(''))
1329-
1330-
1331-class _OutSideTest(_ParserState):
1332- """State for the subunit parser outside of a test context."""
1333-
1334- def lostConnection(self):
1335- """Connection lost."""
1336-
1337- def startTest(self, offset, line):
1338- """A test start command received."""
1339- self.parser._state = self.parser._in_test
1340- test_name = line[offset:-1].decode('utf8')
1341- self.parser._current_test = RemotedTestCase(test_name)
1342- self.parser.current_test_description = test_name
1343- self.parser.client.startTest(self.parser._current_test)
1344- self.parser.subunitLineReceived(line)
1345-
1346-
1347-class _ReadingDetails(_ParserState):
1348- """Common logic for readin state details."""
1349-
1350- def endDetails(self):
1351- """The end of a details section has been reached."""
1352- self.parser._state = self.parser._outside_test
1353- self.parser.current_test_description = None
1354- self._report_outcome()
1355- self.parser.client.stopTest(self.parser._current_test)
1356-
1357- def lineReceived(self, line):
1358- """a line has been received."""
1359- self.details_parser.lineReceived(line)
1360- self.parser.subunitLineReceived(line)
1361-
1362- def lostConnection(self):
1363- """Connection lost."""
1364- self.parser._lostConnectionInTest(_u('%s report of ') %
1365- self._outcome_label())
1366-
1367- def _outcome_label(self):
1368- """The label to describe this outcome."""
1369- raise NotImplementedError(self._outcome_label)
1370-
1371- def set_simple(self):
1372- """Start a simple details parser."""
1373- self.details_parser = details.SimpleDetailsParser(self)
1374-
1375- def set_multipart(self):
1376- """Start a multipart details parser."""
1377- self.details_parser = details.MultipartDetailsParser(self)
1378-
1379-
1380-class _ReadingFailureDetails(_ReadingDetails):
1381- """State for the subunit parser when reading failure details."""
1382-
1383- def _report_outcome(self):
1384- self.parser.client.addFailure(self.parser._current_test,
1385- details=self.details_parser.get_details())
1386-
1387- def _outcome_label(self):
1388- return "failure"
1389-
1390-
1391-class _ReadingErrorDetails(_ReadingDetails):
1392- """State for the subunit parser when reading error details."""
1393-
1394- def _report_outcome(self):
1395- self.parser.client.addError(self.parser._current_test,
1396- details=self.details_parser.get_details())
1397-
1398- def _outcome_label(self):
1399- return "error"
1400-
1401-
1402-class _ReadingExpectedFailureDetails(_ReadingDetails):
1403- """State for the subunit parser when reading xfail details."""
1404-
1405- def _report_outcome(self):
1406- self.parser.client.addExpectedFailure(self.parser._current_test,
1407- details=self.details_parser.get_details())
1408-
1409- def _outcome_label(self):
1410- return "xfail"
1411-
1412-
1413-class _ReadingUnexpectedSuccessDetails(_ReadingDetails):
1414- """State for the subunit parser when reading uxsuccess details."""
1415-
1416- def _report_outcome(self):
1417- self.parser.client.addUnexpectedSuccess(self.parser._current_test,
1418- details=self.details_parser.get_details())
1419-
1420- def _outcome_label(self):
1421- return "uxsuccess"
1422-
1423-
1424-class _ReadingSkipDetails(_ReadingDetails):
1425- """State for the subunit parser when reading skip details."""
1426-
1427- def _report_outcome(self):
1428- self.parser.client.addSkip(self.parser._current_test,
1429- details=self.details_parser.get_details("skip"))
1430-
1431- def _outcome_label(self):
1432- return "skip"
1433-
1434-
1435-class _ReadingSuccessDetails(_ReadingDetails):
1436- """State for the subunit parser when reading success details."""
1437-
1438- def _report_outcome(self):
1439- self.parser.client.addSuccess(self.parser._current_test,
1440- details=self.details_parser.get_details("success"))
1441-
1442- def _outcome_label(self):
1443- return "success"
1444-
1445-
1446-class TestProtocolServer(object):
1447- """A parser for subunit.
1448-
1449- :ivar tags: The current tags associated with the protocol stream.
1450- """
1451-
1452- def __init__(self, client, stream=None, forward_stream=None):
1453- """Create a TestProtocolServer instance.
1454-
1455- :param client: An object meeting the unittest.TestResult protocol.
1456- :param stream: The stream that lines received which are not part of the
1457- subunit protocol should be written to. This allows custom handling
1458- of mixed protocols. By default, sys.stdout will be used for
1459- convenience. It should accept bytes to its write() method.
1460- :param forward_stream: A stream to forward subunit lines to. This
1461- allows a filter to forward the entire stream while still parsing
1462- and acting on it. By default forward_stream is set to
1463- DiscardStream() and no forwarding happens.
1464- """
1465- self.client = ExtendedToOriginalDecorator(client)
1466- if stream is None:
1467- stream = sys.stdout
1468- if sys.version_info > (3, 0):
1469- stream = stream.buffer
1470- self._stream = stream
1471- self._forward_stream = forward_stream or DiscardStream()
1472- # state objects we can switch too
1473- self._in_test = _InTest(self)
1474- self._outside_test = _OutSideTest(self)
1475- self._reading_error_details = _ReadingErrorDetails(self)
1476- self._reading_failure_details = _ReadingFailureDetails(self)
1477- self._reading_skip_details = _ReadingSkipDetails(self)
1478- self._reading_success_details = _ReadingSuccessDetails(self)
1479- self._reading_xfail_details = _ReadingExpectedFailureDetails(self)
1480- self._reading_uxsuccess_details = _ReadingUnexpectedSuccessDetails(self)
1481- # start with outside test.
1482- self._state = self._outside_test
1483- # Avoid casts on every call
1484- self._plusminus = _b('+-')
1485- self._push_sym = _b('push')
1486- self._pop_sym = _b('pop')
1487-
1488- def _handleProgress(self, offset, line):
1489- """Process a progress directive."""
1490- line = line[offset:].strip()
1491- if line[0] in self._plusminus:
1492- whence = PROGRESS_CUR
1493- delta = int(line)
1494- elif line == self._push_sym:
1495- whence = PROGRESS_PUSH
1496- delta = None
1497- elif line == self._pop_sym:
1498- whence = PROGRESS_POP
1499- delta = None
1500- else:
1501- whence = PROGRESS_SET
1502- delta = int(line)
1503- self.client.progress(delta, whence)
1504-
1505- def _handleTags(self, offset, line):
1506- """Process a tags command."""
1507- tags = line[offset:].decode('utf8').split()
1508- new_tags, gone_tags = tags_to_new_gone(tags)
1509- self.client.tags(new_tags, gone_tags)
1510-
1511- def _handleTime(self, offset, line):
1512- # Accept it, but do not do anything with it yet.
1513- try:
1514- event_time = iso8601.parse_date(line[offset:-1])
1515- except TypeError:
1516- raise TypeError(_u("Failed to parse %r, got %r")
1517- % (line, sys.exec_info[1]))
1518- self.client.time(event_time)
1519-
1520- def lineReceived(self, line):
1521- """Call the appropriate local method for the received line."""
1522- self._state.lineReceived(line)
1523-
1524- def _lostConnectionInTest(self, state_string):
1525- error_string = _u("lost connection during %stest '%s'") % (
1526- state_string, self.current_test_description)
1527- self.client.addError(self._current_test, RemoteError(error_string))
1528- self.client.stopTest(self._current_test)
1529-
1530- def lostConnection(self):
1531- """The input connection has finished."""
1532- self._state.lostConnection()
1533-
1534- def readFrom(self, pipe):
1535- """Blocking convenience API to parse an entire stream.
1536-
1537- :param pipe: A file-like object supporting readlines().
1538- :return: None.
1539- """
1540- for line in pipe.readlines():
1541- self.lineReceived(line)
1542- self.lostConnection()
1543-
1544- def _startTest(self, offset, line):
1545- """Internal call to change state machine. Override startTest()."""
1546- self._state.startTest(offset, line)
1547-
1548- def subunitLineReceived(self, line):
1549- self._forward_stream.write(line)
1550-
1551- def stdOutLineReceived(self, line):
1552- self._stream.write(line)
1553-
1554-
1555-class TestProtocolClient(testresult.TestResult):
1556- """A TestResult which generates a subunit stream for a test run.
1557-
1558- # Get a TestSuite or TestCase to run
1559- suite = make_suite()
1560- # Create a stream (any object with a 'write' method). This should accept
1561- # bytes not strings: subunit is a byte orientated protocol.
1562- stream = file('tests.log', 'wb')
1563- # Create a subunit result object which will output to the stream
1564- result = subunit.TestProtocolClient(stream)
1565- # Optionally, to get timing data for performance analysis, wrap the
1566- # serialiser with a timing decorator
1567- result = subunit.test_results.AutoTimingTestResultDecorator(result)
1568- # Run the test suite reporting to the subunit result object
1569- suite.run(result)
1570- # Close the stream.
1571- stream.close()
1572- """
1573-
1574- def __init__(self, stream):
1575- testresult.TestResult.__init__(self)
1576- self._stream = stream
1577- _make_stream_binary(stream)
1578- self._progress_fmt = _b("progress: ")
1579- self._bytes_eol = _b("\n")
1580- self._progress_plus = _b("+")
1581- self._progress_push = _b("push")
1582- self._progress_pop = _b("pop")
1583- self._empty_bytes = _b("")
1584- self._start_simple = _b(" [\n")
1585- self._end_simple = _b("]\n")
1586-
1587- def addError(self, test, error=None, details=None):
1588- """Report an error in test test.
1589-
1590- Only one of error and details should be provided: conceptually there
1591- are two separate methods:
1592- addError(self, test, error)
1593- addError(self, test, details)
1594-
1595- :param error: Standard unittest positional argument form - an
1596- exc_info tuple.
1597- :param details: New Testing-in-python drafted API; a dict from string
1598- to subunit.Content objects.
1599- """
1600- self._addOutcome("error", test, error=error, details=details)
1601-
1602- def addExpectedFailure(self, test, error=None, details=None):
1603- """Report an expected failure in test test.
1604-
1605- Only one of error and details should be provided: conceptually there
1606- are two separate methods:
1607- addError(self, test, error)
1608- addError(self, test, details)
1609-
1610- :param error: Standard unittest positional argument form - an
1611- exc_info tuple.
1612- :param details: New Testing-in-python drafted API; a dict from string
1613- to subunit.Content objects.
1614- """
1615- self._addOutcome("xfail", test, error=error, details=details)
1616-
1617- def addFailure(self, test, error=None, details=None):
1618- """Report a failure in test test.
1619-
1620- Only one of error and details should be provided: conceptually there
1621- are two separate methods:
1622- addFailure(self, test, error)
1623- addFailure(self, test, details)
1624-
1625- :param error: Standard unittest positional argument form - an
1626- exc_info tuple.
1627- :param details: New Testing-in-python drafted API; a dict from string
1628- to subunit.Content objects.
1629- """
1630- self._addOutcome("failure", test, error=error, details=details)
1631-
1632- def _addOutcome(self, outcome, test, error=None, details=None,
1633- error_permitted=True):
1634- """Report a failure in test test.
1635-
1636- Only one of error and details should be provided: conceptually there
1637- are two separate methods:
1638- addOutcome(self, test, error)
1639- addOutcome(self, test, details)
1640-
1641- :param outcome: A string describing the outcome - used as the
1642- event name in the subunit stream.
1643- :param error: Standard unittest positional argument form - an
1644- exc_info tuple.
1645- :param details: New Testing-in-python drafted API; a dict from string
1646- to subunit.Content objects.
1647- :param error_permitted: If True then one and only one of error or
1648- details must be supplied. If False then error must not be supplied
1649- and details is still optional. """
1650- self._stream.write(_b("%s: %s" % (outcome, test.id())))
1651- if error_permitted:
1652- if error is None and details is None:
1653- raise ValueError
1654- else:
1655- if error is not None:
1656- raise ValueError
1657- if error is not None:
1658- self._stream.write(self._start_simple)
1659- # XXX: this needs to be made much stricter, along the lines of
1660- # Martin[gz]'s work in testtools. Perhaps subunit can use that?
1661- for line in self._exc_info_to_unicode(error, test).splitlines():
1662- self._stream.write(("%s\n" % line).encode('utf8'))
1663- elif details is not None:
1664- self._write_details(details)
1665- else:
1666- self._stream.write(_b("\n"))
1667- if details is not None or error is not None:
1668- self._stream.write(self._end_simple)
1669-
1670- def addSkip(self, test, reason=None, details=None):
1671- """Report a skipped test."""
1672- if reason is None:
1673- self._addOutcome("skip", test, error=None, details=details)
1674- else:
1675- self._stream.write(_b("skip: %s [\n" % test.id()))
1676- self._stream.write(_b("%s\n" % reason))
1677- self._stream.write(self._end_simple)
1678-
1679- def addSuccess(self, test, details=None):
1680- """Report a success in a test."""
1681- self._addOutcome("successful", test, details=details, error_permitted=False)
1682-
1683- def addUnexpectedSuccess(self, test, details=None):
1684- """Report an unexpected success in test test.
1685-
1686- Details can optionally be provided: conceptually there
1687- are two separate methods:
1688- addError(self, test)
1689- addError(self, test, details)
1690-
1691- :param details: New Testing-in-python drafted API; a dict from string
1692- to subunit.Content objects.
1693- """
1694- self._addOutcome("uxsuccess", test, details=details,
1695- error_permitted=False)
1696-
1697- def startTest(self, test):
1698- """Mark a test as starting its test run."""
1699- super(TestProtocolClient, self).startTest(test)
1700- self._stream.write(_b("test: %s\n" % test.id()))
1701- self._stream.flush()
1702-
1703- def stopTest(self, test):
1704- super(TestProtocolClient, self).stopTest(test)
1705- self._stream.flush()
1706-
1707- def progress(self, offset, whence):
1708- """Provide indication about the progress/length of the test run.
1709-
1710- :param offset: Information about the number of tests remaining. If
1711- whence is PROGRESS_CUR, then offset increases/decreases the
1712- remaining test count. If whence is PROGRESS_SET, then offset
1713- specifies exactly the remaining test count.
1714- :param whence: One of PROGRESS_CUR, PROGRESS_SET, PROGRESS_PUSH,
1715- PROGRESS_POP.
1716- """
1717- if whence == PROGRESS_CUR and offset > -1:
1718- prefix = self._progress_plus
1719- offset = _b(str(offset))
1720- elif whence == PROGRESS_PUSH:
1721- prefix = self._empty_bytes
1722- offset = self._progress_push
1723- elif whence == PROGRESS_POP:
1724- prefix = self._empty_bytes
1725- offset = self._progress_pop
1726- else:
1727- prefix = self._empty_bytes
1728- offset = _b(str(offset))
1729- self._stream.write(self._progress_fmt + prefix + offset +
1730- self._bytes_eol)
1731-
1732- def time(self, a_datetime):
1733- """Inform the client of the time.
1734-
1735- ":param datetime: A datetime.datetime object.
1736- """
1737- time = a_datetime.astimezone(iso8601.Utc())
1738- self._stream.write(_b("time: %04d-%02d-%02d %02d:%02d:%02d.%06dZ\n" % (
1739- time.year, time.month, time.day, time.hour, time.minute,
1740- time.second, time.microsecond)))
1741-
1742- def _write_details(self, details):
1743- """Output details to the stream.
1744-
1745- :param details: An extended details dict for a test outcome.
1746- """
1747- self._stream.write(_b(" [ multipart\n"))
1748- for name, content in sorted(details.items()):
1749- self._stream.write(_b("Content-Type: %s/%s" %
1750- (content.content_type.type, content.content_type.subtype)))
1751- parameters = content.content_type.parameters
1752- if parameters:
1753- self._stream.write(_b(";"))
1754- param_strs = []
1755- for param, value in parameters.items():
1756- param_strs.append("%s=%s" % (param, value))
1757- self._stream.write(_b(",".join(param_strs)))
1758- self._stream.write(_b("\n%s\n" % name))
1759- encoder = chunked.Encoder(self._stream)
1760- list(map(encoder.write, content.iter_bytes()))
1761- encoder.close()
1762-
1763- def done(self):
1764- """Obey the testtools result.done() interface."""
1765-
1766-
1767-def RemoteError(description=_u("")):
1768- return (_StringException, _StringException(description), None)
1769-
1770-
1771-class RemotedTestCase(unittest.TestCase):
1772- """A class to represent test cases run in child processes.
1773-
1774- Instances of this class are used to provide the Python test API a TestCase
1775- that can be printed to the screen, introspected for metadata and so on.
1776- However, as they are a simply a memoisation of a test that was actually
1777- run in the past by a separate process, they cannot perform any interactive
1778- actions.
1779- """
1780-
1781- def __eq__ (self, other):
1782- try:
1783- return self.__description == other.__description
1784- except AttributeError:
1785- return False
1786-
1787- def __init__(self, description):
1788- """Create a psuedo test case with description description."""
1789- self.__description = description
1790-
1791- def error(self, label):
1792- raise NotImplementedError("%s on RemotedTestCases is not permitted." %
1793- label)
1794-
1795- def setUp(self):
1796- self.error("setUp")
1797-
1798- def tearDown(self):
1799- self.error("tearDown")
1800-
1801- def shortDescription(self):
1802- return self.__description
1803-
1804- def id(self):
1805- return "%s" % (self.__description,)
1806-
1807- def __str__(self):
1808- return "%s (%s)" % (self.__description, self._strclass())
1809-
1810- def __repr__(self):
1811- return "<%s description='%s'>" % \
1812- (self._strclass(), self.__description)
1813-
1814- def run(self, result=None):
1815- if result is None: result = self.defaultTestResult()
1816- result.startTest(self)
1817- result.addError(self, RemoteError(_u("Cannot run RemotedTestCases.\n")))
1818- result.stopTest(self)
1819-
1820- def _strclass(self):
1821- cls = self.__class__
1822- return "%s.%s" % (cls.__module__, cls.__name__)
1823-
1824-
1825-class ExecTestCase(unittest.TestCase):
1826- """A test case which runs external scripts for test fixtures."""
1827-
1828- def __init__(self, methodName='runTest'):
1829- """Create an instance of the class that will use the named test
1830- method when executed. Raises a ValueError if the instance does
1831- not have a method with the specified name.
1832- """
1833- unittest.TestCase.__init__(self, methodName)
1834- testMethod = getattr(self, methodName)
1835- self.script = join_dir(sys.modules[self.__class__.__module__].__file__,
1836- testMethod.__doc__)
1837-
1838- def countTestCases(self):
1839- return 1
1840-
1841- def run(self, result=None):
1842- if result is None: result = self.defaultTestResult()
1843- self._run(result)
1844-
1845- def debug(self):
1846- """Run the test without collecting errors in a TestResult"""
1847- self._run(testresult.TestResult())
1848-
1849- def _run(self, result):
1850- protocol = TestProtocolServer(result)
1851- process = subprocess.Popen(self.script, shell=True,
1852- stdout=subprocess.PIPE)
1853- _make_stream_binary(process.stdout)
1854- output = process.communicate()[0]
1855- protocol.readFrom(BytesIO(output))
1856-
1857-
1858-class IsolatedTestCase(unittest.TestCase):
1859- """A TestCase which executes in a forked process.
1860-
1861- Each test gets its own process, which has a performance overhead but will
1862- provide excellent isolation from global state (such as django configs,
1863- zope utilities and so on).
1864- """
1865-
1866- def run(self, result=None):
1867- if result is None: result = self.defaultTestResult()
1868- run_isolated(unittest.TestCase, self, result)
1869-
1870-
1871-class IsolatedTestSuite(unittest.TestSuite):
1872- """A TestSuite which runs its tests in a forked process.
1873-
1874- This decorator that will fork() before running the tests and report the
1875- results from the child process using a Subunit stream. This is useful for
1876- handling tests that mutate global state, or are testing C extensions that
1877- could crash the VM.
1878- """
1879-
1880- def run(self, result=None):
1881- if result is None: result = testresult.TestResult()
1882- run_isolated(unittest.TestSuite, self, result)
1883-
1884-
1885-def run_isolated(klass, self, result):
1886- """Run a test suite or case in a subprocess, using the run method on klass.
1887- """
1888- c2pread, c2pwrite = os.pipe()
1889- # fixme - error -> result
1890- # now fork
1891- pid = os.fork()
1892- if pid == 0:
1893- # Child
1894- # Close parent's pipe ends
1895- os.close(c2pread)
1896- # Dup fds for child
1897- os.dup2(c2pwrite, 1)
1898- # Close pipe fds.
1899- os.close(c2pwrite)
1900-
1901- # at this point, sys.stdin is redirected, now we want
1902- # to filter it to escape ]'s.
1903- ### XXX: test and write that bit.
1904- stream = os.fdopen(1, 'wb')
1905- result = TestProtocolClient(stream)
1906- klass.run(self, result)
1907- stream.flush()
1908- sys.stderr.flush()
1909- # exit HARD, exit NOW.
1910- os._exit(0)
1911- else:
1912- # Parent
1913- # Close child pipe ends
1914- os.close(c2pwrite)
1915- # hookup a protocol engine
1916- protocol = TestProtocolServer(result)
1917- fileobj = os.fdopen(c2pread, 'rb')
1918- protocol.readFrom(fileobj)
1919- os.waitpid(pid, 0)
1920- # TODO return code evaluation.
1921- return result
1922-
1923-
1924-def TAP2SubUnit(tap, subunit):
1925- """Filter a TAP pipe into a subunit pipe.
1926-
1927- :param tap: A tap pipe/stream/file object.
1928- :param subunit: A pipe/stream/file object to write subunit results to.
1929- :return: The exit code to exit with.
1930- """
1931- BEFORE_PLAN = 0
1932- AFTER_PLAN = 1
1933- SKIP_STREAM = 2
1934- state = BEFORE_PLAN
1935- plan_start = 1
1936- plan_stop = 0
1937- def _skipped_test(subunit, plan_start):
1938- # Some tests were skipped.
1939- subunit.write('test test %d\n' % plan_start)
1940- subunit.write('error test %d [\n' % plan_start)
1941- subunit.write('test missing from TAP output\n')
1942- subunit.write(']\n')
1943- return plan_start + 1
1944- # Test data for the next test to emit
1945- test_name = None
1946- log = []
1947- result = None
1948- def _emit_test():
1949- "write out a test"
1950- if test_name is None:
1951- return
1952- subunit.write("test %s\n" % test_name)
1953- if not log:
1954- subunit.write("%s %s\n" % (result, test_name))
1955- else:
1956- subunit.write("%s %s [\n" % (result, test_name))
1957- if log:
1958- for line in log:
1959- subunit.write("%s\n" % line)
1960- subunit.write("]\n")
1961- del log[:]
1962- for line in tap:
1963- if state == BEFORE_PLAN:
1964- match = re.match("(\d+)\.\.(\d+)\s*(?:\#\s+(.*))?\n", line)
1965- if match:
1966- state = AFTER_PLAN
1967- _, plan_stop, comment = match.groups()
1968- plan_stop = int(plan_stop)
1969- if plan_start > plan_stop and plan_stop == 0:
1970- # skipped file
1971- state = SKIP_STREAM
1972- subunit.write("test file skip\n")
1973- subunit.write("skip file skip [\n")
1974- subunit.write("%s\n" % comment)
1975- subunit.write("]\n")
1976- continue
1977- # not a plan line, or have seen one before
1978- match = re.match("(ok|not ok)(?:\s+(\d+)?)?(?:\s+([^#]*[^#\s]+)\s*)?(?:\s+#\s+(TODO|SKIP|skip|todo)(?:\s+(.*))?)?\n", line)
1979- if match:
1980- # new test, emit current one.
1981- _emit_test()
1982- status, number, description, directive, directive_comment = match.groups()
1983- if status == 'ok':
1984- result = 'success'
1985- else:
1986- result = "failure"
1987- if description is None:
1988- description = ''
1989- else:
1990- description = ' ' + description
1991- if directive is not None:
1992- if directive.upper() == 'TODO':
1993- result = 'xfail'
1994- elif directive.upper() == 'SKIP':
1995- result = 'skip'
1996- if directive_comment is not None:
1997- log.append(directive_comment)
1998- if number is not None:
1999- number = int(number)
2000- while plan_start < number:
2001- plan_start = _skipped_test(subunit, plan_start)
2002- test_name = "test %d%s" % (plan_start, description)
2003- plan_start += 1
2004- continue
2005- match = re.match("Bail out\!(?:\s*(.*))?\n", line)
2006- if match:
2007- reason, = match.groups()
2008- if reason is None:
2009- extra = ''
2010- else:
2011- extra = ' %s' % reason
2012- _emit_test()
2013- test_name = "Bail out!%s" % extra
2014- result = "error"
2015- state = SKIP_STREAM
2016- continue
2017- match = re.match("\#.*\n", line)
2018- if match:
2019- log.append(line[:-1])
2020- continue
2021- subunit.write(line)
2022- _emit_test()
2023- while plan_start <= plan_stop:
2024- # record missed tests
2025- plan_start = _skipped_test(subunit, plan_start)
2026- return 0
2027-
2028-
2029-def tag_stream(original, filtered, tags):
2030- """Alter tags on a stream.
2031-
2032- :param original: The input stream.
2033- :param filtered: The output stream.
2034- :param tags: The tags to apply. As in a normal stream - a list of 'TAG' or
2035- '-TAG' commands.
2036-
2037- A 'TAG' command will add the tag to the output stream,
2038- and override any existing '-TAG' command in that stream.
2039- Specifically:
2040- * A global 'tags: TAG' will be added to the start of the stream.
2041- * Any tags commands with -TAG will have the -TAG removed.
2042-
2043- A '-TAG' command will remove the TAG command from the stream.
2044- Specifically:
2045- * A 'tags: -TAG' command will be added to the start of the stream.
2046- * Any 'tags: TAG' command will have 'TAG' removed from it.
2047- Additionally, any redundant tagging commands (adding a tag globally
2048- present, or removing a tag globally removed) are stripped as a
2049- by-product of the filtering.
2050- :return: 0
2051- """
2052- new_tags, gone_tags = tags_to_new_gone(tags)
2053- def write_tags(new_tags, gone_tags):
2054- if new_tags or gone_tags:
2055- filtered.write("tags: " + ' '.join(new_tags))
2056- if gone_tags:
2057- for tag in gone_tags:
2058- filtered.write("-" + tag)
2059- filtered.write("\n")
2060- write_tags(new_tags, gone_tags)
2061- # TODO: use the protocol parser and thus don't mangle test comments.
2062- for line in original:
2063- if line.startswith("tags:"):
2064- line_tags = line[5:].split()
2065- line_new, line_gone = tags_to_new_gone(line_tags)
2066- line_new = line_new - gone_tags
2067- line_gone = line_gone - new_tags
2068- write_tags(line_new, line_gone)
2069- else:
2070- filtered.write(line)
2071- return 0
2072-
2073-
2074-class ProtocolTestCase(object):
2075- """Subunit wire protocol to unittest.TestCase adapter.
2076-
2077- ProtocolTestCase honours the core of ``unittest.TestCase`` protocol -
2078- calling a ProtocolTestCase or invoking the run() method will make a 'test
2079- run' happen. The 'test run' will simply be a replay of the test activity
2080- that has been encoded into the stream. The ``unittest.TestCase`` ``debug``
2081- and ``countTestCases`` methods are not supported because there isn't a
2082- sensible mapping for those methods.
2083-
2084- # Get a stream (any object with a readline() method), in this case the
2085- # stream output by the example from ``subunit.TestProtocolClient``.
2086- stream = file('tests.log', 'rb')
2087- # Create a parser which will read from the stream and emit
2088- # activity to a unittest.TestResult when run() is called.
2089- suite = subunit.ProtocolTestCase(stream)
2090- # Create a result object to accept the contents of that stream.
2091- result = unittest._TextTestResult(sys.stdout)
2092- # 'run' the tests - process the stream and feed its contents to result.
2093- suite.run(result)
2094- stream.close()
2095-
2096- :seealso: TestProtocolServer (the subunit wire protocol parser).
2097- """
2098-
2099- def __init__(self, stream, passthrough=None, forward=False):
2100- """Create a ProtocolTestCase reading from stream.
2101-
2102- :param stream: A filelike object which a subunit stream can be read
2103- from.
2104- :param passthrough: A stream pass non subunit input on to. If not
2105- supplied, the TestProtocolServer default is used.
2106- :param forward: A stream to pass subunit input on to. If not supplied
2107- subunit input is not forwarded.
2108- """
2109- self._stream = stream
2110- _make_stream_binary(stream)
2111- self._passthrough = passthrough
2112- self._forward = forward
2113-
2114- def __call__(self, result=None):
2115- return self.run(result)
2116-
2117- def run(self, result=None):
2118- if result is None:
2119- result = self.defaultTestResult()
2120- protocol = TestProtocolServer(result, self._passthrough, self._forward)
2121- line = self._stream.readline()
2122- while line:
2123- protocol.lineReceived(line)
2124- line = self._stream.readline()
2125- protocol.lostConnection()
2126-
2127-
2128-class TestResultStats(testresult.TestResult):
2129- """A pyunit TestResult interface implementation for making statistics.
2130-
2131- :ivar total_tests: The total tests seen.
2132- :ivar passed_tests: The tests that passed.
2133- :ivar failed_tests: The tests that failed.
2134- :ivar seen_tags: The tags seen across all tests.
2135- """
2136-
2137- def __init__(self, stream):
2138- """Create a TestResultStats which outputs to stream."""
2139- testresult.TestResult.__init__(self)
2140- self._stream = stream
2141- self.failed_tests = 0
2142- self.skipped_tests = 0
2143- self.seen_tags = set()
2144-
2145- @property
2146- def total_tests(self):
2147- return self.testsRun
2148-
2149- def addError(self, test, err, details=None):
2150- self.failed_tests += 1
2151-
2152- def addFailure(self, test, err, details=None):
2153- self.failed_tests += 1
2154-
2155- def addSkip(self, test, reason, details=None):
2156- self.skipped_tests += 1
2157-
2158- def formatStats(self):
2159- self._stream.write("Total tests: %5d\n" % self.total_tests)
2160- self._stream.write("Passed tests: %5d\n" % self.passed_tests)
2161- self._stream.write("Failed tests: %5d\n" % self.failed_tests)
2162- self._stream.write("Skipped tests: %5d\n" % self.skipped_tests)
2163- tags = sorted(self.seen_tags)
2164- self._stream.write("Seen tags: %s\n" % (", ".join(tags)))
2165-
2166- @property
2167- def passed_tests(self):
2168- return self.total_tests - self.failed_tests - self.skipped_tests
2169-
2170- def tags(self, new_tags, gone_tags):
2171- """Accumulate the seen tags."""
2172- self.seen_tags.update(new_tags)
2173-
2174- def wasSuccessful(self):
2175- """Tells whether or not this result was a success"""
2176- return self.failed_tests == 0
2177-
2178-
2179-def get_default_formatter():
2180- """Obtain the default formatter to write to.
2181-
2182- :return: A file-like object.
2183- """
2184- formatter = os.getenv("SUBUNIT_FORMATTER")
2185- if formatter:
2186- return os.popen(formatter, "w")
2187- else:
2188- stream = sys.stdout
2189- if sys.version_info > (3, 0):
2190- stream = stream.buffer
2191- return stream
2192-
2193-
2194-if sys.version_info > (3, 0):
2195- from io import UnsupportedOperation as _NoFilenoError
2196-else:
2197- _NoFilenoError = AttributeError
2198-
2199-def read_test_list(path):
2200- """Read a list of test ids from a file on disk.
2201-
2202- :param path: Path to the file
2203- :return: Sequence of test ids
2204- """
2205- f = open(path, 'rb')
2206- try:
2207- return [l.rstrip("\n") for l in f.readlines()]
2208- finally:
2209- f.close()
2210-
2211-
2212-def _make_stream_binary(stream):
2213- """Ensure that a stream will be binary safe. See _make_binary_on_windows."""
2214- try:
2215- fileno = stream.fileno()
2216- except _NoFilenoError:
2217- return
2218- _make_binary_on_windows(fileno)
2219-
2220-def _make_binary_on_windows(fileno):
2221- """Win32 mangles \r\n to \n and that breaks streams. See bug lp:505078."""
2222- if sys.platform == "win32":
2223- import msvcrt
2224- msvcrt.setmode(fileno, os.O_BINARY)
2225
2226=== removed file 'python-for-subunit2junitxml/subunit/chunked.py'
2227--- python-for-subunit2junitxml/subunit/chunked.py 2013-05-27 13:46:13 +0000
2228+++ python-for-subunit2junitxml/subunit/chunked.py 1970-01-01 00:00:00 +0000
2229@@ -1,185 +0,0 @@
2230-#
2231-# subunit: extensions to python unittest to get test results from subprocesses.
2232-# Copyright (C) 2005 Robert Collins <robertc@robertcollins.net>
2233-# Copyright (C) 2011 Martin Pool <mbp@sourcefrog.net>
2234-#
2235-# Licensed under either the Apache License, Version 2.0 or the BSD 3-clause
2236-# license at the users choice. A copy of both licenses are available in the
2237-# project source as Apache-2.0 and BSD. You may not use this file except in
2238-# compliance with one of these two licences.
2239-#
2240-# Unless required by applicable law or agreed to in writing, software
2241-# distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT
2242-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
2243-# license you chose for the specific language governing permissions and
2244-# limitations under that license.
2245-#
2246-
2247-"""Encoder/decoder for http style chunked encoding."""
2248-
2249-from testtools.compat import _b
2250-
2251-empty = _b('')
2252-
2253-class Decoder(object):
2254- """Decode chunked content to a byte stream."""
2255-
2256- def __init__(self, output, strict=True):
2257- """Create a decoder decoding to output.
2258-
2259- :param output: A file-like object. Bytes written to the Decoder are
2260- decoded to strip off the chunking and written to the output.
2261- Up to a full write worth of data or a single control line may be
2262- buffered (whichever is larger). The close method should be called
2263- when no more data is available, to detect short streams; the
2264- write method will return none-None when the end of a stream is
2265- detected. The output object must accept bytes objects.
2266-
2267- :param strict: If True (the default), the decoder will not knowingly
2268- accept input that is not conformant to the HTTP specification.
2269- (This does not imply that it will catch every nonconformance.)
2270- If False, it will accept incorrect input that is still
2271- unambiguous.
2272- """
2273- self.output = output
2274- self.buffered_bytes = []
2275- self.state = self._read_length
2276- self.body_length = 0
2277- self.strict = strict
2278- self._match_chars = _b("0123456789abcdefABCDEF\r\n")
2279- self._slash_n = _b('\n')
2280- self._slash_r = _b('\r')
2281- self._slash_rn = _b('\r\n')
2282- self._slash_nr = _b('\n\r')
2283-
2284- def close(self):
2285- """Close the decoder.
2286-
2287- :raises ValueError: If the stream is incomplete ValueError is raised.
2288- """
2289- if self.state != self._finished:
2290- raise ValueError("incomplete stream")
2291-
2292- def _finished(self):
2293- """Finished reading, return any remaining bytes."""
2294- if self.buffered_bytes:
2295- buffered_bytes = self.buffered_bytes
2296- self.buffered_bytes = []
2297- return empty.join(buffered_bytes)
2298- else:
2299- raise ValueError("stream is finished")
2300-
2301- def _read_body(self):
2302- """Pass body bytes to the output."""
2303- while self.body_length and self.buffered_bytes:
2304- if self.body_length >= len(self.buffered_bytes[0]):
2305- self.output.write(self.buffered_bytes[0])
2306- self.body_length -= len(self.buffered_bytes[0])
2307- del self.buffered_bytes[0]
2308- # No more data available.
2309- if not self.body_length:
2310- self.state = self._read_length
2311- else:
2312- self.output.write(self.buffered_bytes[0][:self.body_length])
2313- self.buffered_bytes[0] = \
2314- self.buffered_bytes[0][self.body_length:]
2315- self.body_length = 0
2316- self.state = self._read_length
2317- return self.state()
2318-
2319- def _read_length(self):
2320- """Try to decode a length from the bytes."""
2321- count_chars = []
2322- for bytes in self.buffered_bytes:
2323- for pos in range(len(bytes)):
2324- byte = bytes[pos:pos+1]
2325- if byte not in self._match_chars:
2326- break
2327- count_chars.append(byte)
2328- if byte == self._slash_n:
2329- break
2330- if not count_chars:
2331- return
2332- if count_chars[-1] != self._slash_n:
2333- return
2334- count_str = empty.join(count_chars)
2335- if self.strict:
2336- if count_str[-2:] != self._slash_rn:
2337- raise ValueError("chunk header invalid: %r" % count_str)
2338- if self._slash_r in count_str[:-2]:
2339- raise ValueError("too many CRs in chunk header %r" % count_str)
2340- self.body_length = int(count_str.rstrip(self._slash_nr), 16)
2341- excess_bytes = len(count_str)
2342- while excess_bytes:
2343- if excess_bytes >= len(self.buffered_bytes[0]):
2344- excess_bytes -= len(self.buffered_bytes[0])
2345- del self.buffered_bytes[0]
2346- else:
2347- self.buffered_bytes[0] = self.buffered_bytes[0][excess_bytes:]
2348- excess_bytes = 0
2349- if not self.body_length:
2350- self.state = self._finished
2351- if not self.buffered_bytes:
2352- # May not call into self._finished with no buffered data.
2353- return empty
2354- else:
2355- self.state = self._read_body
2356- return self.state()
2357-
2358- def write(self, bytes):
2359- """Decode bytes to the output stream.
2360-
2361- :raises ValueError: If the stream has already seen the end of file
2362- marker.
2363- :returns: None, or the excess bytes beyond the end of file marker.
2364- """
2365- if bytes:
2366- self.buffered_bytes.append(bytes)
2367- return self.state()
2368-
2369-
2370-class Encoder(object):
2371- """Encode content to a stream using HTTP Chunked coding."""
2372-
2373- def __init__(self, output):
2374- """Create an encoder encoding to output.
2375-
2376- :param output: A file-like object. Bytes written to the Encoder
2377- will be encoded using HTTP chunking. Small writes may be buffered
2378- and the ``close`` method must be called to finish the stream.
2379- """
2380- self.output = output
2381- self.buffered_bytes = []
2382- self.buffer_size = 0
2383-
2384- def flush(self, extra_len=0):
2385- """Flush the encoder to the output stream.
2386-
2387- :param extra_len: Increase the size of the chunk by this many bytes
2388- to allow for a subsequent write.
2389- """
2390- if not self.buffer_size and not extra_len:
2391- return
2392- buffered_bytes = self.buffered_bytes
2393- buffer_size = self.buffer_size
2394- self.buffered_bytes = []
2395- self.buffer_size = 0
2396- self.output.write(_b("%X\r\n" % (buffer_size + extra_len)))
2397- if buffer_size:
2398- self.output.write(empty.join(buffered_bytes))
2399- return True
2400-
2401- def write(self, bytes):
2402- """Encode bytes to the output stream."""
2403- bytes_len = len(bytes)
2404- if self.buffer_size + bytes_len >= 65536:
2405- self.flush(bytes_len)
2406- self.output.write(bytes)
2407- else:
2408- self.buffered_bytes.append(bytes)
2409- self.buffer_size += bytes_len
2410-
2411- def close(self):
2412- """Finish the stream. This does not close the output stream."""
2413- self.flush()
2414- self.output.write(_b("0\r\n"))
2415
2416=== removed file 'python-for-subunit2junitxml/subunit/details.py'
2417--- python-for-subunit2junitxml/subunit/details.py 2013-05-27 13:46:13 +0000
2418+++ python-for-subunit2junitxml/subunit/details.py 1970-01-01 00:00:00 +0000
2419@@ -1,119 +0,0 @@
2420-#
2421-# subunit: extensions to Python unittest to get test results from subprocesses.
2422-# Copyright (C) 2005 Robert Collins <robertc@robertcollins.net>
2423-#
2424-# Licensed under either the Apache License, Version 2.0 or the BSD 3-clause
2425-# license at the users choice. A copy of both licenses are available in the
2426-# project source as Apache-2.0 and BSD. You may not use this file except in
2427-# compliance with one of these two licences.
2428-#
2429-# Unless required by applicable law or agreed to in writing, software
2430-# distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT
2431-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
2432-# license you chose for the specific language governing permissions and
2433-# limitations under that license.
2434-#
2435-
2436-"""Handlers for outcome details."""
2437-
2438-from testtools import content, content_type
2439-from testtools.compat import _b, BytesIO
2440-
2441-from subunit import chunked
2442-
2443-end_marker = _b("]\n")
2444-quoted_marker = _b(" ]")
2445-empty = _b('')
2446-
2447-
2448-class DetailsParser(object):
2449- """Base class/API reference for details parsing."""
2450-
2451-
2452-class SimpleDetailsParser(DetailsParser):
2453- """Parser for single-part [] delimited details."""
2454-
2455- def __init__(self, state):
2456- self._message = _b("")
2457- self._state = state
2458-
2459- def lineReceived(self, line):
2460- if line == end_marker:
2461- self._state.endDetails()
2462- return
2463- if line[0:2] == quoted_marker:
2464- # quoted ] start
2465- self._message += line[1:]
2466- else:
2467- self._message += line
2468-
2469- def get_details(self, style=None):
2470- result = {}
2471- if not style:
2472- # We know that subunit/testtools serialise [] formatted
2473- # tracebacks as utf8, but perhaps we need a ReplacingContent
2474- # or something like that.
2475- result['traceback'] = content.Content(
2476- content_type.ContentType("text", "x-traceback",
2477- {"charset": "utf8"}),
2478- lambda:[self._message])
2479- else:
2480- if style == 'skip':
2481- name = 'reason'
2482- else:
2483- name = 'message'
2484- result[name] = content.Content(
2485- content_type.ContentType("text", "plain"),
2486- lambda:[self._message])
2487- return result
2488-
2489- def get_message(self):
2490- return self._message
2491-
2492-
2493-class MultipartDetailsParser(DetailsParser):
2494- """Parser for multi-part [] surrounded MIME typed chunked details."""
2495-
2496- def __init__(self, state):
2497- self._state = state
2498- self._details = {}
2499- self._parse_state = self._look_for_content
2500-
2501- def _look_for_content(self, line):
2502- if line == end_marker:
2503- self._state.endDetails()
2504- return
2505- # TODO error handling
2506- field, value = line[:-1].decode('utf8').split(' ', 1)
2507- try:
2508- main, sub = value.split('/')
2509- except ValueError:
2510- raise ValueError("Invalid MIME type %r" % value)
2511- self._content_type = content_type.ContentType(main, sub)
2512- self._parse_state = self._get_name
2513-
2514- def _get_name(self, line):
2515- self._name = line[:-1].decode('utf8')
2516- self._body = BytesIO()
2517- self._chunk_parser = chunked.Decoder(self._body)
2518- self._parse_state = self._feed_chunks
2519-
2520- def _feed_chunks(self, line):
2521- residue = self._chunk_parser.write(line)
2522- if residue is not None:
2523- # Line based use always ends on no residue.
2524- assert residue == empty, 'residue: %r' % (residue,)
2525- body = self._body
2526- self._details[self._name] = content.Content(
2527- self._content_type, lambda:[body.getvalue()])
2528- self._chunk_parser.close()
2529- self._parse_state = self._look_for_content
2530-
2531- def get_details(self, for_skip=False):
2532- return self._details
2533-
2534- def get_message(self):
2535- return None
2536-
2537- def lineReceived(self, line):
2538- self._parse_state(line)
2539
2540=== removed file 'python-for-subunit2junitxml/subunit/iso8601.py'
2541--- python-for-subunit2junitxml/subunit/iso8601.py 2013-05-27 13:46:13 +0000
2542+++ python-for-subunit2junitxml/subunit/iso8601.py 1970-01-01 00:00:00 +0000
2543@@ -1,133 +0,0 @@
2544-# Copyright (c) 2007 Michael Twomey
2545-#
2546-# Permission is hereby granted, free of charge, to any person obtaining a
2547-# copy of this software and associated documentation files (the
2548-# "Software"), to deal in the Software without restriction, including
2549-# without limitation the rights to use, copy, modify, merge, publish,
2550-# distribute, sublicense, and/or sell copies of the Software, and to
2551-# permit persons to whom the Software is furnished to do so, subject to
2552-# the following conditions:
2553-#
2554-# The above copyright notice and this permission notice shall be included
2555-# in all copies or substantial portions of the Software.
2556-#
2557-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
2558-# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
2559-# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
2560-# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
2561-# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
2562-# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
2563-# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2564-
2565-"""ISO 8601 date time string parsing
2566-
2567-Basic usage:
2568->>> import iso8601
2569->>> iso8601.parse_date("2007-01-25T12:00:00Z")
2570-datetime.datetime(2007, 1, 25, 12, 0, tzinfo=<iso8601.iso8601.Utc ...>)
2571->>>
2572-
2573-"""
2574-
2575-from datetime import datetime, timedelta, tzinfo
2576-import re
2577-import sys
2578-
2579-__all__ = ["parse_date", "ParseError"]
2580-
2581-# Adapted from http://delete.me.uk/2005/03/iso8601.html
2582-ISO8601_REGEX_PATTERN = (r"(?P<year>[0-9]{4})(-(?P<month>[0-9]{1,2})(-(?P<day>[0-9]{1,2})"
2583- r"((?P<separator>.)(?P<hour>[0-9]{2}):(?P<minute>[0-9]{2})(:(?P<second>[0-9]{2})(\.(?P<fraction>[0-9]+))?)?"
2584- r"(?P<timezone>Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?"
2585-)
2586-TIMEZONE_REGEX_PATTERN = "(?P<prefix>[+-])(?P<hours>[0-9]{2}).(?P<minutes>[0-9]{2})"
2587-ISO8601_REGEX = re.compile(ISO8601_REGEX_PATTERN.encode('utf8'))
2588-TIMEZONE_REGEX = re.compile(TIMEZONE_REGEX_PATTERN.encode('utf8'))
2589-
2590-zulu = "Z".encode('latin-1')
2591-minus = "-".encode('latin-1')
2592-
2593-if sys.version_info < (3, 0):
2594- bytes = str
2595-
2596-
2597-class ParseError(Exception):
2598- """Raised when there is a problem parsing a date string"""
2599-
2600-# Yoinked from python docs
2601-ZERO = timedelta(0)
2602-class Utc(tzinfo):
2603- """UTC
2604-
2605- """
2606- def utcoffset(self, dt):
2607- return ZERO
2608-
2609- def tzname(self, dt):
2610- return "UTC"
2611-
2612- def dst(self, dt):
2613- return ZERO
2614-UTC = Utc()
2615-
2616-class FixedOffset(tzinfo):
2617- """Fixed offset in hours and minutes from UTC
2618-
2619- """
2620- def __init__(self, offset_hours, offset_minutes, name):
2621- self.__offset = timedelta(hours=offset_hours, minutes=offset_minutes)
2622- self.__name = name
2623-
2624- def utcoffset(self, dt):
2625- return self.__offset
2626-
2627- def tzname(self, dt):
2628- return self.__name
2629-
2630- def dst(self, dt):
2631- return ZERO
2632-
2633- def __repr__(self):
2634- return "<FixedOffset %r>" % self.__name
2635-
2636-def parse_timezone(tzstring, default_timezone=UTC):
2637- """Parses ISO 8601 time zone specs into tzinfo offsets
2638-
2639- """
2640- if tzstring == zulu:
2641- return default_timezone
2642- # This isn't strictly correct, but it's common to encounter dates without
2643- # timezones so I'll assume the default (which defaults to UTC).
2644- # Addresses issue 4.
2645- if tzstring is None:
2646- return default_timezone
2647- m = TIMEZONE_REGEX.match(tzstring)
2648- prefix, hours, minutes = m.groups()
2649- hours, minutes = int(hours), int(minutes)
2650- if prefix == minus:
2651- hours = -hours
2652- minutes = -minutes
2653- return FixedOffset(hours, minutes, tzstring)
2654-
2655-def parse_date(datestring, default_timezone=UTC):
2656- """Parses ISO 8601 dates into datetime objects
2657-
2658- The timezone is parsed from the date string. However it is quite common to
2659- have dates without a timezone (not strictly correct). In this case the
2660- default timezone specified in default_timezone is used. This is UTC by
2661- default.
2662- """
2663- if not isinstance(datestring, bytes):
2664- raise ParseError("Expecting bytes %r" % datestring)
2665- m = ISO8601_REGEX.match(datestring)
2666- if not m:
2667- raise ParseError("Unable to parse date string %r" % datestring)
2668- groups = m.groupdict()
2669- tz = parse_timezone(groups["timezone"], default_timezone=default_timezone)
2670- if groups["fraction"] is None:
2671- groups["fraction"] = 0
2672- else:
2673- groups["fraction"] = int(float("0.%s" % groups["fraction"]) * 1e6)
2674- return datetime(int(groups["year"]), int(groups["month"]), int(groups["day"]),
2675- int(groups["hour"]), int(groups["minute"]), int(groups["second"]),
2676- int(groups["fraction"]), tz)
2677
2678=== removed file 'python-for-subunit2junitxml/subunit/progress_model.py'
2679--- python-for-subunit2junitxml/subunit/progress_model.py 2013-05-27 13:46:13 +0000
2680+++ python-for-subunit2junitxml/subunit/progress_model.py 1970-01-01 00:00:00 +0000
2681@@ -1,106 +0,0 @@
2682-#
2683-# subunit: extensions to Python unittest to get test results from subprocesses.
2684-# Copyright (C) 2009 Robert Collins <robertc@robertcollins.net>
2685-#
2686-# Licensed under either the Apache License, Version 2.0 or the BSD 3-clause
2687-# license at the users choice. A copy of both licenses are available in the
2688-# project source as Apache-2.0 and BSD. You may not use this file except in
2689-# compliance with one of these two licences.
2690-#
2691-# Unless required by applicable law or agreed to in writing, software
2692-# distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT
2693-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
2694-# license you chose for the specific language governing permissions and
2695-# limitations under that license.
2696-#
2697-
2698-"""Support for dealing with progress state."""
2699-
2700-class ProgressModel(object):
2701- """A model of progress indicators as subunit defines it.
2702-
2703- Instances of this class represent a single logical operation that is
2704- progressing. The operation may have many steps, and some of those steps may
2705- supply their own progress information. ProgressModel uses a nested concept
2706- where the overall state can be pushed, creating new starting state, and
2707- later pushed to return to the prior state. Many user interfaces will want
2708- to display an overall summary though, and accordingly the pos() and width()
2709- methods return overall summary information rather than information on the
2710- current subtask.
2711-
2712- The default state is 0/0 - indicating that the overall progress is unknown.
2713- Anytime the denominator of pos/width is 0, rendering of a ProgressModel
2714- should should take this into consideration.
2715-
2716- :ivar: _tasks. This private attribute stores the subtasks. Each is a tuple:
2717- pos, width, overall_numerator, overall_denominator. The overall fields
2718- store the calculated overall numerator and denominator for the state
2719- that was pushed.
2720- """
2721-
2722- def __init__(self):
2723- """Create a ProgressModel.
2724-
2725- The new model has no progress data at all - it will claim a summary
2726- width of zero and position of 0.
2727- """
2728- self._tasks = []
2729- self.push()
2730-
2731- def adjust_width(self, offset):
2732- """Adjust the with of the current subtask."""
2733- self._tasks[-1][1] += offset
2734-
2735- def advance(self):
2736- """Advance the current subtask."""
2737- self._tasks[-1][0] += 1
2738-
2739- def pop(self):
2740- """Pop a subtask off the ProgressModel.
2741-
2742- See push for a description of how push and pop work.
2743- """
2744- self._tasks.pop()
2745-
2746- def pos(self):
2747- """Return how far through the operation has progressed."""
2748- if not self._tasks:
2749- return 0
2750- task = self._tasks[-1]
2751- if len(self._tasks) > 1:
2752- # scale up the overall pos by the current task or preserve it if
2753- # no current width is known.
2754- offset = task[2] * (task[1] or 1)
2755- else:
2756- offset = 0
2757- return offset + task[0]
2758-
2759- def push(self):
2760- """Push a new subtask.
2761-
2762- After pushing a new subtask, the overall progress hasn't changed. Calls
2763- to adjust_width, advance, set_width will only after the progress within
2764- the range that calling 'advance' would have before - the subtask
2765- represents progressing one step in the earlier task.
2766-
2767- Call pop() to restore the progress model to the state before push was
2768- called.
2769- """
2770- self._tasks.append([0, 0, self.pos(), self.width()])
2771-
2772- def set_width(self, width):
2773- """Set the width of the current subtask."""
2774- self._tasks[-1][1] = width
2775-
2776- def width(self):
2777- """Return the total width of the operation."""
2778- if not self._tasks:
2779- return 0
2780- task = self._tasks[-1]
2781- if len(self._tasks) > 1:
2782- # scale up the overall width by the current task or preserve it if
2783- # no current width is known.
2784- return task[3] * (task[1] or 1)
2785- else:
2786- return task[1]
2787-
2788
2789=== removed file 'python-for-subunit2junitxml/subunit/run.py'
2790--- python-for-subunit2junitxml/subunit/run.py 2013-05-27 13:46:13 +0000
2791+++ python-for-subunit2junitxml/subunit/run.py 1970-01-01 00:00:00 +0000
2792@@ -1,73 +0,0 @@
2793-#!/usr/bin/python
2794-#
2795-# Simple subunit testrunner for python
2796-# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007
2797-#
2798-# Licensed under either the Apache License, Version 2.0 or the BSD 3-clause
2799-# license at the users choice. A copy of both licenses are available in the
2800-# project source as Apache-2.0 and BSD. You may not use this file except in
2801-# compliance with one of these two licences.
2802-#
2803-# Unless required by applicable law or agreed to in writing, software
2804-# distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT
2805-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
2806-# license you chose for the specific language governing permissions and
2807-# limitations under that license.
2808-#
2809-
2810-"""Run a unittest testcase reporting results as Subunit.
2811-
2812- $ python -m subunit.run mylib.tests.test_suite
2813-"""
2814-
2815-import sys
2816-
2817-from subunit import TestProtocolClient, get_default_formatter
2818-from testtools.run import (
2819- BUFFEROUTPUT,
2820- CATCHBREAK,
2821- FAILFAST,
2822- TestProgram,
2823- USAGE_AS_MAIN,
2824- )
2825-
2826-
2827-class SubunitTestRunner(object):
2828- def __init__(self, stream=sys.stdout):
2829- self.stream = stream
2830-
2831- def run(self, test):
2832- "Run the given test case or test suite."
2833- result = TestProtocolClient(self.stream)
2834- test(result)
2835- return result
2836-
2837-
2838-class SubunitTestProgram(TestProgram):
2839-
2840- USAGE = USAGE_AS_MAIN
2841-
2842- def usageExit(self, msg=None):
2843- if msg:
2844- print msg
2845- usage = {'progName': self.progName, 'catchbreak': '', 'failfast': '',
2846- 'buffer': ''}
2847- if self.failfast != False:
2848- usage['failfast'] = FAILFAST
2849- if self.catchbreak != False:
2850- usage['catchbreak'] = CATCHBREAK
2851- if self.buffer != False:
2852- usage['buffer'] = BUFFEROUTPUT
2853- usage_text = self.USAGE % usage
2854- usage_lines = usage_text.split('\n')
2855- usage_lines.insert(2, "Run a test suite with a subunit reporter.")
2856- usage_lines.insert(3, "")
2857- print('\n'.join(usage_lines))
2858- sys.exit(2)
2859-
2860-
2861-if __name__ == '__main__':
2862- stream = get_default_formatter()
2863- runner = SubunitTestRunner(stream)
2864- SubunitTestProgram(module=None, argv=sys.argv, testRunner=runner,
2865- stdout=sys.stdout)
2866
2867=== removed file 'python-for-subunit2junitxml/subunit/test_results.py'
2868--- python-for-subunit2junitxml/subunit/test_results.py 2013-05-27 13:46:13 +0000
2869+++ python-for-subunit2junitxml/subunit/test_results.py 1970-01-01 00:00:00 +0000
2870@@ -1,492 +0,0 @@
2871-#
2872-# subunit: extensions to Python unittest to get test results from subprocesses.
2873-# Copyright (C) 2009 Robert Collins <robertc@robertcollins.net>
2874-#
2875-# Licensed under either the Apache License, Version 2.0 or the BSD 3-clause
2876-# license at the users choice. A copy of both licenses are available in the
2877-# project source as Apache-2.0 and BSD. You may not use this file except in
2878-# compliance with one of these two licences.
2879-#
2880-# Unless required by applicable law or agreed to in writing, software
2881-# distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT
2882-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
2883-# license you chose for the specific language governing permissions and
2884-# limitations under that license.
2885-#
2886-
2887-"""TestResult helper classes used to by subunit."""
2888-
2889-import datetime
2890-
2891-import testtools
2892-
2893-from subunit import iso8601
2894-
2895-
2896-# NOT a TestResult, because we are implementing the interface, not inheriting
2897-# it.
2898-class TestResultDecorator(object):
2899- """General pass-through decorator.
2900-
2901- This provides a base that other TestResults can inherit from to
2902- gain basic forwarding functionality. It also takes care of
2903- handling the case where the target doesn't support newer methods
2904- or features by degrading them.
2905- """
2906-
2907- def __init__(self, decorated):
2908- """Create a TestResultDecorator forwarding to decorated."""
2909- # Make every decorator degrade gracefully.
2910- self.decorated = testtools.ExtendedToOriginalDecorator(decorated)
2911-
2912- def startTest(self, test):
2913- return self.decorated.startTest(test)
2914-
2915- def startTestRun(self):
2916- return self.decorated.startTestRun()
2917-
2918- def stopTest(self, test):
2919- return self.decorated.stopTest(test)
2920-
2921- def stopTestRun(self):
2922- return self.decorated.stopTestRun()
2923-
2924- def addError(self, test, err=None, details=None):
2925- return self.decorated.addError(test, err, details=details)
2926-
2927- def addFailure(self, test, err=None, details=None):
2928- return self.decorated.addFailure(test, err, details=details)
2929-
2930- def addSuccess(self, test, details=None):
2931- return self.decorated.addSuccess(test, details=details)
2932-
2933- def addSkip(self, test, reason=None, details=None):
2934- return self.decorated.addSkip(test, reason, details=details)
2935-
2936- def addExpectedFailure(self, test, err=None, details=None):
2937- return self.decorated.addExpectedFailure(test, err, details=details)
2938-
2939- def addUnexpectedSuccess(self, test, details=None):
2940- return self.decorated.addUnexpectedSuccess(test, details=details)
2941-
2942- def progress(self, offset, whence):
2943- return self.decorated.progress(offset, whence)
2944-
2945- def wasSuccessful(self):
2946- return self.decorated.wasSuccessful()
2947-
2948- @property
2949- def shouldStop(self):
2950- return self.decorated.shouldStop
2951-
2952- def stop(self):
2953- return self.decorated.stop()
2954-
2955- @property
2956- def testsRun(self):
2957- return self.decorated.testsRun
2958-
2959- def tags(self, new_tags, gone_tags):
2960- return self.decorated.tags(new_tags, gone_tags)
2961-
2962- def time(self, a_datetime):
2963- return self.decorated.time(a_datetime)
2964-
2965-
2966-class HookedTestResultDecorator(TestResultDecorator):
2967- """A TestResult which calls a hook on every event."""
2968-
2969- def __init__(self, decorated):
2970- self.super = super(HookedTestResultDecorator, self)
2971- self.super.__init__(decorated)
2972-
2973- def startTest(self, test):
2974- self._before_event()
2975- return self.super.startTest(test)
2976-
2977- def startTestRun(self):
2978- self._before_event()
2979- return self.super.startTestRun()
2980-
2981- def stopTest(self, test):
2982- self._before_event()
2983- return self.super.stopTest(test)
2984-
2985- def stopTestRun(self):
2986- self._before_event()
2987- return self.super.stopTestRun()
2988-
2989- def addError(self, test, err=None, details=None):
2990- self._before_event()
2991- return self.super.addError(test, err, details=details)
2992-
2993- def addFailure(self, test, err=None, details=None):
2994- self._before_event()
2995- return self.super.addFailure(test, err, details=details)
2996-
2997- def addSuccess(self, test, details=None):
2998- self._before_event()
2999- return self.super.addSuccess(test, details=details)
3000-
3001- def addSkip(self, test, reason=None, details=None):
3002- self._before_event()
3003- return self.super.addSkip(test, reason, details=details)
3004-
3005- def addExpectedFailure(self, test, err=None, details=None):
3006- self._before_event()
3007- return self.super.addExpectedFailure(test, err, details=details)
3008-
3009- def addUnexpectedSuccess(self, test, details=None):
3010- self._before_event()
3011- return self.super.addUnexpectedSuccess(test, details=details)
3012-
3013- def progress(self, offset, whence):
3014- self._before_event()
3015- return self.super.progress(offset, whence)
3016-
3017- def wasSuccessful(self):
3018- self._before_event()
3019- return self.super.wasSuccessful()
3020-
3021- @property
3022- def shouldStop(self):
3023- self._before_event()
3024- return self.super.shouldStop
3025-
3026- def stop(self):
3027- self._before_event()
3028- return self.super.stop()
3029-
3030- def time(self, a_datetime):
3031- self._before_event()
3032- return self.super.time(a_datetime)
3033-
3034-
3035-class AutoTimingTestResultDecorator(HookedTestResultDecorator):
3036- """Decorate a TestResult to add time events to a test run.
3037-
3038- By default this will cause a time event before every test event,
3039- but if explicit time data is being provided by the test run, then
3040- this decorator will turn itself off to prevent causing confusion.
3041- """
3042-
3043- def __init__(self, decorated):
3044- self._time = None
3045- super(AutoTimingTestResultDecorator, self).__init__(decorated)
3046-
3047- def _before_event(self):
3048- time = self._time
3049- if time is not None:
3050- return
3051- time = datetime.datetime.utcnow().replace(tzinfo=iso8601.Utc())
3052- self.decorated.time(time)
3053-
3054- def progress(self, offset, whence):
3055- return self.decorated.progress(offset, whence)
3056-
3057- @property
3058- def shouldStop(self):
3059- return self.decorated.shouldStop
3060-
3061- def time(self, a_datetime):
3062- """Provide a timestamp for the current test activity.
3063-
3064- :param a_datetime: If None, automatically add timestamps before every
3065- event (this is the default behaviour if time() is not called at
3066- all). If not None, pass the provided time onto the decorated
3067- result object and disable automatic timestamps.
3068- """
3069- self._time = a_datetime
3070- return self.decorated.time(a_datetime)
3071-
3072-
3073-class TagCollapsingDecorator(TestResultDecorator):
3074- """Collapses many 'tags' calls into one where possible."""
3075-
3076- def __init__(self, result):
3077- super(TagCollapsingDecorator, self).__init__(result)
3078- # The (new, gone) tags for the current test.
3079- self._current_test_tags = None
3080-
3081- def startTest(self, test):
3082- """Start a test.
3083-
3084- Not directly passed to the client, but used for handling of tags
3085- correctly.
3086- """
3087- self.decorated.startTest(test)
3088- self._current_test_tags = set(), set()
3089-
3090- def stopTest(self, test):
3091- """Stop a test.
3092-
3093- Not directly passed to the client, but used for handling of tags
3094- correctly.
3095- """
3096- # Tags to output for this test.
3097- if self._current_test_tags[0] or self._current_test_tags[1]:
3098- self.decorated.tags(*self._current_test_tags)
3099- self.decorated.stopTest(test)
3100- self._current_test_tags = None
3101-
3102- def tags(self, new_tags, gone_tags):
3103- """Handle tag instructions.
3104-
3105- Adds and removes tags as appropriate. If a test is currently running,
3106- tags are not affected for subsequent tests.
3107-
3108- :param new_tags: Tags to add,
3109- :param gone_tags: Tags to remove.
3110- """
3111- if self._current_test_tags is not None:
3112- # gather the tags until the test stops.
3113- self._current_test_tags[0].update(new_tags)
3114- self._current_test_tags[0].difference_update(gone_tags)
3115- self._current_test_tags[1].update(gone_tags)
3116- self._current_test_tags[1].difference_update(new_tags)
3117- else:
3118- return self.decorated.tags(new_tags, gone_tags)
3119-
3120-
3121-class TimeCollapsingDecorator(HookedTestResultDecorator):
3122- """Only pass on the first and last of a consecutive sequence of times."""
3123-
3124- def __init__(self, decorated):
3125- super(TimeCollapsingDecorator, self).__init__(decorated)
3126- self._last_received_time = None
3127- self._last_sent_time = None
3128-
3129- def _before_event(self):
3130- if self._last_received_time is None:
3131- return
3132- if self._last_received_time != self._last_sent_time:
3133- self.decorated.time(self._last_received_time)
3134- self._last_sent_time = self._last_received_time
3135- self._last_received_time = None
3136-
3137- def time(self, a_time):
3138- # Don't upcall, because we don't want to call _before_event, it's only
3139- # for non-time events.
3140- if self._last_received_time is None:
3141- self.decorated.time(a_time)
3142- self._last_sent_time = a_time
3143- self._last_received_time = a_time
3144-
3145-
3146-def all_true(bools):
3147- """Return True if all of 'bools' are True. False otherwise."""
3148- for b in bools:
3149- if not b:
3150- return False
3151- return True
3152-
3153-
3154-class TestResultFilter(TestResultDecorator):
3155- """A pyunit TestResult interface implementation which filters tests.
3156-
3157- Tests that pass the filter are handed on to another TestResult instance
3158- for further processing/reporting. To obtain the filtered results,
3159- the other instance must be interrogated.
3160-
3161- :ivar result: The result that tests are passed to after filtering.
3162- :ivar filter_predicate: The callback run to decide whether to pass
3163- a result.
3164- """
3165-
3166- def __init__(self, result, filter_error=False, filter_failure=False,
3167- filter_success=True, filter_skip=False,
3168- filter_predicate=None, fixup_expected_failures=None):
3169- """Create a FilterResult object filtering to result.
3170-
3171- :param filter_error: Filter out errors.
3172- :param filter_failure: Filter out failures.
3173- :param filter_success: Filter out successful tests.
3174- :param filter_skip: Filter out skipped tests.
3175- :param filter_predicate: A callable taking (test, outcome, err,
3176- details) and returning True if the result should be passed
3177- through. err and details may be none if no error or extra
3178- metadata is available. outcome is the name of the outcome such
3179- as 'success' or 'failure'.
3180- :param fixup_expected_failures: Set of test ids to consider known
3181- failing.
3182- """
3183- super(TestResultFilter, self).__init__(result)
3184- self.decorated = TimeCollapsingDecorator(
3185- TagCollapsingDecorator(self.decorated))
3186- predicates = []
3187- if filter_error:
3188- predicates.append(lambda t, outcome, e, d: outcome != 'error')
3189- if filter_failure:
3190- predicates.append(lambda t, outcome, e, d: outcome != 'failure')
3191- if filter_success:
3192- predicates.append(lambda t, outcome, e, d: outcome != 'success')
3193- if filter_skip:
3194- predicates.append(lambda t, outcome, e, d: outcome != 'skip')
3195- if filter_predicate is not None:
3196- predicates.append(filter_predicate)
3197- self.filter_predicate = (
3198- lambda test, outcome, err, details:
3199- all_true(p(test, outcome, err, details) for p in predicates))
3200- # The current test (for filtering tags)
3201- self._current_test = None
3202- # Has the current test been filtered (for outputting test tags)
3203- self._current_test_filtered = None
3204- # Calls to this result that we don't know whether to forward on yet.
3205- self._buffered_calls = []
3206- if fixup_expected_failures is None:
3207- self._fixup_expected_failures = frozenset()
3208- else:
3209- self._fixup_expected_failures = fixup_expected_failures
3210-
3211- def addError(self, test, err=None, details=None):
3212- if (self.filter_predicate(test, 'error', err, details)):
3213- if self._failure_expected(test):
3214- self._buffered_calls.append(
3215- ('addExpectedFailure', [test, err], {'details': details}))
3216- else:
3217- self._buffered_calls.append(
3218- ('addError', [test, err], {'details': details}))
3219- else:
3220- self._filtered()
3221-
3222- def addFailure(self, test, err=None, details=None):
3223- if (self.filter_predicate(test, 'failure', err, details)):
3224- if self._failure_expected(test):
3225- self._buffered_calls.append(
3226- ('addExpectedFailure', [test, err], {'details': details}))
3227- else:
3228- self._buffered_calls.append(
3229- ('addFailure', [test, err], {'details': details}))
3230- else:
3231- self._filtered()
3232-
3233- def addSkip(self, test, reason=None, details=None):
3234- if (self.filter_predicate(test, 'skip', reason, details)):
3235- self._buffered_calls.append(
3236- ('addSkip', [test, reason], {'details': details}))
3237- else:
3238- self._filtered()
3239-
3240- def addSuccess(self, test, details=None):
3241- if (self.filter_predicate(test, 'success', None, details)):
3242- if self._failure_expected(test):
3243- self._buffered_calls.append(
3244- ('addUnexpectedSuccess', [test], {'details': details}))
3245- else:
3246- self._buffered_calls.append(
3247- ('addSuccess', [test], {'details': details}))
3248- else:
3249- self._filtered()
3250-
3251- def addExpectedFailure(self, test, err=None, details=None):
3252- if self.filter_predicate(test, 'expectedfailure', err, details):
3253- self._buffered_calls.append(
3254- ('addExpectedFailure', [test, err], {'details': details}))
3255- else:
3256- self._filtered()
3257-
3258- def addUnexpectedSuccess(self, test, details=None):
3259- self._buffered_calls.append(
3260- ('addUnexpectedSuccess', [test], {'details': details}))
3261-
3262- def _filtered(self):
3263- self._current_test_filtered = True
3264-
3265- def _failure_expected(self, test):
3266- return (test.id() in self._fixup_expected_failures)
3267-
3268- def startTest(self, test):
3269- """Start a test.
3270-
3271- Not directly passed to the client, but used for handling of tags
3272- correctly.
3273- """
3274- self._current_test = test
3275- self._current_test_filtered = False
3276- self._buffered_calls.append(('startTest', [test], {}))
3277-
3278- def stopTest(self, test):
3279- """Stop a test.
3280-
3281- Not directly passed to the client, but used for handling of tags
3282- correctly.
3283- """
3284- if not self._current_test_filtered:
3285- # Tags to output for this test.
3286- for method, args, kwargs in self._buffered_calls:
3287- getattr(self.decorated, method)(*args, **kwargs)
3288- self.decorated.stopTest(test)
3289- self._current_test = None
3290- self._current_test_filtered = None
3291- self._buffered_calls = []
3292-
3293- def time(self, a_time):
3294- if self._current_test is not None:
3295- self._buffered_calls.append(('time', [a_time], {}))
3296- else:
3297- return self.decorated.time(a_time)
3298-
3299- def id_to_orig_id(self, id):
3300- if id.startswith("subunit.RemotedTestCase."):
3301- return id[len("subunit.RemotedTestCase."):]
3302- return id
3303-
3304-
3305-class TestIdPrintingResult(testtools.TestResult):
3306-
3307- def __init__(self, stream, show_times=False):
3308- """Create a FilterResult object outputting to stream."""
3309- super(TestIdPrintingResult, self).__init__()
3310- self._stream = stream
3311- self.failed_tests = 0
3312- self.__time = None
3313- self.show_times = show_times
3314- self._test = None
3315- self._test_duration = 0
3316-
3317- def addError(self, test, err):
3318- self.failed_tests += 1
3319- self._test = test
3320-
3321- def addFailure(self, test, err):
3322- self.failed_tests += 1
3323- self._test = test
3324-
3325- def addSuccess(self, test):
3326- self._test = test
3327-
3328- def addSkip(self, test, reason=None, details=None):
3329- self._test = test
3330-
3331- def addUnexpectedSuccess(self, test, details=None):
3332- self.failed_tests += 1
3333- self._test = test
3334-
3335- def addExpectedFailure(self, test, err=None, details=None):
3336- self._test = test
3337-
3338- def reportTest(self, test, duration):
3339- if self.show_times:
3340- seconds = duration.seconds
3341- seconds += duration.days * 3600 * 24
3342- seconds += duration.microseconds / 1000000.0
3343- self._stream.write(test.id() + ' %0.3f\n' % seconds)
3344- else:
3345- self._stream.write(test.id() + '\n')
3346-
3347- def startTest(self, test):
3348- self._start_time = self._time()
3349-
3350- def stopTest(self, test):
3351- test_duration = self._time() - self._start_time
3352- self.reportTest(self._test, test_duration)
3353-
3354- def time(self, time):
3355- self.__time = time
3356-
3357- def _time(self):
3358- return self.__time
3359-
3360- def wasSuccessful(self):
3361- "Tells whether or not this result was a success"
3362- return self.failed_tests == 0
3363
3364=== removed directory 'python-for-subunit2junitxml/subunit/tests'
3365=== removed file 'python-for-subunit2junitxml/subunit/tests/TestUtil.py'
3366--- python-for-subunit2junitxml/subunit/tests/TestUtil.py 2013-05-27 13:46:13 +0000
3367+++ python-for-subunit2junitxml/subunit/tests/TestUtil.py 1970-01-01 00:00:00 +0000
3368@@ -1,80 +0,0 @@
3369-# Copyright (c) 2004 Canonical Limited
3370-# Author: Robert Collins <robert.collins@canonical.com>
3371-#
3372-# This program is free software; you can redistribute it and/or modify
3373-# it under the terms of the GNU General Public License as published by
3374-# the Free Software Foundation; either version 2 of the License, or
3375-# (at your option) any later version.
3376-#
3377-# This program is distributed in the hope that it will be useful,
3378-# but WITHOUT ANY WARRANTY; without even the implied warranty of
3379-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3380-# GNU General Public License for more details.
3381-#
3382-# You should have received a copy of the GNU General Public License
3383-# along with this program; if not, write to the Free Software
3384-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
3385-#
3386-
3387-import sys
3388-import logging
3389-import unittest
3390-
3391-
3392-class LogCollector(logging.Handler):
3393- def __init__(self):
3394- logging.Handler.__init__(self)
3395- self.records=[]
3396- def emit(self, record):
3397- self.records.append(record.getMessage())
3398-
3399-
3400-def makeCollectingLogger():
3401- """I make a logger instance that collects its logs for programmatic analysis
3402- -> (logger, collector)"""
3403- logger=logging.Logger("collector")
3404- handler=LogCollector()
3405- handler.setFormatter(logging.Formatter("%(levelname)s: %(message)s"))
3406- logger.addHandler(handler)
3407- return logger, handler
3408-
3409-
3410-def visitTests(suite, visitor):
3411- """A foreign method for visiting the tests in a test suite."""
3412- for test in suite._tests:
3413- #Abusing types to avoid monkey patching unittest.TestCase.
3414- # Maybe that would be better?
3415- try:
3416- test.visit(visitor)
3417- except AttributeError:
3418- if isinstance(test, unittest.TestCase):
3419- visitor.visitCase(test)
3420- elif isinstance(test, unittest.TestSuite):
3421- visitor.visitSuite(test)
3422- visitTests(test, visitor)
3423- else:
3424- print ("unvisitable non-unittest.TestCase element %r (%r)" % (test, test.__class__))
3425-
3426-
3427-class TestSuite(unittest.TestSuite):
3428- """I am an extended TestSuite with a visitor interface.
3429- This is primarily to allow filtering of tests - and suites or
3430- more in the future. An iterator of just tests wouldn't scale..."""
3431-
3432- def visit(self, visitor):
3433- """visit the composite. Visiting is depth-first.
3434- current callbacks are visitSuite and visitCase."""
3435- visitor.visitSuite(self)
3436- visitTests(self, visitor)
3437-
3438-
3439-class TestLoader(unittest.TestLoader):
3440- """Custome TestLoader to set the right TestSuite class."""
3441- suiteClass = TestSuite
3442-
3443-class TestVisitor(object):
3444- """A visitor for Tests"""
3445- def visitSuite(self, aTestSuite):
3446- pass
3447- def visitCase(self, aTestCase):
3448- pass
3449
3450=== removed file 'python-for-subunit2junitxml/subunit/tests/__init__.py'
3451--- python-for-subunit2junitxml/subunit/tests/__init__.py 2013-05-27 13:46:13 +0000
3452+++ python-for-subunit2junitxml/subunit/tests/__init__.py 1970-01-01 00:00:00 +0000
3453@@ -1,41 +0,0 @@
3454-#
3455-# subunit: extensions to python unittest to get test results from subprocesses.
3456-# Copyright (C) 2005 Robert Collins <robertc@robertcollins.net>
3457-#
3458-# Licensed under either the Apache License, Version 2.0 or the BSD 3-clause
3459-# license at the users choice. A copy of both licenses are available in the
3460-# project source as Apache-2.0 and BSD. You may not use this file except in
3461-# compliance with one of these two licences.
3462-#
3463-# Unless required by applicable law or agreed to in writing, software
3464-# distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT
3465-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
3466-# license you chose for the specific language governing permissions and
3467-# limitations under that license.
3468-#
3469-
3470-from subunit.tests import (
3471- TestUtil,
3472- test_chunked,
3473- test_details,
3474- test_progress_model,
3475- test_subunit_filter,
3476- test_subunit_stats,
3477- test_subunit_tags,
3478- test_tap2subunit,
3479- test_test_protocol,
3480- test_test_results,
3481- )
3482-
3483-def test_suite():
3484- result = TestUtil.TestSuite()
3485- result.addTest(test_chunked.test_suite())
3486- result.addTest(test_details.test_suite())
3487- result.addTest(test_progress_model.test_suite())
3488- result.addTest(test_test_results.test_suite())
3489- result.addTest(test_test_protocol.test_suite())
3490- result.addTest(test_tap2subunit.test_suite())
3491- result.addTest(test_subunit_filter.test_suite())
3492- result.addTest(test_subunit_tags.test_suite())
3493- result.addTest(test_subunit_stats.test_suite())
3494- return result
3495
3496=== removed file 'python-for-subunit2junitxml/subunit/tests/sample-script.py'
3497--- python-for-subunit2junitxml/subunit/tests/sample-script.py 2013-05-27 13:46:13 +0000
3498+++ python-for-subunit2junitxml/subunit/tests/sample-script.py 1970-01-01 00:00:00 +0000
3499@@ -1,21 +0,0 @@
3500-#!/usr/bin/env python
3501-import sys
3502-if sys.platform == "win32":
3503- import msvcrt, os
3504- msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
3505-if len(sys.argv) == 2:
3506- # subunit.tests.test_test_protocol.TestExecTestCase.test_sample_method_args
3507- # uses this code path to be sure that the arguments were passed to
3508- # sample-script.py
3509- print "test fail"
3510- print "error fail"
3511- sys.exit(0)
3512-print "test old mcdonald"
3513-print "success old mcdonald"
3514-print "test bing crosby"
3515-print "failure bing crosby ["
3516-print "foo.c:53:ERROR invalid state"
3517-print "]"
3518-print "test an error"
3519-print "error an error"
3520-sys.exit(0)
3521
3522=== removed file 'python-for-subunit2junitxml/subunit/tests/sample-two-script.py'
3523--- python-for-subunit2junitxml/subunit/tests/sample-two-script.py 2013-05-27 13:46:13 +0000
3524+++ python-for-subunit2junitxml/subunit/tests/sample-two-script.py 1970-01-01 00:00:00 +0000
3525@@ -1,7 +0,0 @@
3526-#!/usr/bin/env python
3527-import sys
3528-print "test old mcdonald"
3529-print "success old mcdonald"
3530-print "test bing crosby"
3531-print "success bing crosby"
3532-sys.exit(0)
3533
3534=== removed file 'python-for-subunit2junitxml/subunit/tests/test_chunked.py'
3535--- python-for-subunit2junitxml/subunit/tests/test_chunked.py 2013-05-27 13:46:13 +0000
3536+++ python-for-subunit2junitxml/subunit/tests/test_chunked.py 1970-01-01 00:00:00 +0000
3537@@ -1,152 +0,0 @@
3538-#
3539-# subunit: extensions to python unittest to get test results from subprocesses.
3540-# Copyright (C) 2005 Robert Collins <robertc@robertcollins.net>
3541-# Copyright (C) 2011 Martin Pool <mbp@sourcefrog.net>
3542-#
3543-# Licensed under either the Apache License, Version 2.0 or the BSD 3-clause
3544-# license at the users choice. A copy of both licenses are available in the
3545-# project source as Apache-2.0 and BSD. You may not use this file except in
3546-# compliance with one of these two licences.
3547-#
3548-# Unless required by applicable law or agreed to in writing, software
3549-# distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT
3550-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
3551-# license you chose for the specific language governing permissions and
3552-# limitations under that license.
3553-#
3554-
3555-import unittest
3556-
3557-from testtools.compat import _b, BytesIO
3558-
3559-import subunit.chunked
3560-
3561-
3562-def test_suite():
3563- loader = subunit.tests.TestUtil.TestLoader()
3564- result = loader.loadTestsFromName(__name__)
3565- return result
3566-
3567-
3568-class TestDecode(unittest.TestCase):
3569-
3570- def setUp(self):
3571- unittest.TestCase.setUp(self)
3572- self.output = BytesIO()
3573- self.decoder = subunit.chunked.Decoder(self.output)
3574-
3575- def test_close_read_length_short_errors(self):
3576- self.assertRaises(ValueError, self.decoder.close)
3577-
3578- def test_close_body_short_errors(self):
3579- self.assertEqual(None, self.decoder.write(_b('2\r\na')))
3580- self.assertRaises(ValueError, self.decoder.close)
3581-
3582- def test_close_body_buffered_data_errors(self):
3583- self.assertEqual(None, self.decoder.write(_b('2\r')))
3584- self.assertRaises(ValueError, self.decoder.close)
3585-
3586- def test_close_after_finished_stream_safe(self):
3587- self.assertEqual(None, self.decoder.write(_b('2\r\nab')))
3588- self.assertEqual(_b(''), self.decoder.write(_b('0\r\n')))
3589- self.decoder.close()
3590-
3591- def test_decode_nothing(self):
3592- self.assertEqual(_b(''), self.decoder.write(_b('0\r\n')))
3593- self.assertEqual(_b(''), self.output.getvalue())
3594-
3595- def test_decode_serialised_form(self):
3596- self.assertEqual(None, self.decoder.write(_b("F\r\n")))
3597- self.assertEqual(None, self.decoder.write(_b("serialised\n")))
3598- self.assertEqual(_b(''), self.decoder.write(_b("form0\r\n")))
3599-
3600- def test_decode_short(self):
3601- self.assertEqual(_b(''), self.decoder.write(_b('3\r\nabc0\r\n')))
3602- self.assertEqual(_b('abc'), self.output.getvalue())
3603-
3604- def test_decode_combines_short(self):
3605- self.assertEqual(_b(''), self.decoder.write(_b('6\r\nabcdef0\r\n')))
3606- self.assertEqual(_b('abcdef'), self.output.getvalue())
3607-
3608- def test_decode_excess_bytes_from_write(self):
3609- self.assertEqual(_b('1234'), self.decoder.write(_b('3\r\nabc0\r\n1234')))
3610- self.assertEqual(_b('abc'), self.output.getvalue())
3611-
3612- def test_decode_write_after_finished_errors(self):
3613- self.assertEqual(_b('1234'), self.decoder.write(_b('3\r\nabc0\r\n1234')))
3614- self.assertRaises(ValueError, self.decoder.write, _b(''))
3615-
3616- def test_decode_hex(self):
3617- self.assertEqual(_b(''), self.decoder.write(_b('A\r\n12345678900\r\n')))
3618- self.assertEqual(_b('1234567890'), self.output.getvalue())
3619-
3620- def test_decode_long_ranges(self):
3621- self.assertEqual(None, self.decoder.write(_b('10000\r\n')))
3622- self.assertEqual(None, self.decoder.write(_b('1' * 65536)))
3623- self.assertEqual(None, self.decoder.write(_b('10000\r\n')))
3624- self.assertEqual(None, self.decoder.write(_b('2' * 65536)))
3625- self.assertEqual(_b(''), self.decoder.write(_b('0\r\n')))
3626- self.assertEqual(_b('1' * 65536 + '2' * 65536), self.output.getvalue())
3627-
3628- def test_decode_newline_nonstrict(self):
3629- """Tolerate chunk markers with no CR character."""
3630- # From <http://pad.lv/505078>
3631- self.decoder = subunit.chunked.Decoder(self.output, strict=False)
3632- self.assertEqual(None, self.decoder.write(_b('a\n')))
3633- self.assertEqual(None, self.decoder.write(_b('abcdeabcde')))
3634- self.assertEqual(_b(''), self.decoder.write(_b('0\n')))
3635- self.assertEqual(_b('abcdeabcde'), self.output.getvalue())
3636-
3637- def test_decode_strict_newline_only(self):
3638- """Reject chunk markers with no CR character in strict mode."""
3639- # From <http://pad.lv/505078>
3640- self.assertRaises(ValueError,
3641- self.decoder.write, _b('a\n'))
3642-
3643- def test_decode_strict_multiple_crs(self):
3644- self.assertRaises(ValueError,
3645- self.decoder.write, _b('a\r\r\n'))
3646-
3647- def test_decode_short_header(self):
3648- self.assertRaises(ValueError,
3649- self.decoder.write, _b('\n'))
3650-
3651-
3652-class TestEncode(unittest.TestCase):
3653-
3654- def setUp(self):
3655- unittest.TestCase.setUp(self)
3656- self.output = BytesIO()
3657- self.encoder = subunit.chunked.Encoder(self.output)
3658-
3659- def test_encode_nothing(self):
3660- self.encoder.close()
3661- self.assertEqual(_b('0\r\n'), self.output.getvalue())
3662-
3663- def test_encode_empty(self):
3664- self.encoder.write(_b(''))
3665- self.encoder.close()
3666- self.assertEqual(_b('0\r\n'), self.output.getvalue())
3667-
3668- def test_encode_short(self):
3669- self.encoder.write(_b('abc'))
3670- self.encoder.close()
3671- self.assertEqual(_b('3\r\nabc0\r\n'), self.output.getvalue())
3672-
3673- def test_encode_combines_short(self):
3674- self.encoder.write(_b('abc'))
3675- self.encoder.write(_b('def'))
3676- self.encoder.close()
3677- self.assertEqual(_b('6\r\nabcdef0\r\n'), self.output.getvalue())
3678-
3679- def test_encode_over_9_is_in_hex(self):
3680- self.encoder.write(_b('1234567890'))
3681- self.encoder.close()
3682- self.assertEqual(_b('A\r\n12345678900\r\n'), self.output.getvalue())
3683-
3684- def test_encode_long_ranges_not_combined(self):
3685- self.encoder.write(_b('1' * 65536))
3686- self.encoder.write(_b('2' * 65536))
3687- self.encoder.close()
3688- self.assertEqual(_b('10000\r\n' + '1' * 65536 + '10000\r\n' +
3689- '2' * 65536 + '0\r\n'), self.output.getvalue())
3690
3691=== removed file 'python-for-subunit2junitxml/subunit/tests/test_details.py'
3692--- python-for-subunit2junitxml/subunit/tests/test_details.py 2013-05-27 13:46:13 +0000
3693+++ python-for-subunit2junitxml/subunit/tests/test_details.py 1970-01-01 00:00:00 +0000
3694@@ -1,112 +0,0 @@
3695-#
3696-# subunit: extensions to python unittest to get test results from subprocesses.
3697-# Copyright (C) 2005 Robert Collins <robertc@robertcollins.net>
3698-#
3699-# Licensed under either the Apache License, Version 2.0 or the BSD 3-clause
3700-# license at the users choice. A copy of both licenses are available in the
3701-# project source as Apache-2.0 and BSD. You may not use this file except in
3702-# compliance with one of these two licences.
3703-#
3704-# Unless required by applicable law or agreed to in writing, software
3705-# distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT
3706-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
3707-# license you chose for the specific language governing permissions and
3708-# limitations under that license.
3709-#
3710-
3711-import unittest
3712-
3713-from testtools.compat import _b, StringIO
3714-
3715-import subunit.tests
3716-from subunit import content, content_type, details
3717-
3718-
3719-def test_suite():
3720- loader = subunit.tests.TestUtil.TestLoader()
3721- result = loader.loadTestsFromName(__name__)
3722- return result
3723-
3724-
3725-class TestSimpleDetails(unittest.TestCase):
3726-
3727- def test_lineReceived(self):
3728- parser = details.SimpleDetailsParser(None)
3729- parser.lineReceived(_b("foo\n"))
3730- parser.lineReceived(_b("bar\n"))
3731- self.assertEqual(_b("foo\nbar\n"), parser._message)
3732-
3733- def test_lineReceived_escaped_bracket(self):
3734- parser = details.SimpleDetailsParser(None)
3735- parser.lineReceived(_b("foo\n"))
3736- parser.lineReceived(_b(" ]are\n"))
3737- parser.lineReceived(_b("bar\n"))
3738- self.assertEqual(_b("foo\n]are\nbar\n"), parser._message)
3739-
3740- def test_get_message(self):
3741- parser = details.SimpleDetailsParser(None)
3742- self.assertEqual(_b(""), parser.get_message())
3743-
3744- def test_get_details(self):
3745- parser = details.SimpleDetailsParser(None)
3746- traceback = ""
3747- expected = {}
3748- expected['traceback'] = content.Content(
3749- content_type.ContentType("text", "x-traceback",
3750- {'charset': 'utf8'}),
3751- lambda:[_b("")])
3752- found = parser.get_details()
3753- self.assertEqual(expected.keys(), found.keys())
3754- self.assertEqual(expected['traceback'].content_type,
3755- found['traceback'].content_type)
3756- self.assertEqual(_b('').join(expected['traceback'].iter_bytes()),
3757- _b('').join(found['traceback'].iter_bytes()))
3758-
3759- def test_get_details_skip(self):
3760- parser = details.SimpleDetailsParser(None)
3761- traceback = ""
3762- expected = {}
3763- expected['reason'] = content.Content(
3764- content_type.ContentType("text", "plain"),
3765- lambda:[_b("")])
3766- found = parser.get_details("skip")
3767- self.assertEqual(expected, found)
3768-
3769- def test_get_details_success(self):
3770- parser = details.SimpleDetailsParser(None)
3771- traceback = ""
3772- expected = {}
3773- expected['message'] = content.Content(
3774- content_type.ContentType("text", "plain"),
3775- lambda:[_b("")])
3776- found = parser.get_details("success")
3777- self.assertEqual(expected, found)
3778-
3779-
3780-class TestMultipartDetails(unittest.TestCase):
3781-
3782- def test_get_message_is_None(self):
3783- parser = details.MultipartDetailsParser(None)
3784- self.assertEqual(None, parser.get_message())
3785-
3786- def test_get_details(self):
3787- parser = details.MultipartDetailsParser(None)
3788- self.assertEqual({}, parser.get_details())
3789-
3790- def test_parts(self):
3791- parser = details.MultipartDetailsParser(None)
3792- parser.lineReceived(_b("Content-Type: text/plain\n"))
3793- parser.lineReceived(_b("something\n"))
3794- parser.lineReceived(_b("F\r\n"))
3795- parser.lineReceived(_b("serialised\n"))
3796- parser.lineReceived(_b("form0\r\n"))
3797- expected = {}
3798- expected['something'] = content.Content(
3799- content_type.ContentType("text", "plain"),
3800- lambda:[_b("serialised\nform")])
3801- found = parser.get_details()
3802- self.assertEqual(expected.keys(), found.keys())
3803- self.assertEqual(expected['something'].content_type,
3804- found['something'].content_type)
3805- self.assertEqual(_b('').join(expected['something'].iter_bytes()),
3806- _b('').join(found['something'].iter_bytes()))
3807
3808=== removed file 'python-for-subunit2junitxml/subunit/tests/test_progress_model.py'
3809--- python-for-subunit2junitxml/subunit/tests/test_progress_model.py 2013-05-27 13:46:13 +0000
3810+++ python-for-subunit2junitxml/subunit/tests/test_progress_model.py 1970-01-01 00:00:00 +0000
3811@@ -1,118 +0,0 @@
3812-#
3813-# subunit: extensions to Python unittest to get test results from subprocesses.
3814-# Copyright (C) 2009 Robert Collins <robertc@robertcollins.net>
3815-#
3816-# Licensed under either the Apache License, Version 2.0 or the BSD 3-clause
3817-# license at the users choice. A copy of both licenses are available in the
3818-# project source as Apache-2.0 and BSD. You may not use this file except in
3819-# compliance with one of these two licences.
3820-#
3821-# Unless required by applicable law or agreed to in writing, software
3822-# distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT
3823-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
3824-# license you chose for the specific language governing permissions and
3825-# limitations under that license.
3826-#
3827-
3828-import unittest
3829-
3830-import subunit
3831-from subunit.progress_model import ProgressModel
3832-
3833-
3834-class TestProgressModel(unittest.TestCase):
3835-
3836- def assertProgressSummary(self, pos, total, progress):
3837- """Assert that a progress model has reached a particular point."""
3838- self.assertEqual(pos, progress.pos())
3839- self.assertEqual(total, progress.width())
3840-
3841- def test_new_progress_0_0(self):
3842- progress = ProgressModel()
3843- self.assertProgressSummary(0, 0, progress)
3844-
3845- def test_advance_0_0(self):
3846- progress = ProgressModel()
3847- progress.advance()
3848- self.assertProgressSummary(1, 0, progress)
3849-
3850- def test_advance_1_0(self):
3851- progress = ProgressModel()
3852- progress.advance()
3853- self.assertProgressSummary(1, 0, progress)
3854-
3855- def test_set_width_absolute(self):
3856- progress = ProgressModel()
3857- progress.set_width(10)
3858- self.assertProgressSummary(0, 10, progress)
3859-
3860- def test_set_width_absolute_preserves_pos(self):
3861- progress = ProgressModel()
3862- progress.advance()
3863- progress.set_width(2)
3864- self.assertProgressSummary(1, 2, progress)
3865-
3866- def test_adjust_width(self):
3867- progress = ProgressModel()
3868- progress.adjust_width(10)
3869- self.assertProgressSummary(0, 10, progress)
3870- progress.adjust_width(-10)
3871- self.assertProgressSummary(0, 0, progress)
3872-
3873- def test_adjust_width_preserves_pos(self):
3874- progress = ProgressModel()
3875- progress.advance()
3876- progress.adjust_width(10)
3877- self.assertProgressSummary(1, 10, progress)
3878- progress.adjust_width(-10)
3879- self.assertProgressSummary(1, 0, progress)
3880-
3881- def test_push_preserves_progress(self):
3882- progress = ProgressModel()
3883- progress.adjust_width(3)
3884- progress.advance()
3885- progress.push()
3886- self.assertProgressSummary(1, 3, progress)
3887-
3888- def test_advance_advances_substack(self):
3889- progress = ProgressModel()
3890- progress.adjust_width(3)
3891- progress.advance()
3892- progress.push()
3893- progress.adjust_width(1)
3894- progress.advance()
3895- self.assertProgressSummary(2, 3, progress)
3896-
3897- def test_adjust_width_adjusts_substack(self):
3898- progress = ProgressModel()
3899- progress.adjust_width(3)
3900- progress.advance()
3901- progress.push()
3902- progress.adjust_width(2)
3903- progress.advance()
3904- self.assertProgressSummary(3, 6, progress)
3905-
3906- def test_set_width_adjusts_substack(self):
3907- progress = ProgressModel()
3908- progress.adjust_width(3)
3909- progress.advance()
3910- progress.push()
3911- progress.set_width(2)
3912- progress.advance()
3913- self.assertProgressSummary(3, 6, progress)
3914-
3915- def test_pop_restores_progress(self):
3916- progress = ProgressModel()
3917- progress.adjust_width(3)
3918- progress.advance()
3919- progress.push()
3920- progress.adjust_width(1)
3921- progress.advance()
3922- progress.pop()
3923- self.assertProgressSummary(1, 3, progress)
3924-
3925-
3926-def test_suite():
3927- loader = subunit.tests.TestUtil.TestLoader()
3928- result = loader.loadTestsFromName(__name__)
3929- return result
3930
3931=== removed file 'python-for-subunit2junitxml/subunit/tests/test_subunit_filter.py'
3932--- python-for-subunit2junitxml/subunit/tests/test_subunit_filter.py 2013-05-27 13:46:13 +0000
3933+++ python-for-subunit2junitxml/subunit/tests/test_subunit_filter.py 1970-01-01 00:00:00 +0000
3934@@ -1,208 +0,0 @@
3935-#
3936-# subunit: extensions to python unittest to get test results from subprocesses.
3937-# Copyright (C) 2005 Robert Collins <robertc@robertcollins.net>
3938-#
3939-# Licensed under either the Apache License, Version 2.0 or the BSD 3-clause
3940-# license at the users choice. A copy of both licenses are available in the
3941-# project source as Apache-2.0 and BSD. You may not use this file except in
3942-# compliance with one of these two licences.
3943-#
3944-# Unless required by applicable law or agreed to in writing, software
3945-# distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT
3946-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
3947-# license you chose for the specific language governing permissions and
3948-# limitations under that license.
3949-#
3950-
3951-"""Tests for subunit.TestResultFilter."""
3952-
3953-from datetime import datetime
3954-from subunit import iso8601
3955-import unittest
3956-
3957-from testtools import TestCase
3958-from testtools.compat import _b, BytesIO, StringIO
3959-from testtools.testresult.doubles import ExtendedTestResult
3960-
3961-import subunit
3962-from subunit.test_results import TestResultFilter
3963-
3964-
3965-class TestTestResultFilter(TestCase):
3966- """Test for TestResultFilter, a TestResult object which filters tests."""
3967-
3968- # While TestResultFilter works on python objects, using a subunit stream
3969- # is an easy pithy way of getting a series of test objects to call into
3970- # the TestResult, and as TestResultFilter is intended for use with subunit
3971- # also has the benefit of detecting any interface skew issues.
3972- example_subunit_stream = _b("""\
3973-tags: global
3974-test passed
3975-success passed
3976-test failed
3977-tags: local
3978-failure failed
3979-test error
3980-error error [
3981-error details
3982-]
3983-test skipped
3984-skip skipped
3985-test todo
3986-xfail todo
3987-""")
3988-
3989- def run_tests(self, result_filter, input_stream=None):
3990- """Run tests through the given filter.
3991-
3992- :param result_filter: A filtering TestResult object.
3993- :param input_stream: Bytes of subunit stream data. If not provided,
3994- uses TestTestResultFilter.example_subunit_stream.
3995- """
3996- if input_stream is None:
3997- input_stream = self.example_subunit_stream
3998- test = subunit.ProtocolTestCase(BytesIO(input_stream))
3999- test.run(result_filter)
4000-
4001- def test_default(self):
4002- """The default is to exclude success and include everything else."""
4003- filtered_result = unittest.TestResult()
4004- result_filter = TestResultFilter(filtered_result)
4005- self.run_tests(result_filter)
4006- # skips are seen as success by default python TestResult.
4007- self.assertEqual(['error'],
4008- [error[0].id() for error in filtered_result.errors])
4009- self.assertEqual(['failed'],
4010- [failure[0].id() for failure in
4011- filtered_result.failures])
4012- self.assertEqual(4, filtered_result.testsRun)
4013-
4014- def test_exclude_errors(self):
4015- filtered_result = unittest.TestResult()
4016- result_filter = TestResultFilter(filtered_result, filter_error=True)
4017- self.run_tests(result_filter)
4018- # skips are seen as errors by default python TestResult.
4019- self.assertEqual([], filtered_result.errors)
4020- self.assertEqual(['failed'],
4021- [failure[0].id() for failure in
4022- filtered_result.failures])
4023- self.assertEqual(3, filtered_result.testsRun)
4024-
4025- def test_fixup_expected_failures(self):
4026- filtered_result = unittest.TestResult()
4027- result_filter = TestResultFilter(filtered_result,
4028- fixup_expected_failures=set(["failed"]))
4029- self.run_tests(result_filter)
4030- self.assertEqual(['failed', 'todo'],
4031- [failure[0].id() for failure in filtered_result.expectedFailures])
4032- self.assertEqual([], filtered_result.failures)
4033- self.assertEqual(4, filtered_result.testsRun)
4034-
4035- def test_fixup_expected_errors(self):
4036- filtered_result = unittest.TestResult()
4037- result_filter = TestResultFilter(filtered_result,
4038- fixup_expected_failures=set(["error"]))
4039- self.run_tests(result_filter)
4040- self.assertEqual(['error', 'todo'],
4041- [failure[0].id() for failure in filtered_result.expectedFailures])
4042- self.assertEqual([], filtered_result.errors)
4043- self.assertEqual(4, filtered_result.testsRun)
4044-
4045- def test_fixup_unexpected_success(self):
4046- filtered_result = unittest.TestResult()
4047- result_filter = TestResultFilter(filtered_result, filter_success=False,
4048- fixup_expected_failures=set(["passed"]))
4049- self.run_tests(result_filter)
4050- self.assertEqual(['passed'],
4051- [passed.id() for passed in filtered_result.unexpectedSuccesses])
4052- self.assertEqual(5, filtered_result.testsRun)
4053-
4054- def test_exclude_failure(self):
4055- filtered_result = unittest.TestResult()
4056- result_filter = TestResultFilter(filtered_result, filter_failure=True)
4057- self.run_tests(result_filter)
4058- self.assertEqual(['error'],
4059- [error[0].id() for error in filtered_result.errors])
4060- self.assertEqual([],
4061- [failure[0].id() for failure in
4062- filtered_result.failures])
4063- self.assertEqual(3, filtered_result.testsRun)
4064-
4065- def test_exclude_skips(self):
4066- filtered_result = subunit.TestResultStats(None)
4067- result_filter = TestResultFilter(filtered_result, filter_skip=True)
4068- self.run_tests(result_filter)
4069- self.assertEqual(0, filtered_result.skipped_tests)
4070- self.assertEqual(2, filtered_result.failed_tests)
4071- self.assertEqual(3, filtered_result.testsRun)
4072-
4073- def test_include_success(self):
4074- """Successes can be included if requested."""
4075- filtered_result = unittest.TestResult()
4076- result_filter = TestResultFilter(filtered_result,
4077- filter_success=False)
4078- self.run_tests(result_filter)
4079- self.assertEqual(['error'],
4080- [error[0].id() for error in filtered_result.errors])
4081- self.assertEqual(['failed'],
4082- [failure[0].id() for failure in
4083- filtered_result.failures])
4084- self.assertEqual(5, filtered_result.testsRun)
4085-
4086- def test_filter_predicate(self):
4087- """You can filter by predicate callbacks"""
4088- filtered_result = unittest.TestResult()
4089- def filter_cb(test, outcome, err, details):
4090- return outcome == 'success'
4091- result_filter = TestResultFilter(filtered_result,
4092- filter_predicate=filter_cb,
4093- filter_success=False)
4094- self.run_tests(result_filter)
4095- # Only success should pass
4096- self.assertEqual(1, filtered_result.testsRun)
4097-
4098- def test_time_ordering_preserved(self):
4099- # Passing a subunit stream through TestResultFilter preserves the
4100- # relative ordering of 'time' directives and any other subunit
4101- # directives that are still included.
4102- date_a = datetime(year=2000, month=1, day=1, tzinfo=iso8601.UTC)
4103- date_b = datetime(year=2000, month=1, day=2, tzinfo=iso8601.UTC)
4104- date_c = datetime(year=2000, month=1, day=3, tzinfo=iso8601.UTC)
4105- subunit_stream = _b('\n'.join([
4106- "time: %s",
4107- "test: foo",
4108- "time: %s",
4109- "error: foo",
4110- "time: %s",
4111- ""]) % (date_a, date_b, date_c))
4112- result = ExtendedTestResult()
4113- result_filter = TestResultFilter(result)
4114- self.run_tests(result_filter, subunit_stream)
4115- foo = subunit.RemotedTestCase('foo')
4116- self.assertEquals(
4117- [('time', date_a),
4118- ('startTest', foo),
4119- ('time', date_b),
4120- ('addError', foo, {}),
4121- ('stopTest', foo),
4122- ('time', date_c)], result._events)
4123-
4124- def test_skip_preserved(self):
4125- subunit_stream = _b('\n'.join([
4126- "test: foo",
4127- "skip: foo",
4128- ""]))
4129- result = ExtendedTestResult()
4130- result_filter = TestResultFilter(result)
4131- self.run_tests(result_filter, subunit_stream)
4132- foo = subunit.RemotedTestCase('foo')
4133- self.assertEquals(
4134- [('startTest', foo),
4135- ('addSkip', foo, {}),
4136- ('stopTest', foo), ], result._events)
4137-
4138-
4139-def test_suite():
4140- loader = subunit.tests.TestUtil.TestLoader()
4141- result = loader.loadTestsFromName(__name__)
4142- return result
4143
4144=== removed file 'python-for-subunit2junitxml/subunit/tests/test_subunit_stats.py'
4145--- python-for-subunit2junitxml/subunit/tests/test_subunit_stats.py 2013-05-27 13:46:13 +0000
4146+++ python-for-subunit2junitxml/subunit/tests/test_subunit_stats.py 1970-01-01 00:00:00 +0000
4147@@ -1,84 +0,0 @@
4148-#
4149-# subunit: extensions to python unittest to get test results from subprocesses.
4150-# Copyright (C) 2005 Robert Collins <robertc@robertcollins.net>
4151-#
4152-# Licensed under either the Apache License, Version 2.0 or the BSD 3-clause
4153-# license at the users choice. A copy of both licenses are available in the
4154-# project source as Apache-2.0 and BSD. You may not use this file except in
4155-# compliance with one of these two licences.
4156-#
4157-# Unless required by applicable law or agreed to in writing, software
4158-# distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT
4159-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
4160-# license you chose for the specific language governing permissions and
4161-# limitations under that license.
4162-#
4163-
4164-"""Tests for subunit.TestResultStats."""
4165-
4166-import unittest
4167-
4168-from testtools.compat import _b, BytesIO, StringIO
4169-
4170-import subunit
4171-
4172-
4173-class TestTestResultStats(unittest.TestCase):
4174- """Test for TestResultStats, a TestResult object that generates stats."""
4175-
4176- def setUp(self):
4177- self.output = StringIO()
4178- self.result = subunit.TestResultStats(self.output)
4179- self.input_stream = BytesIO()
4180- self.test = subunit.ProtocolTestCase(self.input_stream)
4181-
4182- def test_stats_empty(self):
4183- self.test.run(self.result)
4184- self.assertEqual(0, self.result.total_tests)
4185- self.assertEqual(0, self.result.passed_tests)
4186- self.assertEqual(0, self.result.failed_tests)
4187- self.assertEqual(set(), self.result.seen_tags)
4188-
4189- def setUpUsedStream(self):
4190- self.input_stream.write(_b("""tags: global
4191-test passed
4192-success passed
4193-test failed
4194-tags: local
4195-failure failed
4196-test error
4197-error error
4198-test skipped
4199-skip skipped
4200-test todo
4201-xfail todo
4202-"""))
4203- self.input_stream.seek(0)
4204- self.test.run(self.result)
4205-
4206- def test_stats_smoke_everything(self):
4207- # Statistics are calculated usefully.
4208- self.setUpUsedStream()
4209- self.assertEqual(5, self.result.total_tests)
4210- self.assertEqual(2, self.result.passed_tests)
4211- self.assertEqual(2, self.result.failed_tests)
4212- self.assertEqual(1, self.result.skipped_tests)
4213- self.assertEqual(set(["global", "local"]), self.result.seen_tags)
4214-
4215- def test_stat_formatting(self):
4216- expected = ("""
4217-Total tests: 5
4218-Passed tests: 2
4219-Failed tests: 2
4220-Skipped tests: 1
4221-Seen tags: global, local
4222-""")[1:]
4223- self.setUpUsedStream()
4224- self.result.formatStats()
4225- self.assertEqual(expected, self.output.getvalue())
4226-
4227-
4228-def test_suite():
4229- loader = subunit.tests.TestUtil.TestLoader()
4230- result = loader.loadTestsFromName(__name__)
4231- return result
4232
4233=== removed file 'python-for-subunit2junitxml/subunit/tests/test_subunit_tags.py'
4234--- python-for-subunit2junitxml/subunit/tests/test_subunit_tags.py 2013-05-27 13:46:13 +0000
4235+++ python-for-subunit2junitxml/subunit/tests/test_subunit_tags.py 1970-01-01 00:00:00 +0000
4236@@ -1,69 +0,0 @@
4237-#
4238-# subunit: extensions to python unittest to get test results from subprocesses.
4239-# Copyright (C) 2005 Robert Collins <robertc@robertcollins.net>
4240-#
4241-# Licensed under either the Apache License, Version 2.0 or the BSD 3-clause
4242-# license at the users choice. A copy of both licenses are available in the
4243-# project source as Apache-2.0 and BSD. You may not use this file except in
4244-# compliance with one of these two licences.
4245-#
4246-# Unless required by applicable law or agreed to in writing, software
4247-# distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT
4248-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
4249-# license you chose for the specific language governing permissions and
4250-# limitations under that license.
4251-#
4252-
4253-"""Tests for subunit.tag_stream."""
4254-
4255-import unittest
4256-
4257-from testtools.compat import StringIO
4258-
4259-import subunit
4260-import subunit.test_results
4261-
4262-
4263-class TestSubUnitTags(unittest.TestCase):
4264-
4265- def setUp(self):
4266- self.original = StringIO()
4267- self.filtered = StringIO()
4268-
4269- def test_add_tag(self):
4270- self.original.write("tags: foo\n")
4271- self.original.write("test: test\n")
4272- self.original.write("tags: bar -quux\n")
4273- self.original.write("success: test\n")
4274- self.original.seek(0)
4275- result = subunit.tag_stream(self.original, self.filtered, ["quux"])
4276- self.assertEqual([
4277- "tags: quux",
4278- "tags: foo",
4279- "test: test",
4280- "tags: bar",
4281- "success: test",
4282- ],
4283- self.filtered.getvalue().splitlines())
4284-
4285- def test_remove_tag(self):
4286- self.original.write("tags: foo\n")
4287- self.original.write("test: test\n")
4288- self.original.write("tags: bar -quux\n")
4289- self.original.write("success: test\n")
4290- self.original.seek(0)
4291- result = subunit.tag_stream(self.original, self.filtered, ["-bar"])
4292- self.assertEqual([
4293- "tags: -bar",
4294- "tags: foo",
4295- "test: test",
4296- "tags: -quux",
4297- "success: test",
4298- ],
4299- self.filtered.getvalue().splitlines())
4300-
4301-
4302-def test_suite():
4303- loader = subunit.tests.TestUtil.TestLoader()
4304- result = loader.loadTestsFromName(__name__)
4305- return result
4306
4307=== removed file 'python-for-subunit2junitxml/subunit/tests/test_tap2subunit.py'
4308--- python-for-subunit2junitxml/subunit/tests/test_tap2subunit.py 2013-05-27 13:46:13 +0000
4309+++ python-for-subunit2junitxml/subunit/tests/test_tap2subunit.py 1970-01-01 00:00:00 +0000
4310@@ -1,445 +0,0 @@
4311-#
4312-# subunit: extensions to python unittest to get test results from subprocesses.
4313-# Copyright (C) 2005 Robert Collins <robertc@robertcollins.net>
4314-#
4315-# Licensed under either the Apache License, Version 2.0 or the BSD 3-clause
4316-# license at the users choice. A copy of both licenses are available in the
4317-# project source as Apache-2.0 and BSD. You may not use this file except in
4318-# compliance with one of these two licences.
4319-#
4320-# Unless required by applicable law or agreed to in writing, software
4321-# distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT
4322-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
4323-# license you chose for the specific language governing permissions and
4324-# limitations under that license.
4325-#
4326-
4327-"""Tests for TAP2SubUnit."""
4328-
4329-import unittest
4330-
4331-from testtools.compat import StringIO
4332-
4333-import subunit
4334-
4335-
4336-class TestTAP2SubUnit(unittest.TestCase):
4337- """Tests for TAP2SubUnit.
4338-
4339- These tests test TAP string data in, and subunit string data out.
4340- This is ok because the subunit protocol is intended to be stable,
4341- but it might be easier/pithier to write tests against TAP string in,
4342- parsed subunit objects out (by hooking the subunit stream to a subunit
4343- protocol server.
4344- """
4345-
4346- def setUp(self):
4347- self.tap = StringIO()
4348- self.subunit = StringIO()
4349-
4350- def test_skip_entire_file(self):
4351- # A file
4352- # 1..- # Skipped: comment
4353- # results in a single skipped test.
4354- self.tap.write("1..0 # Skipped: entire file skipped\n")
4355- self.tap.seek(0)
4356- result = subunit.TAP2SubUnit(self.tap, self.subunit)
4357- self.assertEqual(0, result)
4358- self.assertEqual([
4359- "test file skip",
4360- "skip file skip [",
4361- "Skipped: entire file skipped",
4362- "]",
4363- ],
4364- self.subunit.getvalue().splitlines())
4365-
4366- def test_ok_test_pass(self):
4367- # A file
4368- # ok
4369- # results in a passed test with name 'test 1' (a synthetic name as tap
4370- # does not require named fixtures - it is the first test in the tap
4371- # stream).
4372- self.tap.write("ok\n")
4373- self.tap.seek(0)
4374- result = subunit.TAP2SubUnit(self.tap, self.subunit)
4375- self.assertEqual(0, result)
4376- self.assertEqual([
4377- "test test 1",
4378- "success test 1",
4379- ],
4380- self.subunit.getvalue().splitlines())
4381-
4382- def test_ok_test_number_pass(self):
4383- # A file
4384- # ok 1
4385- # results in a passed test with name 'test 1'
4386- self.tap.write("ok 1\n")
4387- self.tap.seek(0)
4388- result = subunit.TAP2SubUnit(self.tap, self.subunit)
4389- self.assertEqual(0, result)
4390- self.assertEqual([
4391- "test test 1",
4392- "success test 1",
4393- ],
4394- self.subunit.getvalue().splitlines())
4395-
4396- def test_ok_test_number_description_pass(self):
4397- # A file
4398- # ok 1 - There is a description
4399- # results in a passed test with name 'test 1 - There is a description'
4400- self.tap.write("ok 1 - There is a description\n")
4401- self.tap.seek(0)
4402- result = subunit.TAP2SubUnit(self.tap, self.subunit)
4403- self.assertEqual(0, result)
4404- self.assertEqual([
4405- "test test 1 - There is a description",
4406- "success test 1 - There is a description",
4407- ],
4408- self.subunit.getvalue().splitlines())
4409-
4410- def test_ok_test_description_pass(self):
4411- # A file
4412- # ok There is a description
4413- # results in a passed test with name 'test 1 There is a description'
4414- self.tap.write("ok There is a description\n")
4415- self.tap.seek(0)
4416- result = subunit.TAP2SubUnit(self.tap, self.subunit)
4417- self.assertEqual(0, result)
4418- self.assertEqual([
4419- "test test 1 There is a description",
4420- "success test 1 There is a description",
4421- ],
4422- self.subunit.getvalue().splitlines())
4423-
4424- def test_ok_SKIP_skip(self):
4425- # A file
4426- # ok # SKIP
4427- # results in a skkip test with name 'test 1'
4428- self.tap.write("ok # SKIP\n")
4429- self.tap.seek(0)
4430- result = subunit.TAP2SubUnit(self.tap, self.subunit)
4431- self.assertEqual(0, result)
4432- self.assertEqual([
4433- "test test 1",
4434- "skip test 1",
4435- ],
4436- self.subunit.getvalue().splitlines())
4437-
4438- def test_ok_skip_number_comment_lowercase(self):
4439- self.tap.write("ok 1 # skip no samba environment available, skipping compilation\n")
4440- self.tap.seek(0)
4441- result = subunit.TAP2SubUnit(self.tap, self.subunit)
4442- self.assertEqual(0, result)
4443- self.assertEqual([
4444- "test test 1",
4445- "skip test 1 [",
4446- "no samba environment available, skipping compilation",
4447- "]"
4448- ],
4449- self.subunit.getvalue().splitlines())
4450-
4451- def test_ok_number_description_SKIP_skip_comment(self):
4452- # A file
4453- # ok 1 foo # SKIP Not done yet
4454- # results in a skip test with name 'test 1 foo' and a log of
4455- # Not done yet
4456- self.tap.write("ok 1 foo # SKIP Not done yet\n")
4457- self.tap.seek(0)
4458- result = subunit.TAP2SubUnit(self.tap, self.subunit)
4459- self.assertEqual(0, result)
4460- self.assertEqual([
4461- "test test 1 foo",
4462- "skip test 1 foo [",
4463- "Not done yet",
4464- "]",
4465- ],
4466- self.subunit.getvalue().splitlines())
4467-
4468- def test_ok_SKIP_skip_comment(self):
4469- # A file
4470- # ok # SKIP Not done yet
4471- # results in a skip test with name 'test 1' and a log of Not done yet
4472- self.tap.write("ok # SKIP Not done yet\n")
4473- self.tap.seek(0)
4474- result = subunit.TAP2SubUnit(self.tap, self.subunit)
4475- self.assertEqual(0, result)
4476- self.assertEqual([
4477- "test test 1",
4478- "skip test 1 [",
4479- "Not done yet",
4480- "]",
4481- ],
4482- self.subunit.getvalue().splitlines())
4483-
4484- def test_ok_TODO_xfail(self):
4485- # A file
4486- # ok # TODO
4487- # results in a xfail test with name 'test 1'
4488- self.tap.write("ok # TODO\n")
4489- self.tap.seek(0)
4490- result = subunit.TAP2SubUnit(self.tap, self.subunit)
4491- self.assertEqual(0, result)
4492- self.assertEqual([
4493- "test test 1",
4494- "xfail test 1",
4495- ],
4496- self.subunit.getvalue().splitlines())
4497-
4498- def test_ok_TODO_xfail_comment(self):
4499- # A file
4500- # ok # TODO Not done yet
4501- # results in a xfail test with name 'test 1' and a log of Not done yet
4502- self.tap.write("ok # TODO Not done yet\n")
4503- self.tap.seek(0)
4504- result = subunit.TAP2SubUnit(self.tap, self.subunit)
4505- self.assertEqual(0, result)
4506- self.assertEqual([
4507- "test test 1",
4508- "xfail test 1 [",
4509- "Not done yet",
4510- "]",
4511- ],
4512- self.subunit.getvalue().splitlines())
4513-
4514- def test_bail_out_errors(self):
4515- # A file with line in it
4516- # Bail out! COMMENT
4517- # is treated as an error
4518- self.tap.write("ok 1 foo\n")
4519- self.tap.write("Bail out! Lifejacket engaged\n")
4520- self.tap.seek(0)
4521- result = subunit.TAP2SubUnit(self.tap, self.subunit)
4522- self.assertEqual(0, result)
4523- self.assertEqual([
4524- "test test 1 foo",
4525- "success test 1 foo",
4526- "test Bail out! Lifejacket engaged",
4527- "error Bail out! Lifejacket engaged",
4528- ],
4529- self.subunit.getvalue().splitlines())
4530-
4531- def test_missing_test_at_end_with_plan_adds_error(self):
4532- # A file
4533- # 1..3
4534- # ok first test
4535- # not ok third test
4536- # results in three tests, with the third being created
4537- self.tap.write('1..3\n')
4538- self.tap.write('ok first test\n')
4539- self.tap.write('not ok second test\n')
4540- self.tap.seek(0)
4541- result = subunit.TAP2SubUnit(self.tap, self.subunit)
4542- self.assertEqual(0, result)
4543- self.assertEqual([
4544- 'test test 1 first test',
4545- 'success test 1 first test',
4546- 'test test 2 second test',
4547- 'failure test 2 second test',
4548- 'test test 3',
4549- 'error test 3 [',
4550- 'test missing from TAP output',
4551- ']',
4552- ],
4553- self.subunit.getvalue().splitlines())
4554-
4555- def test_missing_test_with_plan_adds_error(self):
4556- # A file
4557- # 1..3
4558- # ok first test
4559- # not ok 3 third test
4560- # results in three tests, with the second being created
4561- self.tap.write('1..3\n')
4562- self.tap.write('ok first test\n')
4563- self.tap.write('not ok 3 third test\n')
4564- self.tap.seek(0)
4565- result = subunit.TAP2SubUnit(self.tap, self.subunit)
4566- self.assertEqual(0, result)
4567- self.assertEqual([
4568- 'test test 1 first test',
4569- 'success test 1 first test',
4570- 'test test 2',
4571- 'error test 2 [',
4572- 'test missing from TAP output',
4573- ']',
4574- 'test test 3 third test',
4575- 'failure test 3 third test',
4576- ],
4577- self.subunit.getvalue().splitlines())
4578-
4579- def test_missing_test_no_plan_adds_error(self):
4580- # A file
4581- # ok first test
4582- # not ok 3 third test
4583- # results in three tests, with the second being created
4584- self.tap.write('ok first test\n')
4585- self.tap.write('not ok 3 third test\n')
4586- self.tap.seek(0)
4587- result = subunit.TAP2SubUnit(self.tap, self.subunit)
4588- self.assertEqual(0, result)
4589- self.assertEqual([
4590- 'test test 1 first test',
4591- 'success test 1 first test',
4592- 'test test 2',
4593- 'error test 2 [',
4594- 'test missing from TAP output',
4595- ']',
4596- 'test test 3 third test',
4597- 'failure test 3 third test',
4598- ],
4599- self.subunit.getvalue().splitlines())
4600-
4601- def test_four_tests_in_a_row_trailing_plan(self):
4602- # A file
4603- # ok 1 - first test in a script with no plan at all
4604- # not ok 2 - second
4605- # ok 3 - third
4606- # not ok 4 - fourth
4607- # 1..4
4608- # results in four tests numbered and named
4609- self.tap.write('ok 1 - first test in a script with trailing plan\n')
4610- self.tap.write('not ok 2 - second\n')
4611- self.tap.write('ok 3 - third\n')
4612- self.tap.write('not ok 4 - fourth\n')
4613- self.tap.write('1..4\n')
4614- self.tap.seek(0)
4615- result = subunit.TAP2SubUnit(self.tap, self.subunit)
4616- self.assertEqual(0, result)
4617- self.assertEqual([
4618- 'test test 1 - first test in a script with trailing plan',
4619- 'success test 1 - first test in a script with trailing plan',
4620- 'test test 2 - second',
4621- 'failure test 2 - second',
4622- 'test test 3 - third',
4623- 'success test 3 - third',
4624- 'test test 4 - fourth',
4625- 'failure test 4 - fourth'
4626- ],
4627- self.subunit.getvalue().splitlines())
4628-
4629- def test_four_tests_in_a_row_with_plan(self):
4630- # A file
4631- # 1..4
4632- # ok 1 - first test in a script with no plan at all
4633- # not ok 2 - second
4634- # ok 3 - third
4635- # not ok 4 - fourth
4636- # results in four tests numbered and named
4637- self.tap.write('1..4\n')
4638- self.tap.write('ok 1 - first test in a script with a plan\n')
4639- self.tap.write('not ok 2 - second\n')
4640- self.tap.write('ok 3 - third\n')
4641- self.tap.write('not ok 4 - fourth\n')
4642- self.tap.seek(0)
4643- result = subunit.TAP2SubUnit(self.tap, self.subunit)
4644- self.assertEqual(0, result)
4645- self.assertEqual([
4646- 'test test 1 - first test in a script with a plan',
4647- 'success test 1 - first test in a script with a plan',
4648- 'test test 2 - second',
4649- 'failure test 2 - second',
4650- 'test test 3 - third',
4651- 'success test 3 - third',
4652- 'test test 4 - fourth',
4653- 'failure test 4 - fourth'
4654- ],
4655- self.subunit.getvalue().splitlines())
4656-
4657- def test_four_tests_in_a_row_no_plan(self):
4658- # A file
4659- # ok 1 - first test in a script with no plan at all
4660- # not ok 2 - second
4661- # ok 3 - third
4662- # not ok 4 - fourth
4663- # results in four tests numbered and named
4664- self.tap.write('ok 1 - first test in a script with no plan at all\n')
4665- self.tap.write('not ok 2 - second\n')
4666- self.tap.write('ok 3 - third\n')
4667- self.tap.write('not ok 4 - fourth\n')
4668- self.tap.seek(0)
4669- result = subunit.TAP2SubUnit(self.tap, self.subunit)
4670- self.assertEqual(0, result)
4671- self.assertEqual([
4672- 'test test 1 - first test in a script with no plan at all',
4673- 'success test 1 - first test in a script with no plan at all',
4674- 'test test 2 - second',
4675- 'failure test 2 - second',
4676- 'test test 3 - third',
4677- 'success test 3 - third',
4678- 'test test 4 - fourth',
4679- 'failure test 4 - fourth'
4680- ],
4681- self.subunit.getvalue().splitlines())
4682-
4683- def test_todo_and_skip(self):
4684- # A file
4685- # not ok 1 - a fail but # TODO but is TODO
4686- # not ok 2 - another fail # SKIP instead
4687- # results in two tests, numbered and commented.
4688- self.tap.write("not ok 1 - a fail but # TODO but is TODO\n")
4689- self.tap.write("not ok 2 - another fail # SKIP instead\n")
4690- self.tap.seek(0)
4691- result = subunit.TAP2SubUnit(self.tap, self.subunit)
4692- self.assertEqual(0, result)
4693- self.assertEqual([
4694- 'test test 1 - a fail but',
4695- 'xfail test 1 - a fail but [',
4696- 'but is TODO',
4697- ']',
4698- 'test test 2 - another fail',
4699- 'skip test 2 - another fail [',
4700- 'instead',
4701- ']',
4702- ],
4703- self.subunit.getvalue().splitlines())
4704-
4705- def test_leading_comments_add_to_next_test_log(self):
4706- # A file
4707- # # comment
4708- # ok
4709- # ok
4710- # results in a single test with the comment included
4711- # in the first test and not the second.
4712- self.tap.write("# comment\n")
4713- self.tap.write("ok\n")
4714- self.tap.write("ok\n")
4715- self.tap.seek(0)
4716- result = subunit.TAP2SubUnit(self.tap, self.subunit)
4717- self.assertEqual(0, result)
4718- self.assertEqual([
4719- 'test test 1',
4720- 'success test 1 [',
4721- '# comment',
4722- ']',
4723- 'test test 2',
4724- 'success test 2',
4725- ],
4726- self.subunit.getvalue().splitlines())
4727-
4728- def test_trailing_comments_are_included_in_last_test_log(self):
4729- # A file
4730- # ok foo
4731- # ok foo
4732- # # comment
4733- # results in a two tests, with the second having the comment
4734- # attached to its log.
4735- self.tap.write("ok\n")
4736- self.tap.write("ok\n")
4737- self.tap.write("# comment\n")
4738- self.tap.seek(0)
4739- result = subunit.TAP2SubUnit(self.tap, self.subunit)
4740- self.assertEqual(0, result)
4741- self.assertEqual([
4742- 'test test 1',
4743- 'success test 1',
4744- 'test test 2',
4745- 'success test 2 [',
4746- '# comment',
4747- ']',
4748- ],
4749- self.subunit.getvalue().splitlines())
4750-
4751-
4752-def test_suite():
4753- loader = subunit.tests.TestUtil.TestLoader()
4754- result = loader.loadTestsFromName(__name__)
4755- return result
4756
4757=== removed file 'python-for-subunit2junitxml/subunit/tests/test_test_protocol.py'
4758--- python-for-subunit2junitxml/subunit/tests/test_test_protocol.py 2013-05-27 13:46:13 +0000
4759+++ python-for-subunit2junitxml/subunit/tests/test_test_protocol.py 1970-01-01 00:00:00 +0000
4760@@ -1,1299 +0,0 @@
4761-#
4762-# subunit: extensions to Python unittest to get test results from subprocesses.
4763-# Copyright (C) 2005 Robert Collins <robertc@robertcollins.net>
4764-#
4765-# Licensed under either the Apache License, Version 2.0 or the BSD 3-clause
4766-# license at the users choice. A copy of both licenses are available in the
4767-# project source as Apache-2.0 and BSD. You may not use this file except in
4768-# compliance with one of these two licences.
4769-#
4770-# Unless required by applicable law or agreed to in writing, software
4771-# distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT
4772-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
4773-# license you chose for the specific language governing permissions and
4774-# limitations under that license.
4775-#
4776-
4777-import datetime
4778-import unittest
4779-import os
4780-
4781-from testtools import skipIf, TestCase
4782-from testtools.compat import _b, _u, BytesIO, StringIO
4783-from testtools.content import Content, TracebackContent
4784-from testtools.content_type import ContentType
4785-from testtools.tests.helpers import (
4786- Python26TestResult,
4787- Python27TestResult,
4788- ExtendedTestResult,
4789- )
4790-
4791-import subunit
4792-from subunit import _remote_exception_str, _remote_exception_str_chunked
4793-import subunit.iso8601 as iso8601
4794-
4795-
4796-class TestTestImports(unittest.TestCase):
4797-
4798- def test_imports(self):
4799- from subunit import DiscardStream
4800- from subunit import TestProtocolServer
4801- from subunit import RemotedTestCase
4802- from subunit import RemoteError
4803- from subunit import ExecTestCase
4804- from subunit import IsolatedTestCase
4805- from subunit import TestProtocolClient
4806- from subunit import ProtocolTestCase
4807-
4808-
4809-class TestDiscardStream(unittest.TestCase):
4810-
4811- def test_write(self):
4812- subunit.DiscardStream().write("content")
4813-
4814-
4815-class TestProtocolServerForward(unittest.TestCase):
4816-
4817- def test_story(self):
4818- client = unittest.TestResult()
4819- out = BytesIO()
4820- protocol = subunit.TestProtocolServer(client, forward_stream=out)
4821- pipe = BytesIO(_b("test old mcdonald\n"
4822- "success old mcdonald\n"))
4823- protocol.readFrom(pipe)
4824- self.assertEqual(client.testsRun, 1)
4825- self.assertEqual(pipe.getvalue(), out.getvalue())
4826-
4827- def test_not_command(self):
4828- client = unittest.TestResult()
4829- out = BytesIO()
4830- protocol = subunit.TestProtocolServer(client,
4831- stream=subunit.DiscardStream(), forward_stream=out)
4832- pipe = BytesIO(_b("success old mcdonald\n"))
4833- protocol.readFrom(pipe)
4834- self.assertEqual(client.testsRun, 0)
4835- self.assertEqual(_b(""), out.getvalue())
4836-
4837-
4838-class TestTestProtocolServerPipe(unittest.TestCase):
4839-
4840- def test_story(self):
4841- client = unittest.TestResult()
4842- protocol = subunit.TestProtocolServer(client)
4843- pipe = BytesIO(_b("test old mcdonald\n"
4844- "success old mcdonald\n"
4845- "test bing crosby\n"
4846- "failure bing crosby [\n"
4847- "foo.c:53:ERROR invalid state\n"
4848- "]\n"
4849- "test an error\n"
4850- "error an error\n"))
4851- protocol.readFrom(pipe)
4852- bing = subunit.RemotedTestCase("bing crosby")
4853- an_error = subunit.RemotedTestCase("an error")
4854- self.assertEqual(client.errors,
4855- [(an_error, _remote_exception_str + '\n')])
4856- self.assertEqual(
4857- client.failures,
4858- [(bing, _remote_exception_str + ": Text attachment: traceback\n"
4859- "------------\nfoo.c:53:ERROR invalid state\n"
4860- "------------\n\n")])
4861- self.assertEqual(client.testsRun, 3)
4862-
4863- def test_non_test_characters_forwarded_immediately(self):
4864- pass
4865-
4866-
4867-class TestTestProtocolServerStartTest(unittest.TestCase):
4868-
4869- def setUp(self):
4870- self.client = Python26TestResult()
4871- self.stream = BytesIO()
4872- self.protocol = subunit.TestProtocolServer(self.client, self.stream)
4873-
4874- def test_start_test(self):
4875- self.protocol.lineReceived(_b("test old mcdonald\n"))
4876- self.assertEqual(self.client._events,
4877- [('startTest', subunit.RemotedTestCase("old mcdonald"))])
4878-
4879- def test_start_testing(self):
4880- self.protocol.lineReceived(_b("testing old mcdonald\n"))
4881- self.assertEqual(self.client._events,
4882- [('startTest', subunit.RemotedTestCase("old mcdonald"))])
4883-
4884- def test_start_test_colon(self):
4885- self.protocol.lineReceived(_b("test: old mcdonald\n"))
4886- self.assertEqual(self.client._events,
4887- [('startTest', subunit.RemotedTestCase("old mcdonald"))])
4888-
4889- def test_indented_test_colon_ignored(self):
4890- ignored_line = _b(" test: old mcdonald\n")
4891- self.protocol.lineReceived(ignored_line)
4892- self.assertEqual([], self.client._events)
4893- self.assertEqual(self.stream.getvalue(), ignored_line)
4894-
4895- def test_start_testing_colon(self):
4896- self.protocol.lineReceived(_b("testing: old mcdonald\n"))
4897- self.assertEqual(self.client._events,
4898- [('startTest', subunit.RemotedTestCase("old mcdonald"))])
4899-
4900-
4901-class TestTestProtocolServerPassThrough(unittest.TestCase):
4902-
4903- def setUp(self):
4904- self.stdout = BytesIO()
4905- self.test = subunit.RemotedTestCase("old mcdonald")
4906- self.client = ExtendedTestResult()
4907- self.protocol = subunit.TestProtocolServer(self.client, self.stdout)
4908-
4909- def keywords_before_test(self):
4910- self.protocol.lineReceived(_b("failure a\n"))
4911- self.protocol.lineReceived(_b("failure: a\n"))
4912- self.protocol.lineReceived(_b("error a\n"))
4913- self.protocol.lineReceived(_b("error: a\n"))
4914- self.protocol.lineReceived(_b("success a\n"))
4915- self.protocol.lineReceived(_b("success: a\n"))
4916- self.protocol.lineReceived(_b("successful a\n"))
4917- self.protocol.lineReceived(_b("successful: a\n"))
4918- self.protocol.lineReceived(_b("]\n"))
4919- self.assertEqual(self.stdout.getvalue(), _b("failure a\n"
4920- "failure: a\n"
4921- "error a\n"
4922- "error: a\n"
4923- "success a\n"
4924- "success: a\n"
4925- "successful a\n"
4926- "successful: a\n"
4927- "]\n"))
4928-
4929- def test_keywords_before_test(self):
4930- self.keywords_before_test()
4931- self.assertEqual(self.client._events, [])
4932-
4933- def test_keywords_after_error(self):
4934- self.protocol.lineReceived(_b("test old mcdonald\n"))
4935- self.protocol.lineReceived(_b("error old mcdonald\n"))
4936- self.keywords_before_test()
4937- self.assertEqual([
4938- ('startTest', self.test),
4939- ('addError', self.test, {}),
4940- ('stopTest', self.test),
4941- ], self.client._events)
4942-
4943- def test_keywords_after_failure(self):
4944- self.protocol.lineReceived(_b("test old mcdonald\n"))
4945- self.protocol.lineReceived(_b("failure old mcdonald\n"))
4946- self.keywords_before_test()
4947- self.assertEqual(self.client._events, [
4948- ('startTest', self.test),
4949- ('addFailure', self.test, {}),
4950- ('stopTest', self.test),
4951- ])
4952-
4953- def test_keywords_after_success(self):
4954- self.protocol.lineReceived(_b("test old mcdonald\n"))
4955- self.protocol.lineReceived(_b("success old mcdonald\n"))
4956- self.keywords_before_test()
4957- self.assertEqual([
4958- ('startTest', self.test),
4959- ('addSuccess', self.test),
4960- ('stopTest', self.test),
4961- ], self.client._events)
4962-
4963- def test_keywords_after_test(self):
4964- self.protocol.lineReceived(_b("test old mcdonald\n"))
4965- self.protocol.lineReceived(_b("test old mcdonald\n"))
4966- self.protocol.lineReceived(_b("failure a\n"))
4967- self.protocol.lineReceived(_b("failure: a\n"))
4968- self.protocol.lineReceived(_b("error a\n"))
4969- self.protocol.lineReceived(_b("error: a\n"))
4970- self.protocol.lineReceived(_b("success a\n"))
4971- self.protocol.lineReceived(_b("success: a\n"))
4972- self.protocol.lineReceived(_b("successful a\n"))
4973- self.protocol.lineReceived(_b("successful: a\n"))
4974- self.protocol.lineReceived(_b("]\n"))
4975- self.protocol.lineReceived(_b("failure old mcdonald\n"))
4976- self.assertEqual(self.stdout.getvalue(), _b("test old mcdonald\n"
4977- "failure a\n"
4978- "failure: a\n"
4979- "error a\n"
4980- "error: a\n"
4981- "success a\n"
4982- "success: a\n"
4983- "successful a\n"
4984- "successful: a\n"
4985- "]\n"))
4986- self.assertEqual(self.client._events, [
4987- ('startTest', self.test),
4988- ('addFailure', self.test, {}),
4989- ('stopTest', self.test),
4990- ])
4991-
4992- def test_keywords_during_failure(self):
4993- # A smoke test to make sure that the details parsers have control
4994- # appropriately.
4995- self.protocol.lineReceived(_b("test old mcdonald\n"))
4996- self.protocol.lineReceived(_b("failure: old mcdonald [\n"))
4997- self.protocol.lineReceived(_b("test old mcdonald\n"))
4998- self.protocol.lineReceived(_b("failure a\n"))
4999- self.protocol.lineReceived(_b("failure: a\n"))
5000- self.protocol.lineReceived(_b("error a\n"))
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches