Merge lp:~lifeless/subunit/filter into lp:~subunit/subunit/trunk
- filter
- Merge into trunk
Proposed by
Jonathan Lange
Status: | Merged |
---|---|
Approved by: | Jonathan Lange |
Approved revision: | 56 |
Merged at revision: | not available |
Proposed branch: | lp:~lifeless/subunit/filter |
Merge into: | lp:~subunit/subunit/trunk |
Diff against target: | None lines |
To merge this branch: | bzr merge lp:~lifeless/subunit/filter |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Jonathan Lange | Approve | ||
Review via email: mp+4006@code.launchpad.net |
Commit message
Description of the change
To post a comment you must log in.
Revision history for this message
Jonathan Lange (jml) wrote : | # |
lp:~lifeless/subunit/filter
updated
- 57. By Robert Collins
-
Update skip support in python to be in line with testtools.
- 58. By Robert Collins
-
subunit-filter can now filter skips too.
Revision history for this message
Jonathan Lange (jml) wrote : | # |
Two things!
* Rename FilterResult in subunit-ls so the name indicates what kind of filtering it does. ListingFilterRe
* Spurious blank line at python/
review:
Approve
Revision history for this message
Jonathan Lange (jml) wrote : | # |
I meant line 307 of the diff, sorry.
lp:~lifeless/subunit/filter
updated
- 59. By Robert Collins
-
Review feedback on filters.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'README' | |||
2 | --- README 2009-02-15 11:55:00 +0000 | |||
3 | +++ README 2009-02-22 13:18:04 +0000 | |||
4 | @@ -40,6 +40,8 @@ | |||
5 | 40 | stream on-the-fly. Currently subunit provides: | 40 | stream on-the-fly. Currently subunit provides: |
6 | 41 | * tap2subunit - convert perl's TestAnythingProtocol to subunit. | 41 | * tap2subunit - convert perl's TestAnythingProtocol to subunit. |
7 | 42 | * subunit2pyunit - convert a subunit stream to pyunit test results. | 42 | * subunit2pyunit - convert a subunit stream to pyunit test results. |
8 | 43 | * subunit-filter - filter out tests from a subunit stream. | ||
9 | 44 | * subunit-ls - list the tests present in a subunit stream. | ||
10 | 43 | * subunit-stats - generate a summary of a subunit stream. | 45 | * subunit-stats - generate a summary of a subunit stream. |
11 | 44 | * subunit-tags - add or remove tags from a stream. | 46 | * subunit-tags - add or remove tags from a stream. |
12 | 45 | 47 | ||
13 | 46 | 48 | ||
14 | === added file 'filters/subunit-filter' | |||
15 | --- filters/subunit-filter 1970-01-01 00:00:00 +0000 | |||
16 | +++ filters/subunit-filter 2009-02-22 07:51:04 +0000 | |||
17 | @@ -0,0 +1,50 @@ | |||
18 | 1 | #!/usr/bin/env python | ||
19 | 2 | # subunit: extensions to python unittest to get test results from subprocesses. | ||
20 | 3 | # Copyright (C) 2008 Robert Collins <robertc@robertcollins.net> | ||
21 | 4 | # | ||
22 | 5 | # This program is free software; you can redistribute it and/or modify | ||
23 | 6 | # it under the terms of the GNU General Public License as published by | ||
24 | 7 | # the Free Software Foundation; either version 2 of the License, or | ||
25 | 8 | # (at your option) any later version. | ||
26 | 9 | # | ||
27 | 10 | # This program is distributed in the hope that it will be useful, | ||
28 | 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
29 | 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
30 | 13 | # GNU General Public License for more details. | ||
31 | 14 | # | ||
32 | 15 | # You should have received a copy of the GNU General Public License | ||
33 | 16 | # along with this program; if not, write to the Free Software | ||
34 | 17 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
35 | 18 | # | ||
36 | 19 | |||
37 | 20 | """Filter a subunit stream to include/exclude tests. | ||
38 | 21 | |||
39 | 22 | The default is to strip successful tests. | ||
40 | 23 | """ | ||
41 | 24 | |||
42 | 25 | from optparse import OptionParser | ||
43 | 26 | import sys | ||
44 | 27 | import unittest | ||
45 | 28 | |||
46 | 29 | from subunit import ProtocolTestCase, TestResultFilter, TestProtocolClient | ||
47 | 30 | |||
48 | 31 | parser = OptionParser(description=__doc__) | ||
49 | 32 | parser.add_option("--error", action="store_false", | ||
50 | 33 | help="include errors", default=False, dest="error") | ||
51 | 34 | parser.add_option("-e", "--no-error", action="store_true", | ||
52 | 35 | help="exclude errors", dest="error") | ||
53 | 36 | parser.add_option("--failure", action="store_false", | ||
54 | 37 | help="include failures", default=False, dest="failure") | ||
55 | 38 | parser.add_option("-f", "--no-failure", action="store_true", | ||
56 | 39 | help="include failures", dest="failure") | ||
57 | 40 | parser.add_option("-s", "--success", action="store_false", | ||
58 | 41 | help="include successes", dest="success") | ||
59 | 42 | parser.add_option("--no-success", action="store_true", | ||
60 | 43 | help="exclude successes", default=True, dest="success") | ||
61 | 44 | (options, args) = parser.parse_args() | ||
62 | 45 | result = TestProtocolClient(sys.stdout) | ||
63 | 46 | result = TestResultFilter(result, filter_error=options.error, filter_failure=options.failure, | ||
64 | 47 | filter_success=options.success) | ||
65 | 48 | test = ProtocolTestCase(sys.stdin) | ||
66 | 49 | test.run(result) | ||
67 | 50 | sys.exit(0) | ||
68 | 0 | 51 | ||
69 | === added file 'filters/subunit-ls' | |||
70 | --- filters/subunit-ls 1970-01-01 00:00:00 +0000 | |||
71 | +++ filters/subunit-ls 2009-02-23 10:54:28 +0000 | |||
72 | @@ -0,0 +1,62 @@ | |||
73 | 1 | #!/usr/bin/env python | ||
74 | 2 | # subunit: extensions to python unittest to get test results from subprocesses. | ||
75 | 3 | # Copyright (C) 2008 Robert Collins <robertc@robertcollins.net> | ||
76 | 4 | # | ||
77 | 5 | # This program is free software; you can redistribute it and/or modify | ||
78 | 6 | # it under the terms of the GNU General Public License as published by | ||
79 | 7 | # the Free Software Foundation; either version 2 of the License, or | ||
80 | 8 | # (at your option) any later version. | ||
81 | 9 | # | ||
82 | 10 | # This program is distributed in the hope that it will be useful, | ||
83 | 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
84 | 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
85 | 13 | # GNU General Public License for more details. | ||
86 | 14 | # | ||
87 | 15 | # You should have received a copy of the GNU General Public License | ||
88 | 16 | # along with this program; if not, write to the Free Software | ||
89 | 17 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
90 | 18 | # | ||
91 | 19 | |||
92 | 20 | """List tests in a subunit stream.""" | ||
93 | 21 | |||
94 | 22 | import sys | ||
95 | 23 | import unittest | ||
96 | 24 | |||
97 | 25 | from subunit import ProtocolTestCase | ||
98 | 26 | |||
99 | 27 | class FilterResult(unittest.TestResult): | ||
100 | 28 | """Filter test objects for display.""" | ||
101 | 29 | |||
102 | 30 | def __init__(self, stream): | ||
103 | 31 | """Create a FilterResult object outputting to stream.""" | ||
104 | 32 | unittest.TestResult.__init__(self) | ||
105 | 33 | self._stream = stream | ||
106 | 34 | self.failed_tests = 0 | ||
107 | 35 | |||
108 | 36 | def addError(self, test, err): | ||
109 | 37 | self.failed_tests += 1 | ||
110 | 38 | self.reportTest(test) | ||
111 | 39 | |||
112 | 40 | def addFailure(self, test, err): | ||
113 | 41 | self.failed_tests += 1 | ||
114 | 42 | self.reportTest(test) | ||
115 | 43 | |||
116 | 44 | def addSuccess(self, test): | ||
117 | 45 | self.reportTest(test) | ||
118 | 46 | |||
119 | 47 | def reportTest(self, test): | ||
120 | 48 | self._stream.write(test.id() + '\n') | ||
121 | 49 | |||
122 | 50 | def wasSuccessful(self): | ||
123 | 51 | "Tells whether or not this result was a success" | ||
124 | 52 | return self.failed_tests == 0 | ||
125 | 53 | |||
126 | 54 | |||
127 | 55 | result = FilterResult(sys.stdout) | ||
128 | 56 | test = ProtocolTestCase(sys.stdin) | ||
129 | 57 | test.run(result) | ||
130 | 58 | if result.wasSuccessful(): | ||
131 | 59 | exit_code = 0 | ||
132 | 60 | else: | ||
133 | 61 | exit_code = 1 | ||
134 | 62 | sys.exit(exit_code) | ||
135 | 0 | 63 | ||
136 | === modified file 'python/subunit/__init__.py' | |||
137 | --- python/subunit/__init__.py 2009-02-15 11:55:00 +0000 | |||
138 | +++ python/subunit/__init__.py 2009-02-23 10:54:28 +0000 | |||
139 | @@ -363,7 +363,7 @@ | |||
140 | 363 | return self.__description | 363 | return self.__description |
141 | 364 | 364 | ||
142 | 365 | def id(self): | 365 | def id(self): |
144 | 366 | return "%s.%s" % (self._strclass(), self.__description) | 366 | return "%s" % (self.__description,) |
145 | 367 | 367 | ||
146 | 368 | def __str__(self): | 368 | def __str__(self): |
147 | 369 | return "%s (%s)" % (self.__description, self._strclass()) | 369 | return "%s (%s)" % (self.__description, self._strclass()) |
148 | @@ -681,3 +681,52 @@ | |||
149 | 681 | def wasSuccessful(self): | 681 | def wasSuccessful(self): |
150 | 682 | """Tells whether or not this result was a success""" | 682 | """Tells whether or not this result was a success""" |
151 | 683 | return self.failed_tests == 0 | 683 | return self.failed_tests == 0 |
152 | 684 | |||
153 | 685 | |||
154 | 686 | class TestResultFilter(unittest.TestResult): | ||
155 | 687 | """A pyunit TestResult interface implementation which filters tests. | ||
156 | 688 | |||
157 | 689 | Tests that pass the filter are handed on to another TestResult instance | ||
158 | 690 | for further processing/reporting. To obtain the filtered results, | ||
159 | 691 | the other instance must be interrogated. | ||
160 | 692 | |||
161 | 693 | :ivar result: The result that tests are passed to after filtering. | ||
162 | 694 | """ | ||
163 | 695 | |||
164 | 696 | def __init__(self, result, filter_error=False, filter_failure=False, | ||
165 | 697 | filter_success=True): | ||
166 | 698 | """Create a FilterResult object filtering to result. | ||
167 | 699 | |||
168 | 700 | :param filter_error: Filter out errors. | ||
169 | 701 | :param filter_failure: Filter out failures. | ||
170 | 702 | :param filter_success: Filter out successful tests. | ||
171 | 703 | """ | ||
172 | 704 | unittest.TestResult.__init__(self) | ||
173 | 705 | self.result = result | ||
174 | 706 | self._filter_error = filter_error | ||
175 | 707 | self._filter_failure = filter_failure | ||
176 | 708 | self._filter_success = filter_success | ||
177 | 709 | |||
178 | 710 | def addError(self, test, err): | ||
179 | 711 | if not self._filter_error: | ||
180 | 712 | self.result.startTest(test) | ||
181 | 713 | self.result.addError(test, err) | ||
182 | 714 | self.result.stopTest(test) | ||
183 | 715 | |||
184 | 716 | def addFailure(self, test, err): | ||
185 | 717 | if not self._filter_failure: | ||
186 | 718 | self.result.startTest(test) | ||
187 | 719 | self.result.addFailure(test, err) | ||
188 | 720 | self.result.stopTest(test) | ||
189 | 721 | |||
190 | 722 | def addSuccess(self, test): | ||
191 | 723 | if not self._filter_success: | ||
192 | 724 | self.result.startTest(test) | ||
193 | 725 | self.result.addSuccess(test) | ||
194 | 726 | self.result.stopTest(test) | ||
195 | 727 | |||
196 | 728 | def id_to_orig_id(self, id): | ||
197 | 729 | if id.startswith("subunit.RemotedTestCase."): | ||
198 | 730 | return id[len("subunit.RemotedTestCase."):] | ||
199 | 731 | return id | ||
200 | 732 | |||
201 | 684 | 733 | ||
202 | === modified file 'python/subunit/tests/__init__.py' | |||
203 | --- python/subunit/tests/__init__.py 2008-12-09 01:00:03 +0000 | |||
204 | +++ python/subunit/tests/__init__.py 2009-02-22 06:28:08 +0000 | |||
205 | @@ -19,6 +19,7 @@ | |||
206 | 19 | 19 | ||
207 | 20 | from subunit.tests import ( | 20 | from subunit.tests import ( |
208 | 21 | TestUtil, | 21 | TestUtil, |
209 | 22 | test_subunit_filter, | ||
210 | 22 | test_subunit_stats, | 23 | test_subunit_stats, |
211 | 23 | test_subunit_tags, | 24 | test_subunit_tags, |
212 | 24 | test_tap2subunit, | 25 | test_tap2subunit, |
213 | @@ -29,6 +30,7 @@ | |||
214 | 29 | result = TestUtil.TestSuite() | 30 | result = TestUtil.TestSuite() |
215 | 30 | result.addTest(test_test_protocol.test_suite()) | 31 | result.addTest(test_test_protocol.test_suite()) |
216 | 31 | result.addTest(test_tap2subunit.test_suite()) | 32 | result.addTest(test_tap2subunit.test_suite()) |
217 | 33 | result.addTest(test_subunit_filter.test_suite()) | ||
218 | 32 | result.addTest(test_subunit_tags.test_suite()) | 34 | result.addTest(test_subunit_tags.test_suite()) |
219 | 33 | result.addTest(test_subunit_stats.test_suite()) | 35 | result.addTest(test_subunit_stats.test_suite()) |
220 | 34 | return result | 36 | return result |
221 | 35 | 37 | ||
222 | === added file 'python/subunit/tests/test_subunit_filter.py' | |||
223 | --- python/subunit/tests/test_subunit_filter.py 1970-01-01 00:00:00 +0000 | |||
224 | +++ python/subunit/tests/test_subunit_filter.py 2009-02-23 10:54:28 +0000 | |||
225 | @@ -0,0 +1,115 @@ | |||
226 | 1 | # | ||
227 | 2 | # subunit: extensions to python unittest to get test results from subprocesses. | ||
228 | 3 | # Copyright (C) 2005 Robert Collins <robertc@robertcollins.net> | ||
229 | 4 | # | ||
230 | 5 | # This program is free software; you can redistribute it and/or modify | ||
231 | 6 | # it under the terms of the GNU General Public License as published by | ||
232 | 7 | # the Free Software Foundation; either version 2 of the License, or | ||
233 | 8 | # (at your option) any later version. | ||
234 | 9 | # | ||
235 | 10 | # This program is distributed in the hope that it will be useful, | ||
236 | 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
237 | 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
238 | 13 | # GNU General Public License for more details. | ||
239 | 14 | # | ||
240 | 15 | # You should have received a copy of the GNU General Public License | ||
241 | 16 | # along with this program; if not, write to the Free Software | ||
242 | 17 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
243 | 18 | # | ||
244 | 19 | |||
245 | 20 | """Tests for subunit.TestResultFilter.""" | ||
246 | 21 | |||
247 | 22 | import unittest | ||
248 | 23 | from StringIO import StringIO | ||
249 | 24 | |||
250 | 25 | import subunit | ||
251 | 26 | |||
252 | 27 | |||
253 | 28 | class TestTestResultFilter(unittest.TestCase): | ||
254 | 29 | """Test for TestResultFilter, a TestResult object which filters tests.""" | ||
255 | 30 | |||
256 | 31 | def _setUp(self): | ||
257 | 32 | self.output = StringIO() | ||
258 | 33 | |||
259 | 34 | def test_default(self): | ||
260 | 35 | """The default is to exclude success and include everything else.""" | ||
261 | 36 | self.filtered_result = unittest.TestResult() | ||
262 | 37 | self.filter = subunit.TestResultFilter(self.filtered_result) | ||
263 | 38 | self.run_tests() | ||
264 | 39 | self.assertEqual(['error'], | ||
265 | 40 | [error[0].id() for error in self.filtered_result.errors]) | ||
266 | 41 | self.assertEqual(['failed'], | ||
267 | 42 | [failure[0].id() for failure in | ||
268 | 43 | self.filtered_result.failures]) | ||
269 | 44 | self.assertEqual(2, self.filtered_result.testsRun) | ||
270 | 45 | |||
271 | 46 | def test_exclude_errors(self): | ||
272 | 47 | self.filtered_result = unittest.TestResult() | ||
273 | 48 | self.filter = subunit.TestResultFilter(self.filtered_result, | ||
274 | 49 | filter_error=True) | ||
275 | 50 | self.run_tests() | ||
276 | 51 | self.assertEqual([], | ||
277 | 52 | [error[0].id() for error in self.filtered_result.errors]) | ||
278 | 53 | self.assertEqual(['failed'], | ||
279 | 54 | [failure[0].id() for failure in | ||
280 | 55 | self.filtered_result.failures]) | ||
281 | 56 | self.assertEqual(1, self.filtered_result.testsRun) | ||
282 | 57 | |||
283 | 58 | def test_exclude_failure(self): | ||
284 | 59 | self.filtered_result = unittest.TestResult() | ||
285 | 60 | self.filter = subunit.TestResultFilter(self.filtered_result, | ||
286 | 61 | filter_failure=True) | ||
287 | 62 | self.run_tests() | ||
288 | 63 | self.assertEqual(['error'], | ||
289 | 64 | [error[0].id() for error in self.filtered_result.errors]) | ||
290 | 65 | self.assertEqual([], | ||
291 | 66 | [failure[0].id() for failure in | ||
292 | 67 | self.filtered_result.failures]) | ||
293 | 68 | self.assertEqual(1, self.filtered_result.testsRun) | ||
294 | 69 | |||
295 | 70 | def test_include_success(self): | ||
296 | 71 | """Success's can be included if requested.""" | ||
297 | 72 | self.filtered_result = unittest.TestResult() | ||
298 | 73 | self.filter = subunit.TestResultFilter(self.filtered_result, | ||
299 | 74 | filter_success=False) | ||
300 | 75 | self.run_tests() | ||
301 | 76 | self.assertEqual(['error'], | ||
302 | 77 | [error[0].id() for error in self.filtered_result.errors]) | ||
303 | 78 | self.assertEqual(['failed'], | ||
304 | 79 | [failure[0].id() for failure in | ||
305 | 80 | self.filtered_result.failures]) | ||
306 | 81 | self.assertEqual(5, self.filtered_result.testsRun) | ||
307 | 82 | |||
308 | 83 | |||
309 | 84 | def run_tests(self): | ||
310 | 85 | self.setUpTestStream() | ||
311 | 86 | self.test = subunit.ProtocolTestCase(self.input_stream) | ||
312 | 87 | self.test.run(self.filter) | ||
313 | 88 | |||
314 | 89 | def setUpTestStream(self): | ||
315 | 90 | # While TestResultFilter works on python objects, using a subunit | ||
316 | 91 | # stream is an easy pithy way of getting a series of test objects to | ||
317 | 92 | # call into the TestResult, and as TestResultFilter is intended for use | ||
318 | 93 | # with subunit also has the benefit of detecting any interface skew issues. | ||
319 | 94 | self.input_stream = StringIO() | ||
320 | 95 | self.input_stream.write("""tags: global | ||
321 | 96 | test passed | ||
322 | 97 | success passed | ||
323 | 98 | test failed | ||
324 | 99 | tags: local | ||
325 | 100 | failure failed | ||
326 | 101 | test error | ||
327 | 102 | error error | ||
328 | 103 | test skipped | ||
329 | 104 | skip skipped | ||
330 | 105 | test todo | ||
331 | 106 | xfail todo | ||
332 | 107 | """) | ||
333 | 108 | self.input_stream.seek(0) | ||
334 | 109 | |||
335 | 110 | |||
336 | 111 | |||
337 | 112 | def test_suite(): | ||
338 | 113 | loader = subunit.tests.TestUtil.TestLoader() | ||
339 | 114 | result = loader.loadTestsFromName(__name__) | ||
340 | 115 | return result | ||
341 | 0 | 116 | ||
342 | === modified file 'python/subunit/tests/test_test_protocol.py' | |||
343 | --- python/subunit/tests/test_test_protocol.py 2008-12-14 18:37:08 +0000 | |||
344 | +++ python/subunit/tests/test_test_protocol.py 2009-02-23 10:54:28 +0000 | |||
345 | @@ -772,7 +772,7 @@ | |||
346 | 772 | self.assertRaises(NotImplementedError, test.tearDown) | 772 | self.assertRaises(NotImplementedError, test.tearDown) |
347 | 773 | self.assertEqual("A test description", | 773 | self.assertEqual("A test description", |
348 | 774 | test.shortDescription()) | 774 | test.shortDescription()) |
350 | 775 | self.assertEqual("subunit.RemotedTestCase.A test description", | 775 | self.assertEqual("A test description", |
351 | 776 | test.id()) | 776 | test.id()) |
352 | 777 | self.assertEqual("A test description (subunit.RemotedTestCase)", "%s" % test) | 777 | self.assertEqual("A test description (subunit.RemotedTestCase)", "%s" % test) |
353 | 778 | self.assertEqual("<subunit.RemotedTestCase description=" | 778 | self.assertEqual("<subunit.RemotedTestCase description=" |
Add filters for listing a stream and selecting only pass|failed|errored tests.