2 # subunit: extensions to Python unittest to get test results from subprocesses.
3 # Copyright (C) 2005 Robert Collins <robertc@robertcollins.net>
5 # Licensed under either the Apache License, Version 2.0 or the BSD 3-clause
6 # license at the users choice. A copy of both licenses are available in the
7 # project source as Apache-2.0 and BSD. You may not use this file except in
8 # compliance with one of these two licences.
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT
12 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 # license you chose for the specific language governing permissions and
14 # limitations under that license.
21 from testtools import skipIf, TestCase
22 from testtools.compat import _b, _u, BytesIO, StringIO
23 from testtools.content import Content, TracebackContent
24 from testtools.content_type import ContentType
25 from testtools.tests.helpers import (
32 from subunit import _remote_exception_str, _remote_exception_str_chunked
33 import subunit.iso8601 as iso8601
36 class TestTestImports(unittest.TestCase):
38 def test_imports(self):
39 from subunit import DiscardStream
40 from subunit import TestProtocolServer
41 from subunit import RemotedTestCase
42 from subunit import RemoteError
43 from subunit import ExecTestCase
44 from subunit import IsolatedTestCase
45 from subunit import TestProtocolClient
46 from subunit import ProtocolTestCase
49 class TestDiscardStream(unittest.TestCase):
52 subunit.DiscardStream().write("content")
55 class TestProtocolServerForward(unittest.TestCase):
58 client = unittest.TestResult()
60 protocol = subunit.TestProtocolServer(client, forward_stream=out)
61 pipe = BytesIO(_b("test old mcdonald\n"
62 "success old mcdonald\n"))
63 protocol.readFrom(pipe)
64 self.assertEqual(client.testsRun, 1)
65 self.assertEqual(pipe.getvalue(), out.getvalue())
67 def test_not_command(self):
68 client = unittest.TestResult()
70 protocol = subunit.TestProtocolServer(client,
71 stream=subunit.DiscardStream(), forward_stream=out)
72 pipe = BytesIO(_b("success old mcdonald\n"))
73 protocol.readFrom(pipe)
74 self.assertEqual(client.testsRun, 0)
75 self.assertEqual(_b(""), out.getvalue())
78 class TestTestProtocolServerPipe(unittest.TestCase):
81 client = unittest.TestResult()
82 protocol = subunit.TestProtocolServer(client)
83 pipe = BytesIO(_b("test old mcdonald\n"
84 "success old mcdonald\n"
86 "failure bing crosby [\n"
87 "foo.c:53:ERROR invalid state\n"
91 protocol.readFrom(pipe)
92 bing = subunit.RemotedTestCase("bing crosby")
93 an_error = subunit.RemotedTestCase("an error")
94 self.assertEqual(client.errors,
95 [(an_error, _remote_exception_str + '\n')])
98 [(bing, _remote_exception_str + ": Text attachment: traceback\n"
99 "------------\nfoo.c:53:ERROR invalid state\n"
100 "------------\n\n")])
101 self.assertEqual(client.testsRun, 3)
103 def test_non_test_characters_forwarded_immediately(self):
107 class TestTestProtocolServerStartTest(unittest.TestCase):
110 self.client = Python26TestResult()
111 self.stream = BytesIO()
112 self.protocol = subunit.TestProtocolServer(self.client, self.stream)
114 def test_start_test(self):
115 self.protocol.lineReceived(_b("test old mcdonald\n"))
116 self.assertEqual(self.client._events,
117 [('startTest', subunit.RemotedTestCase("old mcdonald"))])
119 def test_start_testing(self):
120 self.protocol.lineReceived(_b("testing old mcdonald\n"))
121 self.assertEqual(self.client._events,
122 [('startTest', subunit.RemotedTestCase("old mcdonald"))])
124 def test_start_test_colon(self):
125 self.protocol.lineReceived(_b("test: old mcdonald\n"))
126 self.assertEqual(self.client._events,
127 [('startTest', subunit.RemotedTestCase("old mcdonald"))])
129 def test_indented_test_colon_ignored(self):
130 ignored_line = _b(" test: old mcdonald\n")
131 self.protocol.lineReceived(ignored_line)
132 self.assertEqual([], self.client._events)
133 self.assertEqual(self.stream.getvalue(), ignored_line)
135 def test_start_testing_colon(self):
136 self.protocol.lineReceived(_b("testing: old mcdonald\n"))
137 self.assertEqual(self.client._events,
138 [('startTest', subunit.RemotedTestCase("old mcdonald"))])
141 class TestTestProtocolServerPassThrough(unittest.TestCase):
144 self.stdout = BytesIO()
145 self.test = subunit.RemotedTestCase("old mcdonald")
146 self.client = ExtendedTestResult()
147 self.protocol = subunit.TestProtocolServer(self.client, self.stdout)
149 def keywords_before_test(self):
150 self.protocol.lineReceived(_b("failure a\n"))
151 self.protocol.lineReceived(_b("failure: a\n"))
152 self.protocol.lineReceived(_b("error a\n"))
153 self.protocol.lineReceived(_b("error: a\n"))
154 self.protocol.lineReceived(_b("success a\n"))
155 self.protocol.lineReceived(_b("success: a\n"))
156 self.protocol.lineReceived(_b("successful a\n"))
157 self.protocol.lineReceived(_b("successful: a\n"))
158 self.protocol.lineReceived(_b("]\n"))
159 self.assertEqual(self.stdout.getvalue(), _b("failure a\n"
169 def test_keywords_before_test(self):
170 self.keywords_before_test()
171 self.assertEqual(self.client._events, [])
173 def test_keywords_after_error(self):
174 self.protocol.lineReceived(_b("test old mcdonald\n"))
175 self.protocol.lineReceived(_b("error old mcdonald\n"))
176 self.keywords_before_test()
178 ('startTest', self.test),
179 ('addError', self.test, {}),
180 ('stopTest', self.test),
181 ], self.client._events)
183 def test_keywords_after_failure(self):
184 self.protocol.lineReceived(_b("test old mcdonald\n"))
185 self.protocol.lineReceived(_b("failure old mcdonald\n"))
186 self.keywords_before_test()
187 self.assertEqual(self.client._events, [
188 ('startTest', self.test),
189 ('addFailure', self.test, {}),
190 ('stopTest', self.test),
193 def test_keywords_after_success(self):
194 self.protocol.lineReceived(_b("test old mcdonald\n"))
195 self.protocol.lineReceived(_b("success old mcdonald\n"))
196 self.keywords_before_test()
198 ('startTest', self.test),
199 ('addSuccess', self.test),
200 ('stopTest', self.test),
201 ], self.client._events)
203 def test_keywords_after_test(self):
204 self.protocol.lineReceived(_b("test old mcdonald\n"))
205 self.protocol.lineReceived(_b("test old mcdonald\n"))
206 self.protocol.lineReceived(_b("failure a\n"))
207 self.protocol.lineReceived(_b("failure: a\n"))
208 self.protocol.lineReceived(_b("error a\n"))
209 self.protocol.lineReceived(_b("error: a\n"))
210 self.protocol.lineReceived(_b("success a\n"))
211 self.protocol.lineReceived(_b("success: a\n"))
212 self.protocol.lineReceived(_b("successful a\n"))
213 self.protocol.lineReceived(_b("successful: a\n"))
214 self.protocol.lineReceived(_b("]\n"))
215 self.protocol.lineReceived(_b("failure old mcdonald\n"))
216 self.assertEqual(self.stdout.getvalue(), _b("test old mcdonald\n"
226 self.assertEqual(self.client._events, [
227 ('startTest', self.test),
228 ('addFailure', self.test, {}),
229 ('stopTest', self.test),
232 def test_keywords_during_failure(self):
233 # A smoke test to make sure that the details parsers have control
235 self.protocol.lineReceived(_b("test old mcdonald\n"))
236 self.protocol.lineReceived(_b("failure: old mcdonald [\n"))
237 self.protocol.lineReceived(_b("test old mcdonald\n"))
238 self.protocol.lineReceived(_b("failure a\n"))
239 self.protocol.lineReceived(_b("failure: a\n"))
240 self.protocol.lineReceived(_b("error a\n"))
241 self.protocol.lineReceived(_b("error: a\n"))
242 self.protocol.lineReceived(_b("success a\n"))
243 self.protocol.lineReceived(_b("success: a\n"))
244 self.protocol.lineReceived(_b("successful a\n"))
245 self.protocol.lineReceived(_b("successful: a\n"))
246 self.protocol.lineReceived(_b(" ]\n"))
247 self.protocol.lineReceived(_b("]\n"))
248 self.assertEqual(self.stdout.getvalue(), _b(""))
250 details['traceback'] = Content(ContentType("text", "x-traceback",
251 {'charset': 'utf8'}),
253 "test old mcdonald\n"
263 self.assertEqual(self.client._events, [
264 ('startTest', self.test),
265 ('addFailure', self.test, details),
266 ('stopTest', self.test),
269 def test_stdout_passthrough(self):
270 """Lines received which cannot be interpreted as any protocol action
271 should be passed through to sys.stdout.
273 bytes = _b("randombytes\n")
274 self.protocol.lineReceived(bytes)
275 self.assertEqual(self.stdout.getvalue(), bytes)
278 class TestTestProtocolServerLostConnection(unittest.TestCase):
281 self.client = Python26TestResult()
282 self.protocol = subunit.TestProtocolServer(self.client)
283 self.test = subunit.RemotedTestCase("old mcdonald")
285 def test_lost_connection_no_input(self):
286 self.protocol.lostConnection()
287 self.assertEqual([], self.client._events)
289 def test_lost_connection_after_start(self):
290 self.protocol.lineReceived(_b("test old mcdonald\n"))
291 self.protocol.lostConnection()
292 failure = subunit.RemoteError(
293 _u("lost connection during test 'old mcdonald'"))
295 ('startTest', self.test),
296 ('addError', self.test, failure),
297 ('stopTest', self.test),
298 ], self.client._events)
300 def test_lost_connected_after_error(self):
301 self.protocol.lineReceived(_b("test old mcdonald\n"))
302 self.protocol.lineReceived(_b("error old mcdonald\n"))
303 self.protocol.lostConnection()
305 ('startTest', self.test),
306 ('addError', self.test, subunit.RemoteError(_u(""))),
307 ('stopTest', self.test),
308 ], self.client._events)
310 def do_connection_lost(self, outcome, opening):
311 self.protocol.lineReceived(_b("test old mcdonald\n"))
312 self.protocol.lineReceived(_b("%s old mcdonald %s" % (outcome, opening)))
313 self.protocol.lostConnection()
314 failure = subunit.RemoteError(
315 _u("lost connection during %s report of test 'old mcdonald'") %
318 ('startTest', self.test),
319 ('addError', self.test, failure),
320 ('stopTest', self.test),
321 ], self.client._events)
323 def test_lost_connection_during_error(self):
324 self.do_connection_lost("error", "[\n")
326 def test_lost_connection_during_error_details(self):
327 self.do_connection_lost("error", "[ multipart\n")
329 def test_lost_connected_after_failure(self):
330 self.protocol.lineReceived(_b("test old mcdonald\n"))
331 self.protocol.lineReceived(_b("failure old mcdonald\n"))
332 self.protocol.lostConnection()
334 ('startTest', self.test),
335 ('addFailure', self.test, subunit.RemoteError(_u(""))),
336 ('stopTest', self.test),
337 ], self.client._events)
339 def test_lost_connection_during_failure(self):
340 self.do_connection_lost("failure", "[\n")
342 def test_lost_connection_during_failure_details(self):
343 self.do_connection_lost("failure", "[ multipart\n")
345 def test_lost_connection_after_success(self):
346 self.protocol.lineReceived(_b("test old mcdonald\n"))
347 self.protocol.lineReceived(_b("success old mcdonald\n"))
348 self.protocol.lostConnection()
350 ('startTest', self.test),
351 ('addSuccess', self.test),
352 ('stopTest', self.test),
353 ], self.client._events)
355 def test_lost_connection_during_success(self):
356 self.do_connection_lost("success", "[\n")
358 def test_lost_connection_during_success_details(self):
359 self.do_connection_lost("success", "[ multipart\n")
361 def test_lost_connection_during_skip(self):
362 self.do_connection_lost("skip", "[\n")
364 def test_lost_connection_during_skip_details(self):
365 self.do_connection_lost("skip", "[ multipart\n")
367 def test_lost_connection_during_xfail(self):
368 self.do_connection_lost("xfail", "[\n")
370 def test_lost_connection_during_xfail_details(self):
371 self.do_connection_lost("xfail", "[ multipart\n")
373 def test_lost_connection_during_uxsuccess(self):
374 self.do_connection_lost("uxsuccess", "[\n")
376 def test_lost_connection_during_uxsuccess_details(self):
377 self.do_connection_lost("uxsuccess", "[ multipart\n")
380 class TestInTestMultipart(unittest.TestCase):
383 self.client = ExtendedTestResult()
384 self.protocol = subunit.TestProtocolServer(self.client)
385 self.protocol.lineReceived(_b("test mcdonalds farm\n"))
386 self.test = subunit.RemotedTestCase(_u("mcdonalds farm"))
388 def test__outcome_sets_details_parser(self):
389 self.protocol._reading_success_details.details_parser = None
390 self.protocol._state._outcome(0, _b("mcdonalds farm [ multipart\n"),
391 None, self.protocol._reading_success_details)
392 parser = self.protocol._reading_success_details.details_parser
393 self.assertNotEqual(None, parser)
394 self.assertTrue(isinstance(parser,
395 subunit.details.MultipartDetailsParser))
398 class TestTestProtocolServerAddError(unittest.TestCase):
401 self.client = ExtendedTestResult()
402 self.protocol = subunit.TestProtocolServer(self.client)
403 self.protocol.lineReceived(_b("test mcdonalds farm\n"))
404 self.test = subunit.RemotedTestCase("mcdonalds farm")
406 def simple_error_keyword(self, keyword):
407 self.protocol.lineReceived(_b("%s mcdonalds farm\n" % keyword))
410 ('startTest', self.test),
411 ('addError', self.test, details),
412 ('stopTest', self.test),
413 ], self.client._events)
415 def test_simple_error(self):
416 self.simple_error_keyword("error")
418 def test_simple_error_colon(self):
419 self.simple_error_keyword("error:")
421 def test_error_empty_message(self):
422 self.protocol.lineReceived(_b("error mcdonalds farm [\n"))
423 self.protocol.lineReceived(_b("]\n"))
425 details['traceback'] = Content(ContentType("text", "x-traceback",
426 {'charset': 'utf8'}), lambda:[_b("")])
428 ('startTest', self.test),
429 ('addError', self.test, details),
430 ('stopTest', self.test),
431 ], self.client._events)
433 def error_quoted_bracket(self, keyword):
434 self.protocol.lineReceived(_b("%s mcdonalds farm [\n" % keyword))
435 self.protocol.lineReceived(_b(" ]\n"))
436 self.protocol.lineReceived(_b("]\n"))
438 details['traceback'] = Content(ContentType("text", "x-traceback",
439 {'charset': 'utf8'}), lambda:[_b("]\n")])
441 ('startTest', self.test),
442 ('addError', self.test, details),
443 ('stopTest', self.test),
444 ], self.client._events)
446 def test_error_quoted_bracket(self):
447 self.error_quoted_bracket("error")
449 def test_error_colon_quoted_bracket(self):
450 self.error_quoted_bracket("error:")
453 class TestTestProtocolServerAddFailure(unittest.TestCase):
456 self.client = ExtendedTestResult()
457 self.protocol = subunit.TestProtocolServer(self.client)
458 self.protocol.lineReceived(_b("test mcdonalds farm\n"))
459 self.test = subunit.RemotedTestCase("mcdonalds farm")
461 def assertFailure(self, details):
463 ('startTest', self.test),
464 ('addFailure', self.test, details),
465 ('stopTest', self.test),
466 ], self.client._events)
468 def simple_failure_keyword(self, keyword):
469 self.protocol.lineReceived(_b("%s mcdonalds farm\n" % keyword))
471 self.assertFailure(details)
473 def test_simple_failure(self):
474 self.simple_failure_keyword("failure")
476 def test_simple_failure_colon(self):
477 self.simple_failure_keyword("failure:")
479 def test_failure_empty_message(self):
480 self.protocol.lineReceived(_b("failure mcdonalds farm [\n"))
481 self.protocol.lineReceived(_b("]\n"))
483 details['traceback'] = Content(ContentType("text", "x-traceback",
484 {'charset': 'utf8'}), lambda:[_b("")])
485 self.assertFailure(details)
487 def failure_quoted_bracket(self, keyword):
488 self.protocol.lineReceived(_b("%s mcdonalds farm [\n" % keyword))
489 self.protocol.lineReceived(_b(" ]\n"))
490 self.protocol.lineReceived(_b("]\n"))
492 details['traceback'] = Content(ContentType("text", "x-traceback",
493 {'charset': 'utf8'}), lambda:[_b("]\n")])
494 self.assertFailure(details)
496 def test_failure_quoted_bracket(self):
497 self.failure_quoted_bracket("failure")
499 def test_failure_colon_quoted_bracket(self):
500 self.failure_quoted_bracket("failure:")
503 class TestTestProtocolServerAddxFail(unittest.TestCase):
504 """Tests for the xfail keyword.
506 In Python this can thunk through to Success due to stdlib limitations (see
510 def capture_expected_failure(self, test, err):
511 self._events.append((test, err))
513 def setup_python26(self):
514 """Setup a test object ready to be xfailed and thunk to success."""
515 self.client = Python26TestResult()
516 self.setup_protocol()
518 def setup_python27(self):
519 """Setup a test object ready to be xfailed."""
520 self.client = Python27TestResult()
521 self.setup_protocol()
523 def setup_python_ex(self):
524 """Setup a test object ready to be xfailed with details."""
525 self.client = ExtendedTestResult()
526 self.setup_protocol()
528 def setup_protocol(self):
529 """Setup the protocol based on self.client."""
530 self.protocol = subunit.TestProtocolServer(self.client)
531 self.protocol.lineReceived(_b("test mcdonalds farm\n"))
532 self.test = self.client._events[-1][-1]
534 def simple_xfail_keyword(self, keyword, as_success):
535 self.protocol.lineReceived(_b("%s mcdonalds farm\n" % keyword))
536 self.check_success_or_xfail(as_success)
538 def check_success_or_xfail(self, as_success, error_message=None):
541 ('startTest', self.test),
542 ('addSuccess', self.test),
543 ('stopTest', self.test),
544 ], self.client._events)
547 if error_message is not None:
548 details['traceback'] = Content(
549 ContentType("text", "x-traceback", {'charset': 'utf8'}),
550 lambda:[_b(error_message)])
551 if isinstance(self.client, ExtendedTestResult):
554 if error_message is not None:
555 value = subunit.RemoteError(_u("Text attachment: traceback\n"
556 "------------\n") + _u(error_message) +
557 _u("------------\n"))
559 value = subunit.RemoteError()
561 ('startTest', self.test),
562 ('addExpectedFailure', self.test, value),
563 ('stopTest', self.test),
564 ], self.client._events)
566 def test_simple_xfail(self):
567 self.setup_python26()
568 self.simple_xfail_keyword("xfail", True)
569 self.setup_python27()
570 self.simple_xfail_keyword("xfail", False)
571 self.setup_python_ex()
572 self.simple_xfail_keyword("xfail", False)
574 def test_simple_xfail_colon(self):
575 self.setup_python26()
576 self.simple_xfail_keyword("xfail:", True)
577 self.setup_python27()
578 self.simple_xfail_keyword("xfail:", False)
579 self.setup_python_ex()
580 self.simple_xfail_keyword("xfail:", False)
582 def test_xfail_empty_message(self):
583 self.setup_python26()
584 self.empty_message(True)
585 self.setup_python27()
586 self.empty_message(False)
587 self.setup_python_ex()
588 self.empty_message(False, error_message="")
590 def empty_message(self, as_success, error_message="\n"):
591 self.protocol.lineReceived(_b("xfail mcdonalds farm [\n"))
592 self.protocol.lineReceived(_b("]\n"))
593 self.check_success_or_xfail(as_success, error_message)
595 def xfail_quoted_bracket(self, keyword, as_success):
596 # This tests it is accepted, but cannot test it is used today, because
597 # of not having a way to expose it in Python so far.
598 self.protocol.lineReceived(_b("%s mcdonalds farm [\n" % keyword))
599 self.protocol.lineReceived(_b(" ]\n"))
600 self.protocol.lineReceived(_b("]\n"))
601 self.check_success_or_xfail(as_success, "]\n")
603 def test_xfail_quoted_bracket(self):
604 self.setup_python26()
605 self.xfail_quoted_bracket("xfail", True)
606 self.setup_python27()
607 self.xfail_quoted_bracket("xfail", False)
608 self.setup_python_ex()
609 self.xfail_quoted_bracket("xfail", False)
611 def test_xfail_colon_quoted_bracket(self):
612 self.setup_python26()
613 self.xfail_quoted_bracket("xfail:", True)
614 self.setup_python27()
615 self.xfail_quoted_bracket("xfail:", False)
616 self.setup_python_ex()
617 self.xfail_quoted_bracket("xfail:", False)
620 class TestTestProtocolServerAddunexpectedSuccess(TestCase):
621 """Tests for the uxsuccess keyword."""
623 def capture_expected_failure(self, test, err):
624 self._events.append((test, err))
626 def setup_python26(self):
627 """Setup a test object ready to be xfailed and thunk to success."""
628 self.client = Python26TestResult()
629 self.setup_protocol()
631 def setup_python27(self):
632 """Setup a test object ready to be xfailed."""
633 self.client = Python27TestResult()
634 self.setup_protocol()
636 def setup_python_ex(self):
637 """Setup a test object ready to be xfailed with details."""
638 self.client = ExtendedTestResult()
639 self.setup_protocol()
641 def setup_protocol(self):
642 """Setup the protocol based on self.client."""
643 self.protocol = subunit.TestProtocolServer(self.client)
644 self.protocol.lineReceived(_b("test mcdonalds farm\n"))
645 self.test = self.client._events[-1][-1]
647 def simple_uxsuccess_keyword(self, keyword, as_fail):
648 self.protocol.lineReceived(_b("%s mcdonalds farm\n" % keyword))
649 self.check_fail_or_uxsuccess(as_fail)
651 def check_fail_or_uxsuccess(self, as_fail, error_message=None):
653 if error_message is not None:
654 details['traceback'] = Content(
655 ContentType("text", "x-traceback", {'charset': 'utf8'}),
656 lambda:[_b(error_message)])
657 if isinstance(self.client, ExtendedTestResult):
662 self.client._events[1] = self.client._events[1][:2]
663 # The value is generated within the extended to original decorator:
664 # todo use the testtools matcher to check on this.
666 ('startTest', self.test),
667 ('addFailure', self.test),
668 ('stopTest', self.test),
669 ], self.client._events)
672 ('startTest', self.test),
673 ('addUnexpectedSuccess', self.test, value),
674 ('stopTest', self.test),
675 ], self.client._events)
678 ('startTest', self.test),
679 ('addUnexpectedSuccess', self.test),
680 ('stopTest', self.test),
681 ], self.client._events)
683 def test_simple_uxsuccess(self):
684 self.setup_python26()
685 self.simple_uxsuccess_keyword("uxsuccess", True)
686 self.setup_python27()
687 self.simple_uxsuccess_keyword("uxsuccess", False)
688 self.setup_python_ex()
689 self.simple_uxsuccess_keyword("uxsuccess", False)
691 def test_simple_uxsuccess_colon(self):
692 self.setup_python26()
693 self.simple_uxsuccess_keyword("uxsuccess:", True)
694 self.setup_python27()
695 self.simple_uxsuccess_keyword("uxsuccess:", False)
696 self.setup_python_ex()
697 self.simple_uxsuccess_keyword("uxsuccess:", False)
699 def test_uxsuccess_empty_message(self):
700 self.setup_python26()
701 self.empty_message(True)
702 self.setup_python27()
703 self.empty_message(False)
704 self.setup_python_ex()
705 self.empty_message(False, error_message="")
707 def empty_message(self, as_fail, error_message="\n"):
708 self.protocol.lineReceived(_b("uxsuccess mcdonalds farm [\n"))
709 self.protocol.lineReceived(_b("]\n"))
710 self.check_fail_or_uxsuccess(as_fail, error_message)
712 def uxsuccess_quoted_bracket(self, keyword, as_fail):
713 self.protocol.lineReceived(_b("%s mcdonalds farm [\n" % keyword))
714 self.protocol.lineReceived(_b(" ]\n"))
715 self.protocol.lineReceived(_b("]\n"))
716 self.check_fail_or_uxsuccess(as_fail, "]\n")
718 def test_uxsuccess_quoted_bracket(self):
719 self.setup_python26()
720 self.uxsuccess_quoted_bracket("uxsuccess", True)
721 self.setup_python27()
722 self.uxsuccess_quoted_bracket("uxsuccess", False)
723 self.setup_python_ex()
724 self.uxsuccess_quoted_bracket("uxsuccess", False)
726 def test_uxsuccess_colon_quoted_bracket(self):
727 self.setup_python26()
728 self.uxsuccess_quoted_bracket("uxsuccess:", True)
729 self.setup_python27()
730 self.uxsuccess_quoted_bracket("uxsuccess:", False)
731 self.setup_python_ex()
732 self.uxsuccess_quoted_bracket("uxsuccess:", False)
735 class TestTestProtocolServerAddSkip(unittest.TestCase):
736 """Tests for the skip keyword.
738 In Python this meets the testtools extended TestResult contract.
739 (See https://launchpad.net/testtools).
743 """Setup a test object ready to be skipped."""
744 self.client = ExtendedTestResult()
745 self.protocol = subunit.TestProtocolServer(self.client)
746 self.protocol.lineReceived(_b("test mcdonalds farm\n"))
747 self.test = self.client._events[-1][-1]
749 def assertSkip(self, reason):
751 if reason is not None:
752 details['reason'] = Content(
753 ContentType("text", "plain"), lambda:[reason])
755 ('startTest', self.test),
756 ('addSkip', self.test, details),
757 ('stopTest', self.test),
758 ], self.client._events)
760 def simple_skip_keyword(self, keyword):
761 self.protocol.lineReceived(_b("%s mcdonalds farm\n" % keyword))
762 self.assertSkip(None)
764 def test_simple_skip(self):
765 self.simple_skip_keyword("skip")
767 def test_simple_skip_colon(self):
768 self.simple_skip_keyword("skip:")
770 def test_skip_empty_message(self):
771 self.protocol.lineReceived(_b("skip mcdonalds farm [\n"))
772 self.protocol.lineReceived(_b("]\n"))
773 self.assertSkip(_b(""))
775 def skip_quoted_bracket(self, keyword):
776 # This tests it is accepted, but cannot test it is used today, because
777 # of not having a way to expose it in Python so far.
778 self.protocol.lineReceived(_b("%s mcdonalds farm [\n" % keyword))
779 self.protocol.lineReceived(_b(" ]\n"))
780 self.protocol.lineReceived(_b("]\n"))
781 self.assertSkip(_b("]\n"))
783 def test_skip_quoted_bracket(self):
784 self.skip_quoted_bracket("skip")
786 def test_skip_colon_quoted_bracket(self):
787 self.skip_quoted_bracket("skip:")
790 class TestTestProtocolServerAddSuccess(unittest.TestCase):
793 self.client = ExtendedTestResult()
794 self.protocol = subunit.TestProtocolServer(self.client)
795 self.protocol.lineReceived(_b("test mcdonalds farm\n"))
796 self.test = subunit.RemotedTestCase("mcdonalds farm")
798 def simple_success_keyword(self, keyword):
799 self.protocol.lineReceived(_b("%s mcdonalds farm\n" % keyword))
801 ('startTest', self.test),
802 ('addSuccess', self.test),
803 ('stopTest', self.test),
804 ], self.client._events)
806 def test_simple_success(self):
807 self.simple_success_keyword("successful")
809 def test_simple_success_colon(self):
810 self.simple_success_keyword("successful:")
812 def assertSuccess(self, details):
814 ('startTest', self.test),
815 ('addSuccess', self.test, details),
816 ('stopTest', self.test),
817 ], self.client._events)
819 def test_success_empty_message(self):
820 self.protocol.lineReceived(_b("success mcdonalds farm [\n"))
821 self.protocol.lineReceived(_b("]\n"))
823 details['message'] = Content(ContentType("text", "plain"),
825 self.assertSuccess(details)
827 def success_quoted_bracket(self, keyword):
828 # This tests it is accepted, but cannot test it is used today, because
829 # of not having a way to expose it in Python so far.
830 self.protocol.lineReceived(_b("%s mcdonalds farm [\n" % keyword))
831 self.protocol.lineReceived(_b(" ]\n"))
832 self.protocol.lineReceived(_b("]\n"))
834 details['message'] = Content(ContentType("text", "plain"),
836 self.assertSuccess(details)
838 def test_success_quoted_bracket(self):
839 self.success_quoted_bracket("success")
841 def test_success_colon_quoted_bracket(self):
842 self.success_quoted_bracket("success:")
845 class TestTestProtocolServerProgress(unittest.TestCase):
846 """Test receipt of progress: directives."""
848 def test_progress_accepted_stdlib(self):
849 self.result = Python26TestResult()
850 self.stream = BytesIO()
851 self.protocol = subunit.TestProtocolServer(self.result,
853 self.protocol.lineReceived(_b("progress: 23"))
854 self.protocol.lineReceived(_b("progress: -2"))
855 self.protocol.lineReceived(_b("progress: +4"))
856 self.assertEqual(_b(""), self.stream.getvalue())
858 def test_progress_accepted_extended(self):
859 # With a progress capable TestResult, progress events are emitted.
860 self.result = ExtendedTestResult()
861 self.stream = BytesIO()
862 self.protocol = subunit.TestProtocolServer(self.result,
864 self.protocol.lineReceived(_b("progress: 23"))
865 self.protocol.lineReceived(_b("progress: push"))
866 self.protocol.lineReceived(_b("progress: -2"))
867 self.protocol.lineReceived(_b("progress: pop"))
868 self.protocol.lineReceived(_b("progress: +4"))
869 self.assertEqual(_b(""), self.stream.getvalue())
871 ('progress', 23, subunit.PROGRESS_SET),
872 ('progress', None, subunit.PROGRESS_PUSH),
873 ('progress', -2, subunit.PROGRESS_CUR),
874 ('progress', None, subunit.PROGRESS_POP),
875 ('progress', 4, subunit.PROGRESS_CUR),
876 ], self.result._events)
879 class TestTestProtocolServerStreamTags(unittest.TestCase):
880 """Test managing tags on the protocol level."""
883 self.client = ExtendedTestResult()
884 self.protocol = subunit.TestProtocolServer(self.client)
886 def test_initial_tags(self):
887 self.protocol.lineReceived(_b("tags: foo bar:baz quux\n"))
889 ('tags', set(["foo", "bar:baz", "quux"]), set()),
890 ], self.client._events)
892 def test_minus_removes_tags(self):
893 self.protocol.lineReceived(_b("tags: -bar quux\n"))
895 ('tags', set(["quux"]), set(["bar"])),
896 ], self.client._events)
898 def test_tags_do_not_get_set_on_test(self):
899 self.protocol.lineReceived(_b("test mcdonalds farm\n"))
900 test = self.client._events[0][-1]
901 self.assertEqual(None, getattr(test, 'tags', None))
903 def test_tags_do_not_get_set_on_global_tags(self):
904 self.protocol.lineReceived(_b("tags: foo bar\n"))
905 self.protocol.lineReceived(_b("test mcdonalds farm\n"))
906 test = self.client._events[-1][-1]
907 self.assertEqual(None, getattr(test, 'tags', None))
909 def test_tags_get_set_on_test_tags(self):
910 self.protocol.lineReceived(_b("test mcdonalds farm\n"))
911 test = self.client._events[-1][-1]
912 self.protocol.lineReceived(_b("tags: foo bar\n"))
913 self.protocol.lineReceived(_b("success mcdonalds farm\n"))
914 self.assertEqual(None, getattr(test, 'tags', None))
917 class TestTestProtocolServerStreamTime(unittest.TestCase):
918 """Test managing time information at the protocol level."""
920 def test_time_accepted_stdlib(self):
921 self.result = Python26TestResult()
922 self.stream = BytesIO()
923 self.protocol = subunit.TestProtocolServer(self.result,
925 self.protocol.lineReceived(_b("time: 2001-12-12 12:59:59Z\n"))
926 self.assertEqual(_b(""), self.stream.getvalue())
928 def test_time_accepted_extended(self):
929 self.result = ExtendedTestResult()
930 self.stream = BytesIO()
931 self.protocol = subunit.TestProtocolServer(self.result,
933 self.protocol.lineReceived(_b("time: 2001-12-12 12:59:59Z\n"))
934 self.assertEqual(_b(""), self.stream.getvalue())
936 ('time', datetime.datetime(2001, 12, 12, 12, 59, 59, 0,
938 ], self.result._events)
941 class TestRemotedTestCase(unittest.TestCase):
943 def test_simple(self):
944 test = subunit.RemotedTestCase("A test description")
945 self.assertRaises(NotImplementedError, test.setUp)
946 self.assertRaises(NotImplementedError, test.tearDown)
947 self.assertEqual("A test description",
948 test.shortDescription())
949 self.assertEqual("A test description",
951 self.assertEqual("A test description (subunit.RemotedTestCase)", "%s" % test)
952 self.assertEqual("<subunit.RemotedTestCase description="
953 "'A test description'>", "%r" % test)
954 result = unittest.TestResult()
956 self.assertEqual([(test, _remote_exception_str + ": "
957 "Cannot run RemotedTestCases.\n\n")],
959 self.assertEqual(1, result.testsRun)
960 another_test = subunit.RemotedTestCase("A test description")
961 self.assertEqual(test, another_test)
962 different_test = subunit.RemotedTestCase("ofo")
963 self.assertNotEqual(test, different_test)
964 self.assertNotEqual(another_test, different_test)
967 class TestRemoteError(unittest.TestCase):
970 error = subunit.RemoteError(_u("Something went wrong"))
971 another_error = subunit.RemoteError(_u("Something went wrong"))
972 different_error = subunit.RemoteError(_u("boo!"))
973 self.assertEqual(error, another_error)
974 self.assertNotEqual(error, different_error)
975 self.assertNotEqual(different_error, another_error)
977 def test_empty_constructor(self):
978 self.assertEqual(subunit.RemoteError(), subunit.RemoteError(_u("")))
981 class TestExecTestCase(unittest.TestCase):
983 class SampleExecTestCase(subunit.ExecTestCase):
985 def test_sample_method(self):
986 """sample-script.py"""
987 # the sample script runs three tests, one each
988 # that fails, errors and succeeds
990 def test_sample_method_args(self):
991 """sample-script.py foo"""
992 # sample that will run just one test.
994 def test_construct(self):
995 test = self.SampleExecTestCase("test_sample_method")
996 self.assertEqual(test.script,
997 subunit.join_dir(__file__, 'sample-script.py'))
1000 result = unittest.TestResult()
1001 test = self.SampleExecTestCase("test_sample_method_args")
1003 self.assertEqual(1, result.testsRun)
1006 result = ExtendedTestResult()
1007 test = self.SampleExecTestCase("test_sample_method")
1009 mcdonald = subunit.RemotedTestCase("old mcdonald")
1010 bing = subunit.RemotedTestCase("bing crosby")
1012 bing_details['traceback'] = Content(ContentType("text", "x-traceback",
1013 {'charset': 'utf8'}), lambda:[_b("foo.c:53:ERROR invalid state\n")])
1014 an_error = subunit.RemotedTestCase("an error")
1017 ('startTest', mcdonald),
1018 ('addSuccess', mcdonald),
1019 ('stopTest', mcdonald),
1020 ('startTest', bing),
1021 ('addFailure', bing, bing_details),
1023 ('startTest', an_error),
1024 ('addError', an_error, error_details),
1025 ('stopTest', an_error),
1028 def test_debug(self):
1029 test = self.SampleExecTestCase("test_sample_method")
1032 def test_count_test_cases(self):
1033 """TODO run the child process and count responses to determine the count."""
1035 def test_join_dir(self):
1036 sibling = subunit.join_dir(__file__, 'foo')
1037 filedir = os.path.abspath(os.path.dirname(__file__))
1038 expected = os.path.join(filedir, 'foo')
1039 self.assertEqual(sibling, expected)
1042 class DoExecTestCase(subunit.ExecTestCase):
1044 def test_working_script(self):
1045 """sample-two-script.py"""
1048 class TestIsolatedTestCase(TestCase):
1050 class SampleIsolatedTestCase(subunit.IsolatedTestCase):
1057 TestIsolatedTestCase.SampleIsolatedTestCase.SETUP = True
1060 TestIsolatedTestCase.SampleIsolatedTestCase.TEARDOWN = True
1062 def test_sets_global_state(self):
1063 TestIsolatedTestCase.SampleIsolatedTestCase.TEST = True
1066 def test_construct(self):
1067 self.SampleIsolatedTestCase("test_sets_global_state")
1069 @skipIf(os.name != "posix", "Need a posix system for forking tests")
1071 result = unittest.TestResult()
1072 test = self.SampleIsolatedTestCase("test_sets_global_state")
1074 self.assertEqual(result.testsRun, 1)
1075 self.assertEqual(self.SampleIsolatedTestCase.SETUP, False)
1076 self.assertEqual(self.SampleIsolatedTestCase.TEARDOWN, False)
1077 self.assertEqual(self.SampleIsolatedTestCase.TEST, False)
1079 def test_debug(self):
1081 #test = self.SampleExecTestCase("test_sample_method")
1085 class TestIsolatedTestSuite(TestCase):
1087 class SampleTestToIsolate(unittest.TestCase):
1094 TestIsolatedTestSuite.SampleTestToIsolate.SETUP = True
1097 TestIsolatedTestSuite.SampleTestToIsolate.TEARDOWN = True
1099 def test_sets_global_state(self):
1100 TestIsolatedTestSuite.SampleTestToIsolate.TEST = True
1103 def test_construct(self):
1104 subunit.IsolatedTestSuite()
1106 @skipIf(os.name != "posix", "Need a posix system for forking tests")
1108 result = unittest.TestResult()
1109 suite = subunit.IsolatedTestSuite()
1110 sub_suite = unittest.TestSuite()
1111 sub_suite.addTest(self.SampleTestToIsolate("test_sets_global_state"))
1112 sub_suite.addTest(self.SampleTestToIsolate("test_sets_global_state"))
1113 suite.addTest(sub_suite)
1114 suite.addTest(self.SampleTestToIsolate("test_sets_global_state"))
1116 self.assertEqual(result.testsRun, 3)
1117 self.assertEqual(self.SampleTestToIsolate.SETUP, False)
1118 self.assertEqual(self.SampleTestToIsolate.TEARDOWN, False)
1119 self.assertEqual(self.SampleTestToIsolate.TEST, False)
1122 class TestTestProtocolClient(unittest.TestCase):
1126 self.protocol = subunit.TestProtocolClient(self.io)
1127 self.test = TestTestProtocolClient("test_start_test")
1128 self.sample_details = {'something':Content(
1129 ContentType('text', 'plain'), lambda:[_b('serialised\nform')])}
1130 self.sample_tb_details = dict(self.sample_details)
1131 self.sample_tb_details['traceback'] = TracebackContent(
1132 subunit.RemoteError(_u("boo qux")), self.test)
1134 def test_start_test(self):
1135 """Test startTest on a TestProtocolClient."""
1136 self.protocol.startTest(self.test)
1137 self.assertEqual(self.io.getvalue(), _b("test: %s\n" % self.test.id()))
1139 def test_stop_test(self):
1140 # stopTest doesn't output anything.
1141 self.protocol.stopTest(self.test)
1142 self.assertEqual(self.io.getvalue(), _b(""))
1144 def test_add_success(self):
1145 """Test addSuccess on a TestProtocolClient."""
1146 self.protocol.addSuccess(self.test)
1148 self.io.getvalue(), _b("successful: %s\n" % self.test.id()))
1150 def test_add_success_details(self):
1151 """Test addSuccess on a TestProtocolClient with details."""
1152 self.protocol.addSuccess(self.test, details=self.sample_details)
1154 self.io.getvalue(), _b("successful: %s [ multipart\n"
1155 "Content-Type: text/plain\n"
1157 "F\r\nserialised\nform0\r\n]\n" % self.test.id()))
1159 def test_add_failure(self):
1160 """Test addFailure on a TestProtocolClient."""
1161 self.protocol.addFailure(
1162 self.test, subunit.RemoteError(_u("boo qux")))
1165 _b(('failure: %s [\n' + _remote_exception_str + ': boo qux\n]\n')
1168 def test_add_failure_details(self):
1169 """Test addFailure on a TestProtocolClient with details."""
1170 self.protocol.addFailure(
1171 self.test, details=self.sample_tb_details)
1174 _b(("failure: %s [ multipart\n"
1175 "Content-Type: text/plain\n"
1177 "F\r\nserialised\nform0\r\n"
1178 "Content-Type: text/x-traceback;charset=utf8,language=python\n"
1179 "traceback\n" + _remote_exception_str_chunked + ": boo qux\n0\r\n"
1180 "]\n") % self.test.id()))
1182 def test_add_error(self):
1183 """Test stopTest on a TestProtocolClient."""
1184 self.protocol.addError(
1185 self.test, subunit.RemoteError(_u("phwoar crikey")))
1188 _b(('error: %s [\n' +
1189 _remote_exception_str + ": phwoar crikey\n"
1190 "]\n") % self.test.id()))
1192 def test_add_error_details(self):
1193 """Test stopTest on a TestProtocolClient with details."""
1194 self.protocol.addError(
1195 self.test, details=self.sample_tb_details)
1198 _b(("error: %s [ multipart\n"
1199 "Content-Type: text/plain\n"
1201 "F\r\nserialised\nform0\r\n"
1202 "Content-Type: text/x-traceback;charset=utf8,language=python\n"
1203 "traceback\n" + _remote_exception_str_chunked + ": boo qux\n0\r\n"
1204 "]\n") % self.test.id()))
1206 def test_add_expected_failure(self):
1207 """Test addExpectedFailure on a TestProtocolClient."""
1208 self.protocol.addExpectedFailure(
1209 self.test, subunit.RemoteError(_u("phwoar crikey")))
1212 _b(('xfail: %s [\n' +
1213 _remote_exception_str + ": phwoar crikey\n"
1214 "]\n") % self.test.id()))
1216 def test_add_expected_failure_details(self):
1217 """Test addExpectedFailure on a TestProtocolClient with details."""
1218 self.protocol.addExpectedFailure(
1219 self.test, details=self.sample_tb_details)
1222 _b(("xfail: %s [ multipart\n"
1223 "Content-Type: text/plain\n"
1225 "F\r\nserialised\nform0\r\n"
1226 "Content-Type: text/x-traceback;charset=utf8,language=python\n"
1227 "traceback\n" + _remote_exception_str_chunked + ": boo qux\n0\r\n"
1228 "]\n") % self.test.id()))
1231 def test_add_skip(self):
1232 """Test addSkip on a TestProtocolClient."""
1233 self.protocol.addSkip(
1234 self.test, "Has it really?")
1237 _b('skip: %s [\nHas it really?\n]\n' % self.test.id()))
1239 def test_add_skip_details(self):
1240 """Test addSkip on a TestProtocolClient with details."""
1241 details = {'reason':Content(
1242 ContentType('text', 'plain'), lambda:[_b('Has it really?')])}
1243 self.protocol.addSkip(self.test, details=details)
1246 _b("skip: %s [ multipart\n"
1247 "Content-Type: text/plain\n"
1249 "E\r\nHas it really?0\r\n"
1250 "]\n" % self.test.id()))
1252 def test_progress_set(self):
1253 self.protocol.progress(23, subunit.PROGRESS_SET)
1254 self.assertEqual(self.io.getvalue(), _b('progress: 23\n'))
1256 def test_progress_neg_cur(self):
1257 self.protocol.progress(-23, subunit.PROGRESS_CUR)
1258 self.assertEqual(self.io.getvalue(), _b('progress: -23\n'))
1260 def test_progress_pos_cur(self):
1261 self.protocol.progress(23, subunit.PROGRESS_CUR)
1262 self.assertEqual(self.io.getvalue(), _b('progress: +23\n'))
1264 def test_progress_pop(self):
1265 self.protocol.progress(1234, subunit.PROGRESS_POP)
1266 self.assertEqual(self.io.getvalue(), _b('progress: pop\n'))
1268 def test_progress_push(self):
1269 self.protocol.progress(1234, subunit.PROGRESS_PUSH)
1270 self.assertEqual(self.io.getvalue(), _b('progress: push\n'))
1272 def test_time(self):
1273 # Calling time() outputs a time signal immediately.
1275 datetime.datetime(2009,10,11,12,13,14,15, iso8601.Utc()))
1277 _b("time: 2009-10-11 12:13:14.000015Z\n"),
1280 def test_add_unexpected_success(self):
1281 """Test addUnexpectedSuccess on a TestProtocolClient."""
1282 self.protocol.addUnexpectedSuccess(self.test)
1284 self.io.getvalue(), _b("uxsuccess: %s\n" % self.test.id()))
1286 def test_add_unexpected_success_details(self):
1287 """Test addUnexpectedSuccess on a TestProtocolClient with details."""
1288 self.protocol.addUnexpectedSuccess(self.test, details=self.sample_details)
1290 self.io.getvalue(), _b("uxsuccess: %s [ multipart\n"
1291 "Content-Type: text/plain\n"
1293 "F\r\nserialised\nform0\r\n]\n" % self.test.id()))
1297 loader = subunit.tests.TestUtil.TestLoader()
1298 result = loader.loadTestsFromName(__name__)