Merge lp:~lifeless/subunit/time-support into lp:~subunit/subunit/trunk

Proposed by Robert Collins
Status: Superseded
Proposed branch: lp:~lifeless/subunit/time-support
Merge into: lp:~subunit/subunit/trunk
Diff against target: None lines
To merge this branch: bzr merge lp:~lifeless/subunit/time-support
Reviewer Review Type Date Requested Status
Subunit Developers Pending
Review via email: mp+9042@code.launchpad.net

This proposal has been superseded by a proposal from 2009-07-22.

To post a comment you must log in.
Revision history for this message
Robert Collins (lifeless) wrote :

This teaches the python support to export time data to the TestResult.

lp:~lifeless/subunit/time-support updated
75. By Robert Collins

Add subunit.test_results.HookedTestResultDecorator.

76. By Robert Collins

Add TestProtocolClient.time().

77. By Robert Collins

Add AutoTimingTestResultDecorator.

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'Makefile.am'
--- Makefile.am 2009-06-12 01:45:53 +0000
+++ Makefile.am 2009-07-20 10:08:11 +0000
@@ -51,6 +51,7 @@
5151
52pkgpython_PYTHON = \52pkgpython_PYTHON = \
53 python/subunit/__init__.py \53 python/subunit/__init__.py \
54 python/subunit/iso8601.py \
54 python/subunit/run.py55 python/subunit/run.py
5556
56lib_LTLIBRARIES = libsubunit.la57lib_LTLIBRARIES = libsubunit.la
5758
=== modified file 'NEWS'
--- NEWS 2009-07-20 07:11:54 +0000
+++ NEWS 2009-07-20 08:13:55 +0000
@@ -14,6 +14,9 @@
1414
15 API CHANGES:15 API CHANGES:
1616
17 * When a time: directive is encountered in a subunit stream, the python
18 bindings now call the ``time(seconds)`` method on ``TestResult``.
19
17 INTERNALS:20 INTERNALS:
1821
19 * ExecTestCase supports passing arguments to test scripts.22 * ExecTestCase supports passing arguments to test scripts.
2023
=== modified file 'README'
--- README 2009-07-18 01:28:43 +0000
+++ README 2009-07-20 10:08:11 +0000
@@ -17,6 +17,10 @@
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1818
1919
20 subunit reuses iso8601 by Michael Twomey, distributed under an MIT style
21 licence - see python/iso8601/LICENSE for details.
22
23
20Subunit24Subunit
21-------25-------
2226
@@ -44,7 +48,7 @@
44 * tap2subunit - convert perl's TestAnythingProtocol to subunit.48 * tap2subunit - convert perl's TestAnythingProtocol to subunit.
45 * subunit2pyunit - convert a subunit stream to pyunit test results.49 * subunit2pyunit - convert a subunit stream to pyunit test results.
46 * subunit-filter - filter out tests from a subunit stream.50 * subunit-filter - filter out tests from a subunit stream.
47 * subunit-ls - list the tests present in a subunit stream.51 * subunit-ls - list info about tests present in a subunit stream.
48 * subunit-stats - generate a summary of a subunit stream.52 * subunit-stats - generate a summary of a subunit stream.
49 * subunit-tags - add or remove tags from a stream.53 * subunit-tags - add or remove tags from a stream.
5054
@@ -123,6 +127,12 @@
123 # needed and report to your result object.127 # needed and report to your result object.
124 suite.run(result)128 suite.run(result)
125129
130subunit includes extensions to the python ``TestResult`` protocol. The
131``time(a_datetime)`` method is called (if present) when a ``time:``
132directive is encountered in a subunit stream. This is used to tell a TestResult
133about the time that events in the stream occured at, to allow reconstructing
134test timing from a stream.
135
126Finally, subunit.run is a convenience wrapper to run a python test suite via136Finally, subunit.run is a convenience wrapper to run a python test suite via
127the command line, reporting via subunit::137the command line, reporting via subunit::
128138
@@ -215,8 +225,8 @@
215In Python, tags are assigned to the .tags attribute on the RemoteTest objects225In Python, tags are assigned to the .tags attribute on the RemoteTest objects
216created by the TestProtocolServer.226created by the TestProtocolServer.
217227
218The time element acts as a clock event - it sets the time for all future events.228The time element acts as a clock event - it sets the time for all future
219Currently this is not exposed at the python API layer.229events. The value should be a valid ISO8601 time.
220230
221The skip result is used to indicate a test that was found by the runner but not231The skip result is used to indicate a test that was found by the runner but not
222fully executed due to some policy or dependency issue. This is represented in232fully executed due to some policy or dependency issue. This is represented in
223233
=== modified file 'filters/subunit-ls'
--- filters/subunit-ls 2009-03-08 20:34:19 +0000
+++ filters/subunit-ls 2009-07-20 10:12:42 +0000
@@ -19,6 +19,7 @@
1919
20"""List tests in a subunit stream."""20"""List tests in a subunit stream."""
2121
22from optparse import OptionParser
22import sys23import sys
23import unittest24import unittest
2425
@@ -26,32 +27,60 @@
2627
27class TestIdPrintingResult(unittest.TestResult):28class TestIdPrintingResult(unittest.TestResult):
2829
29 def __init__(self, stream):30 def __init__(self, stream, show_times=False):
30 """Create a FilterResult object outputting to stream."""31 """Create a FilterResult object outputting to stream."""
31 unittest.TestResult.__init__(self)32 unittest.TestResult.__init__(self)
32 self._stream = stream33 self._stream = stream
33 self.failed_tests = 034 self.failed_tests = 0
35 self.__time = 0
36 self.show_times = show_times
37 self._test = None
38 self._test_duration = 0
34 39
35 def addError(self, test, err):40 def addError(self, test, err):
36 self.failed_tests += 141 self.failed_tests += 1
37 self.reportTest(test)42 self._test = test
3843
39 def addFailure(self, test, err):44 def addFailure(self, test, err):
40 self.failed_tests += 145 self.failed_tests += 1
41 self.reportTest(test)46 self._test = test
4247
43 def addSuccess(self, test):48 def addSuccess(self, test):
44 self.reportTest(test)49 self._test = test
4550
46 def reportTest(self, test):51 def reportTest(self, test, duration):
47 self._stream.write(test.id() + '\n')52 if self.show_times:
53 seconds = duration.seconds
54 seconds += duration.days * 3600 * 24
55 seconds += duration.microseconds / 1000000.0
56 self._stream.write(test.id() + ' %0.3f\n' % seconds)
57 else:
58 self._stream.write(test.id() + '\n')
59
60 def startTest(self, test):
61 self._start_time = self._time()
62
63 def stopTest(self, test):
64 test_duration = self._time() - self._start_time
65 self.reportTest(self._test, test_duration)
66
67 def time(self, time):
68 self.__time = time
69
70 def _time(self):
71 return self.__time
4872
49 def wasSuccessful(self):73 def wasSuccessful(self):
50 "Tells whether or not this result was a success"74 "Tells whether or not this result was a success"
51 return self.failed_tests == 075 return self.failed_tests == 0
5276
5377
54result = TestIdPrintingResult(sys.stdout)78parser = OptionParser(description=__doc__)
79parser.add_option("--times", action="store_true",
80 help="list the time each test took (requires a timestamped stream)",
81 default=False)
82(options, args) = parser.parse_args()
83result = TestIdPrintingResult(sys.stdout, options.times)
55test = ProtocolTestCase(sys.stdin)84test = ProtocolTestCase(sys.stdin)
56test.run(result)85test.run(result)
57if result.wasSuccessful():86if result.wasSuccessful():
5887
=== added directory 'python/iso8601'
=== added file 'python/iso8601/LICENSE'
--- python/iso8601/LICENSE 1970-01-01 00:00:00 +0000
+++ python/iso8601/LICENSE 2009-07-20 10:08:11 +0000
@@ -0,0 +1,20 @@
1Copyright (c) 2007 Michael Twomey
2
3Permission is hereby granted, free of charge, to any person obtaining a
4copy of this software and associated documentation files (the
5"Software"), to deal in the Software without restriction, including
6without limitation the rights to use, copy, modify, merge, publish,
7distribute, sublicense, and/or sell copies of the Software, and to
8permit persons to whom the Software is furnished to do so, subject to
9the following conditions:
10
11The above copyright notice and this permission notice shall be included
12in all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
021
=== added file 'python/iso8601/README'
--- python/iso8601/README 1970-01-01 00:00:00 +0000
+++ python/iso8601/README 2009-07-20 10:08:11 +0000
@@ -0,0 +1,26 @@
1A simple package to deal with ISO 8601 date time formats.
2
3ISO 8601 defines a neutral, unambiguous date string format, which also
4has the property of sorting naturally.
5
6e.g. YYYY-MM-DDTHH:MM:SSZ or 2007-01-25T12:00:00Z
7
8Currently this covers only the most common date formats encountered, not
9all of ISO 8601 is handled.
10
11Currently the following formats are handled:
12
13* 2006-01-01T00:00:00Z
14* 2006-01-01T00:00:00[+-]00:00
15
16I'll add more as I encounter them in my day to day life. Patches with
17new formats and tests will be gratefully accepted of course :)
18
19References:
20
21* http://www.cl.cam.ac.uk/~mgk25/iso-time.html - simple overview
22
23* http://hydracen.com/dx/iso8601.htm - more detailed enumeration of
24 valid formats.
25
26See the LICENSE file for the license this package is released under.
027
=== added file 'python/iso8601/README.subunit'
--- python/iso8601/README.subunit 1970-01-01 00:00:00 +0000
+++ python/iso8601/README.subunit 2009-07-20 10:08:11 +0000
@@ -0,0 +1,5 @@
1This is a [slightly rearranged] import of http://pypi.python.org/pypi/iso8601/
2version 0.1.4. The OS X hidden files have been stripped, and the package
3turned into a single module, to simplify installation. The remainder of the
4source distribution is included in the subunit source tree at python/iso8601
5for reference.
06
=== added file 'python/iso8601/setup.py'
--- python/iso8601/setup.py 1970-01-01 00:00:00 +0000
+++ python/iso8601/setup.py 2009-07-20 10:08:11 +0000
@@ -0,0 +1,58 @@
1try:
2 from setuptools import setup
3except ImportError:
4 from distutils import setup
5
6long_description="""Simple module to parse ISO 8601 dates
7
8This module parses the most common forms of ISO 8601 date strings (e.g.
92007-01-14T20:34:22+00:00) into datetime objects.
10
11>>> import iso8601
12>>> iso8601.parse_date("2007-01-25T12:00:00Z")
13datetime.datetime(2007, 1, 25, 12, 0, tzinfo=<iso8601.iso8601.Utc ...>)
14>>>
15
16Changes
17=======
18
190.1.4
20-----
21
22* The default_timezone argument wasn't being passed through correctly,
23 UTC was being used in every case. Fixes issue 10.
24
250.1.3
26-----
27
28* Fixed the microsecond handling, the generated microsecond values were
29 way too small. Fixes issue 9.
30
310.1.2
32-----
33
34* Adding ParseError to __all__ in iso8601 module, allows people to import it.
35 Addresses issue 7.
36* Be a little more flexible when dealing with dates without leading zeroes.
37 This violates the spec a little, but handles more dates as seen in the
38 field. Addresses issue 6.
39* Allow date/time separators other than T.
40
410.1.1
42-----
43
44* When parsing dates without a timezone the specified default is used. If no
45 default is specified then UTC is used. Addresses issue 4.
46"""
47
48setup(
49 name="iso8601",
50 version="0.1.4",
51 description=long_description.split("\n")[0],
52 long_description=long_description,
53 author="Michael Twomey",
54 author_email="micktwomey+iso8601@gmail.com",
55 url="http://code.google.com/p/pyiso8601/",
56 packages=["iso8601"],
57 license="MIT",
58)
059
=== added file 'python/iso8601/test_iso8601.py'
--- python/iso8601/test_iso8601.py 1970-01-01 00:00:00 +0000
+++ python/iso8601/test_iso8601.py 2009-07-20 10:08:11 +0000
@@ -0,0 +1,111 @@
1import iso8601
2
3def test_iso8601_regex():
4 assert iso8601.ISO8601_REGEX.match("2006-10-11T00:14:33Z")
5
6def test_timezone_regex():
7 assert iso8601.TIMEZONE_REGEX.match("+01:00")
8 assert iso8601.TIMEZONE_REGEX.match("+00:00")
9 assert iso8601.TIMEZONE_REGEX.match("+01:20")
10 assert iso8601.TIMEZONE_REGEX.match("-01:00")
11
12def test_parse_date():
13 d = iso8601.parse_date("2006-10-20T15:34:56Z")
14 assert d.year == 2006
15 assert d.month == 10
16 assert d.day == 20
17 assert d.hour == 15
18 assert d.minute == 34
19 assert d.second == 56
20 assert d.tzinfo == iso8601.UTC
21
22def test_parse_date_fraction():
23 d = iso8601.parse_date("2006-10-20T15:34:56.123Z")
24 assert d.year == 2006
25 assert d.month == 10
26 assert d.day == 20
27 assert d.hour == 15
28 assert d.minute == 34
29 assert d.second == 56
30 assert d.microsecond == 123000
31 assert d.tzinfo == iso8601.UTC
32
33def test_parse_date_fraction_2():
34 """From bug 6
35
36 """
37 d = iso8601.parse_date("2007-5-7T11:43:55.328Z'")
38 assert d.year == 2007
39 assert d.month == 5
40 assert d.day == 7
41 assert d.hour == 11
42 assert d.minute == 43
43 assert d.second == 55
44 assert d.microsecond == 328000
45 assert d.tzinfo == iso8601.UTC
46
47def test_parse_date_tz():
48 d = iso8601.parse_date("2006-10-20T15:34:56.123+02:30")
49 assert d.year == 2006
50 assert d.month == 10
51 assert d.day == 20
52 assert d.hour == 15
53 assert d.minute == 34
54 assert d.second == 56
55 assert d.microsecond == 123000
56 assert d.tzinfo.tzname(None) == "+02:30"
57 offset = d.tzinfo.utcoffset(None)
58 assert offset.days == 0
59 assert offset.seconds == 60 * 60 * 2.5
60
61def test_parse_invalid_date():
62 try:
63 iso8601.parse_date(None)
64 except iso8601.ParseError:
65 pass
66 else:
67 assert 1 == 2
68
69def test_parse_invalid_date2():
70 try:
71 iso8601.parse_date("23")
72 except iso8601.ParseError:
73 pass
74 else:
75 assert 1 == 2
76
77def test_parse_no_timezone():
78 """issue 4 - Handle datetime string without timezone
79
80 This tests what happens when you parse a date with no timezone. While not
81 strictly correct this is quite common. I'll assume UTC for the time zone
82 in this case.
83 """
84 d = iso8601.parse_date("2007-01-01T08:00:00")
85 assert d.year == 2007
86 assert d.month == 1
87 assert d.day == 1
88 assert d.hour == 8
89 assert d.minute == 0
90 assert d.second == 0
91 assert d.microsecond == 0
92 assert d.tzinfo == iso8601.UTC
93
94def test_parse_no_timezone_different_default():
95 tz = iso8601.FixedOffset(2, 0, "test offset")
96 d = iso8601.parse_date("2007-01-01T08:00:00", default_timezone=tz)
97 assert d.tzinfo == tz
98
99def test_space_separator():
100 """Handle a separator other than T
101
102 """
103 d = iso8601.parse_date("2007-06-23 06:40:34.00Z")
104 assert d.year == 2007
105 assert d.month == 6
106 assert d.day == 23
107 assert d.hour == 6
108 assert d.minute == 40
109 assert d.second == 34
110 assert d.microsecond == 0
111 assert d.tzinfo == iso8601.UTC
0112
=== modified file 'python/subunit/__init__.py'
--- python/subunit/__init__.py 2009-07-18 03:43:05 +0000
+++ python/subunit/__init__.py 2009-07-20 10:08:11 +0000
@@ -17,13 +17,17 @@
17# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA17# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18#18#
1919
20import datetime
20import os21import os
22import re
21from StringIO import StringIO23from StringIO import StringIO
22import subprocess24import subprocess
23import sys25import sys
24import re
25import unittest26import unittest
2627
28import iso8601
29
30
27def test_suite():31def test_suite():
28 import subunit.tests32 import subunit.tests
29 return subunit.tests.test_suite()33 return subunit.tests.test_suite()
@@ -207,6 +211,13 @@
207 update_tags.update(new_tags)211 update_tags.update(new_tags)
208 update_tags.difference_update(gone_tags)212 update_tags.difference_update(gone_tags)
209213
214 def _handleTime(self, offset, line):
215 # Accept it, but do not do anything with it yet.
216 event_time = iso8601.parse_date(line[offset:-1])
217 time_method = getattr(self.client, 'time', None)
218 if callable(time_method):
219 time_method(event_time)
220
210 def lineReceived(self, line):221 def lineReceived(self, line):
211 """Call the appropriate local method for the received line."""222 """Call the appropriate local method for the received line."""
212 if line == "]\n":223 if line == "]\n":
@@ -236,8 +247,7 @@
236 elif cmd in ('tags',):247 elif cmd in ('tags',):
237 self._handleTags(offset, line)248 self._handleTags(offset, line)
238 elif cmd in ('time',):249 elif cmd in ('time',):
239 # Accept it, but do not do anything with it yet.250 self._handleTime(offset, line)
240 pass
241 elif cmd == 'xfail':251 elif cmd == 'xfail':
242 self._addExpectedFail(offset, line)252 self._addExpectedFail(offset, line)
243 else:253 else:
244254
=== added file 'python/subunit/iso8601.py'
--- python/subunit/iso8601.py 1970-01-01 00:00:00 +0000
+++ python/subunit/iso8601.py 2009-07-20 10:08:11 +0000
@@ -0,0 +1,123 @@
1# Copyright (c) 2007 Michael Twomey
2#
3# Permission is hereby granted, free of charge, to any person obtaining a
4# copy of this software and associated documentation files (the
5# "Software"), to deal in the Software without restriction, including
6# without limitation the rights to use, copy, modify, merge, publish,
7# distribute, sublicense, and/or sell copies of the Software, and to
8# permit persons to whom the Software is furnished to do so, subject to
9# the following conditions:
10#
11# The above copyright notice and this permission notice shall be included
12# in all copies or substantial portions of the Software.
13#
14# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22"""ISO 8601 date time string parsing
23
24Basic usage:
25>>> import iso8601
26>>> iso8601.parse_date("2007-01-25T12:00:00Z")
27datetime.datetime(2007, 1, 25, 12, 0, tzinfo=<iso8601.iso8601.Utc ...>)
28>>>
29
30"""
31
32from datetime import datetime, timedelta, tzinfo
33import re
34
35__all__ = ["parse_date", "ParseError"]
36
37# Adapted from http://delete.me.uk/2005/03/iso8601.html
38ISO8601_REGEX = re.compile(r"(?P<year>[0-9]{4})(-(?P<month>[0-9]{1,2})(-(?P<day>[0-9]{1,2})"
39 r"((?P<separator>.)(?P<hour>[0-9]{2}):(?P<minute>[0-9]{2})(:(?P<second>[0-9]{2})(\.(?P<fraction>[0-9]+))?)?"
40 r"(?P<timezone>Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?"
41)
42TIMEZONE_REGEX = re.compile("(?P<prefix>[+-])(?P<hours>[0-9]{2}).(?P<minutes>[0-9]{2})")
43
44class ParseError(Exception):
45 """Raised when there is a problem parsing a date string"""
46
47# Yoinked from python docs
48ZERO = timedelta(0)
49class Utc(tzinfo):
50 """UTC
51
52 """
53 def utcoffset(self, dt):
54 return ZERO
55
56 def tzname(self, dt):
57 return "UTC"
58
59 def dst(self, dt):
60 return ZERO
61UTC = Utc()
62
63class FixedOffset(tzinfo):
64 """Fixed offset in hours and minutes from UTC
65
66 """
67 def __init__(self, offset_hours, offset_minutes, name):
68 self.__offset = timedelta(hours=offset_hours, minutes=offset_minutes)
69 self.__name = name
70
71 def utcoffset(self, dt):
72 return self.__offset
73
74 def tzname(self, dt):
75 return self.__name
76
77 def dst(self, dt):
78 return ZERO
79
80 def __repr__(self):
81 return "<FixedOffset %r>" % self.__name
82
83def parse_timezone(tzstring, default_timezone=UTC):
84 """Parses ISO 8601 time zone specs into tzinfo offsets
85
86 """
87 if tzstring == "Z":
88 return default_timezone
89 # This isn't strictly correct, but it's common to encounter dates without
90 # timezones so I'll assume the default (which defaults to UTC).
91 # Addresses issue 4.
92 if tzstring is None:
93 return default_timezone
94 m = TIMEZONE_REGEX.match(tzstring)
95 prefix, hours, minutes = m.groups()
96 hours, minutes = int(hours), int(minutes)
97 if prefix == "-":
98 hours = -hours
99 minutes = -minutes
100 return FixedOffset(hours, minutes, tzstring)
101
102def parse_date(datestring, default_timezone=UTC):
103 """Parses ISO 8601 dates into datetime objects
104
105 The timezone is parsed from the date string. However it is quite common to
106 have dates without a timezone (not strictly correct). In this case the
107 default timezone specified in default_timezone is used. This is UTC by
108 default.
109 """
110 if not isinstance(datestring, basestring):
111 raise ParseError("Expecting a string %r" % datestring)
112 m = ISO8601_REGEX.match(datestring)
113 if not m:
114 raise ParseError("Unable to parse date string %r" % datestring)
115 groups = m.groupdict()
116 tz = parse_timezone(groups["timezone"], default_timezone=default_timezone)
117 if groups["fraction"] is None:
118 groups["fraction"] = 0
119 else:
120 groups["fraction"] = int(float("0.%s" % groups["fraction"]) * 1e6)
121 return datetime(int(groups["year"]), int(groups["month"]), int(groups["day"]),
122 int(groups["hour"]), int(groups["minute"]), int(groups["second"]),
123 int(groups["fraction"]), tz)
0124
=== modified file 'python/subunit/tests/test_test_protocol.py'
--- python/subunit/tests/test_test_protocol.py 2009-07-18 03:43:05 +0000
+++ python/subunit/tests/test_test_protocol.py 2009-07-20 10:08:11 +0000
@@ -17,46 +17,49 @@
17# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA17# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18#18#
1919
20import datetime
20import unittest21import unittest
21from StringIO import StringIO22from StringIO import StringIO
22import os23import os
23import subunit24import subunit
24import sys25import sys
25import time26
2627import subunit.iso8601 as iso8601
27try:28
28 class MockTestProtocolServerClient(object):29
29 """A mock protocol server client to test callbacks."""30class MockTestProtocolServerClient(object):
3031 """A mock protocol server client to test callbacks."""
31 def __init__(self):32
32 self.end_calls = []33 def __init__(self):
33 self.error_calls = []34 self.end_calls = []
34 self.failure_calls = []35 self.error_calls = []
35 self.skip_calls = []36 self.failure_calls = []
36 self.start_calls = []37 self.skip_calls = []
37 self.success_calls = []38 self.start_calls = []
38 super(MockTestProtocolServerClient, self).__init__()39 self.success_calls = []
3940 self._time = None
40 def addError(self, test, error):41 super(MockTestProtocolServerClient, self).__init__()
41 self.error_calls.append((test, error))42
4243 def addError(self, test, error):
43 def addFailure(self, test, error):44 self.error_calls.append((test, error))
44 self.failure_calls.append((test, error))45
4546 def addFailure(self, test, error):
46 def addSkip(self, test, reason):47 self.failure_calls.append((test, error))
47 self.skip_calls.append((test, reason))48
4849 def addSkip(self, test, reason):
49 def addSuccess(self, test):50 self.skip_calls.append((test, reason))
50 self.success_calls.append(test)51
5152 def addSuccess(self, test):
52 def stopTest(self, test):53 self.success_calls.append(test)
53 self.end_calls.append(test)54
5455 def stopTest(self, test):
55 def startTest(self, test):56 self.end_calls.append(test)
56 self.start_calls.append(test)57
5758 def startTest(self, test):
58except AttributeError:59 self.start_calls.append(test)
59 MockTestProtocolServer = None60
61 def time(self, time):
62 self._time = time
6063
6164
62class TestMockTestProtocolServer(unittest.TestCase):65class TestMockTestProtocolServer(unittest.TestCase):
@@ -763,15 +766,23 @@
763class TestTestProtocolServerStreamTime(unittest.TestCase):766class TestTestProtocolServerStreamTime(unittest.TestCase):
764 """Test managing time information at the protocol level."""767 """Test managing time information at the protocol level."""
765768
766 def setUp(self):769 def test_time_accepted_stdlib(self):
767 self.client = MockTestProtocolServerClient()770 self.result = unittest.TestResult()
768 self.stream = StringIO()771 self.stream = StringIO()
769 self.protocol = subunit.TestProtocolServer(self.client,772 self.protocol = subunit.TestProtocolServer(self.result,
770 stream=self.stream)773 stream=self.stream)
774 self.protocol.lineReceived("time: 2001-12-12 12:59:59Z\n")
775 self.assertEqual("", self.stream.getvalue())
771776
772 def test_time_accepted(self):777 def test_time_accepted_extended(self):
778 self.result = MockTestProtocolServerClient()
779 self.stream = StringIO()
780 self.protocol = subunit.TestProtocolServer(self.result,
781 stream=self.stream)
773 self.protocol.lineReceived("time: 2001-12-12 12:59:59Z\n")782 self.protocol.lineReceived("time: 2001-12-12 12:59:59Z\n")
774 self.assertEqual("", self.stream.getvalue())783 self.assertEqual("", self.stream.getvalue())
784 self.assertEqual(datetime.datetime(2001, 12, 12, 12, 59, 59, 0,
785 iso8601.Utc()), self.result._time)
775786
776787
777class TestRemotedTestCase(unittest.TestCase):788class TestRemotedTestCase(unittest.TestCase):

Subscribers

People subscribed via source and target branches