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 PlaceHolder, skipIf, TestCase, TestResult
22 from testtools.compat import _b, _u, BytesIO
23 from testtools.content import Content, TracebackContent, text_content
24 from testtools.content_type import ContentType
26 from testtools.testresult.doubles import (
32 from testtools.tests.helpers import (
39 from subunit import _remote_exception_str, _remote_exception_str_chunked
40 import subunit.iso8601 as iso8601
43 def details_to_str(details):
44 return TestResult()._err_details_to_string(None, details=details)
47 class TestTestImports(unittest.TestCase):
49 def test_imports(self):
50 from subunit import DiscardStream
51 from subunit import TestProtocolServer
52 from subunit import RemotedTestCase
53 from subunit import RemoteError
54 from subunit import ExecTestCase
55 from subunit import IsolatedTestCase
56 from subunit import TestProtocolClient
57 from subunit import ProtocolTestCase
60 class TestDiscardStream(unittest.TestCase):
63 subunit.DiscardStream().write("content")
66 class TestProtocolServerForward(unittest.TestCase):
69 client = unittest.TestResult()
71 protocol = subunit.TestProtocolServer(client, forward_stream=out)
72 pipe = BytesIO(_b("test old mcdonald\n"
73 "success old mcdonald\n"))
74 protocol.readFrom(pipe)
75 self.assertEqual(client.testsRun, 1)
76 self.assertEqual(pipe.getvalue(), out.getvalue())
78 def test_not_command(self):
79 client = unittest.TestResult()
81 protocol = subunit.TestProtocolServer(client,
82 stream=subunit.DiscardStream(), forward_stream=out)
83 pipe = BytesIO(_b("success old mcdonald\n"))
84 protocol.readFrom(pipe)
85 self.assertEqual(client.testsRun, 0)
86 self.assertEqual(_b(""), out.getvalue())
89 class TestTestProtocolServerPipe(unittest.TestCase):
92 client = unittest.TestResult()
93 protocol = subunit.TestProtocolServer(client)
94 traceback = "foo.c:53:ERROR invalid state\n"
95 pipe = BytesIO(_b("test old mcdonald\n"
96 "success old mcdonald\n"
98 "failure bing crosby [\n"
103 protocol.readFrom(pipe)
104 bing = subunit.RemotedTestCase("bing crosby")
105 an_error = subunit.RemotedTestCase("an error")
106 self.assertEqual(client.errors,
107 [(an_error, _remote_exception_str + '\n')])
110 [(bing, _remote_exception_str + ": "
111 + details_to_str({'traceback': text_content(traceback)}) + "\n")])
112 self.assertEqual(client.testsRun, 3)
114 def test_non_test_characters_forwarded_immediately(self):
118 class TestTestProtocolServerStartTest(unittest.TestCase):
121 self.client = Python26TestResult()
122 self.stream = BytesIO()
123 self.protocol = subunit.TestProtocolServer(self.client, self.stream)
125 def test_start_test(self):
126 self.protocol.lineReceived(_b("test old mcdonald\n"))
127 self.assertEqual(self.client._events,
128 [('startTest', subunit.RemotedTestCase("old mcdonald"))])
130 def test_start_testing(self):
131 self.protocol.lineReceived(_b("testing old mcdonald\n"))
132 self.assertEqual(self.client._events,
133 [('startTest', subunit.RemotedTestCase("old mcdonald"))])
135 def test_start_test_colon(self):
136 self.protocol.lineReceived(_b("test: old mcdonald\n"))
137 self.assertEqual(self.client._events,
138 [('startTest', subunit.RemotedTestCase("old mcdonald"))])
140 def test_indented_test_colon_ignored(self):
141 ignored_line = _b(" test: old mcdonald\n")
142 self.protocol.lineReceived(ignored_line)
143 self.assertEqual([], self.client._events)
144 self.assertEqual(self.stream.getvalue(), ignored_line)
146 def test_start_testing_colon(self):
147 self.protocol.lineReceived(_b("testing: old mcdonald\n"))
148 self.assertEqual(self.client._events,
149 [('startTest', subunit.RemotedTestCase("old mcdonald"))])
152 class TestTestProtocolServerPassThrough(unittest.TestCase):
155 self.stdout = BytesIO()
156 self.test = subunit.RemotedTestCase("old mcdonald")
157 self.client = ExtendedTestResult()
158 self.protocol = subunit.TestProtocolServer(self.client, self.stdout)
160 def keywords_before_test(self):
161 self.protocol.lineReceived(_b("failure a\n"))
162 self.protocol.lineReceived(_b("failure: a\n"))
163 self.protocol.lineReceived(_b("error a\n"))
164 self.protocol.lineReceived(_b("error: a\n"))
165 self.protocol.lineReceived(_b("success a\n"))
166 self.protocol.lineReceived(_b("success: a\n"))
167 self.protocol.lineReceived(_b("successful a\n"))
168 self.protocol.lineReceived(_b("successful: a\n"))
169 self.protocol.lineReceived(_b("]\n"))
170 self.assertEqual(self.stdout.getvalue(), _b("failure a\n"
180 def test_keywords_before_test(self):
181 self.keywords_before_test()
182 self.assertEqual(self.client._events, [])
184 def test_keywords_after_error(self):
185 self.protocol.lineReceived(_b("test old mcdonald\n"))
186 self.protocol.lineReceived(_b("error old mcdonald\n"))
187 self.keywords_before_test()
189 ('startTest', self.test),
190 ('addError', self.test, {}),
191 ('stopTest', self.test),
192 ], self.client._events)
194 def test_keywords_after_failure(self):
195 self.protocol.lineReceived(_b("test old mcdonald\n"))
196 self.protocol.lineReceived(_b("failure old mcdonald\n"))
197 self.keywords_before_test()
198 self.assertEqual(self.client._events, [
199 ('startTest', self.test),
200 ('addFailure', self.test, {}),
201 ('stopTest', self.test),
204 def test_keywords_after_success(self):
205 self.protocol.lineReceived(_b("test old mcdonald\n"))
206 self.protocol.lineReceived(_b("success old mcdonald\n"))
207 self.keywords_before_test()
209 ('startTest', self.test),
210 ('addSuccess', self.test),
211 ('stopTest', self.test),
212 ], self.client._events)
214 def test_keywords_after_test(self):
215 self.protocol.lineReceived(_b("test old mcdonald\n"))
216 self.protocol.lineReceived(_b("test old mcdonald\n"))
217 self.protocol.lineReceived(_b("failure a\n"))
218 self.protocol.lineReceived(_b("failure: a\n"))
219 self.protocol.lineReceived(_b("error a\n"))
220 self.protocol.lineReceived(_b("error: a\n"))
221 self.protocol.lineReceived(_b("success a\n"))
222 self.protocol.lineReceived(_b("success: a\n"))
223 self.protocol.lineReceived(_b("successful a\n"))
224 self.protocol.lineReceived(_b("successful: a\n"))
225 self.protocol.lineReceived(_b("]\n"))
226 self.protocol.lineReceived(_b("failure old mcdonald\n"))
227 self.assertEqual(self.stdout.getvalue(), _b("test old mcdonald\n"
237 self.assertEqual(self.client._events, [
238 ('startTest', self.test),
239 ('addFailure', self.test, {}),
240 ('stopTest', self.test),
243 def test_keywords_during_failure(self):
244 # A smoke test to make sure that the details parsers have control
246 self.protocol.lineReceived(_b("test old mcdonald\n"))
247 self.protocol.lineReceived(_b("failure: old mcdonald [\n"))
248 self.protocol.lineReceived(_b("test old mcdonald\n"))
249 self.protocol.lineReceived(_b("failure a\n"))
250 self.protocol.lineReceived(_b("failure: a\n"))
251 self.protocol.lineReceived(_b("error a\n"))
252 self.protocol.lineReceived(_b("error: a\n"))
253 self.protocol.lineReceived(_b("success a\n"))
254 self.protocol.lineReceived(_b("success: a\n"))
255 self.protocol.lineReceived(_b("successful a\n"))
256 self.protocol.lineReceived(_b("successful: a\n"))
257 self.protocol.lineReceived(_b(" ]\n"))
258 self.protocol.lineReceived(_b("]\n"))
259 self.assertEqual(self.stdout.getvalue(), _b(""))
261 details['traceback'] = Content(ContentType("text", "x-traceback",
262 {'charset': 'utf8'}),
264 "test old mcdonald\n"
274 self.assertEqual(self.client._events, [
275 ('startTest', self.test),
276 ('addFailure', self.test, details),
277 ('stopTest', self.test),
280 def test_stdout_passthrough(self):
281 """Lines received which cannot be interpreted as any protocol action
282 should be passed through to sys.stdout.
284 bytes = _b("randombytes\n")
285 self.protocol.lineReceived(bytes)
286 self.assertEqual(self.stdout.getvalue(), bytes)
289 class TestTestProtocolServerLostConnection(unittest.TestCase):
292 self.client = Python26TestResult()
293 self.protocol = subunit.TestProtocolServer(self.client)
294 self.test = subunit.RemotedTestCase("old mcdonald")
296 def test_lost_connection_no_input(self):
297 self.protocol.lostConnection()
298 self.assertEqual([], self.client._events)
300 def test_lost_connection_after_start(self):
301 self.protocol.lineReceived(_b("test old mcdonald\n"))
302 self.protocol.lostConnection()
303 failure = subunit.RemoteError(
304 _u("lost connection during test 'old mcdonald'"))
306 ('startTest', self.test),
307 ('addError', self.test, failure),
308 ('stopTest', self.test),
309 ], self.client._events)
311 def test_lost_connected_after_error(self):
312 self.protocol.lineReceived(_b("test old mcdonald\n"))
313 self.protocol.lineReceived(_b("error old mcdonald\n"))
314 self.protocol.lostConnection()
316 ('startTest', self.test),
317 ('addError', self.test, subunit.RemoteError(_u(""))),
318 ('stopTest', self.test),
319 ], self.client._events)
321 def do_connection_lost(self, outcome, opening):
322 self.protocol.lineReceived(_b("test old mcdonald\n"))
323 self.protocol.lineReceived(_b("%s old mcdonald %s" % (outcome, opening)))
324 self.protocol.lostConnection()
325 failure = subunit.RemoteError(
326 _u("lost connection during %s report of test 'old mcdonald'") %
329 ('startTest', self.test),
330 ('addError', self.test, failure),
331 ('stopTest', self.test),
332 ], self.client._events)
334 def test_lost_connection_during_error(self):
335 self.do_connection_lost("error", "[\n")
337 def test_lost_connection_during_error_details(self):
338 self.do_connection_lost("error", "[ multipart\n")
340 def test_lost_connected_after_failure(self):
341 self.protocol.lineReceived(_b("test old mcdonald\n"))
342 self.protocol.lineReceived(_b("failure old mcdonald\n"))
343 self.protocol.lostConnection()
345 ('startTest', self.test),
346 ('addFailure', self.test, subunit.RemoteError(_u(""))),
347 ('stopTest', self.test),
348 ], self.client._events)
350 def test_lost_connection_during_failure(self):
351 self.do_connection_lost("failure", "[\n")
353 def test_lost_connection_during_failure_details(self):
354 self.do_connection_lost("failure", "[ multipart\n")
356 def test_lost_connection_after_success(self):
357 self.protocol.lineReceived(_b("test old mcdonald\n"))
358 self.protocol.lineReceived(_b("success old mcdonald\n"))
359 self.protocol.lostConnection()
361 ('startTest', self.test),
362 ('addSuccess', self.test),
363 ('stopTest', self.test),
364 ], self.client._events)
366 def test_lost_connection_during_success(self):
367 self.do_connection_lost("success", "[\n")
369 def test_lost_connection_during_success_details(self):
370 self.do_connection_lost("success", "[ multipart\n")
372 def test_lost_connection_during_skip(self):
373 self.do_connection_lost("skip", "[\n")
375 def test_lost_connection_during_skip_details(self):
376 self.do_connection_lost("skip", "[ multipart\n")
378 def test_lost_connection_during_xfail(self):
379 self.do_connection_lost("xfail", "[\n")
381 def test_lost_connection_during_xfail_details(self):
382 self.do_connection_lost("xfail", "[ multipart\n")
384 def test_lost_connection_during_uxsuccess(self):
385 self.do_connection_lost("uxsuccess", "[\n")
387 def test_lost_connection_during_uxsuccess_details(self):
388 self.do_connection_lost("uxsuccess", "[ multipart\n")
391 class TestInTestMultipart(unittest.TestCase):
394 self.client = ExtendedTestResult()
395 self.protocol = subunit.TestProtocolServer(self.client)
396 self.protocol.lineReceived(_b("test mcdonalds farm\n"))
397 self.test = subunit.RemotedTestCase(_u("mcdonalds farm"))
399 def test__outcome_sets_details_parser(self):
400 self.protocol._reading_success_details.details_parser = None
401 self.protocol._state._outcome(0, _b("mcdonalds farm [ multipart\n"),
402 None, self.protocol._reading_success_details)
403 parser = self.protocol._reading_success_details.details_parser
404 self.assertNotEqual(None, parser)
405 self.assertTrue(isinstance(parser,
406 subunit.details.MultipartDetailsParser))
409 class TestTestProtocolServerAddError(unittest.TestCase):
412 self.client = ExtendedTestResult()
413 self.protocol = subunit.TestProtocolServer(self.client)
414 self.protocol.lineReceived(_b("test mcdonalds farm\n"))
415 self.test = subunit.RemotedTestCase("mcdonalds farm")
417 def simple_error_keyword(self, keyword):
418 self.protocol.lineReceived(_b("%s mcdonalds farm\n" % keyword))
421 ('startTest', self.test),
422 ('addError', self.test, details),
423 ('stopTest', self.test),
424 ], self.client._events)
426 def test_simple_error(self):
427 self.simple_error_keyword("error")
429 def test_simple_error_colon(self):
430 self.simple_error_keyword("error:")
432 def test_error_empty_message(self):
433 self.protocol.lineReceived(_b("error mcdonalds farm [\n"))
434 self.protocol.lineReceived(_b("]\n"))
436 details['traceback'] = Content(ContentType("text", "x-traceback",
437 {'charset': 'utf8'}), lambda:[_b("")])
439 ('startTest', self.test),
440 ('addError', self.test, details),
441 ('stopTest', self.test),
442 ], self.client._events)
444 def error_quoted_bracket(self, keyword):
445 self.protocol.lineReceived(_b("%s mcdonalds farm [\n" % keyword))
446 self.protocol.lineReceived(_b(" ]\n"))
447 self.protocol.lineReceived(_b("]\n"))
449 details['traceback'] = Content(ContentType("text", "x-traceback",
450 {'charset': 'utf8'}), lambda:[_b("]\n")])
452 ('startTest', self.test),
453 ('addError', self.test, details),
454 ('stopTest', self.test),
455 ], self.client._events)
457 def test_error_quoted_bracket(self):
458 self.error_quoted_bracket("error")
460 def test_error_colon_quoted_bracket(self):
461 self.error_quoted_bracket("error:")
464 class TestTestProtocolServerAddFailure(unittest.TestCase):
467 self.client = ExtendedTestResult()
468 self.protocol = subunit.TestProtocolServer(self.client)
469 self.protocol.lineReceived(_b("test mcdonalds farm\n"))
470 self.test = subunit.RemotedTestCase("mcdonalds farm")
472 def assertFailure(self, details):
474 ('startTest', self.test),
475 ('addFailure', self.test, details),
476 ('stopTest', self.test),
477 ], self.client._events)
479 def simple_failure_keyword(self, keyword):
480 self.protocol.lineReceived(_b("%s mcdonalds farm\n" % keyword))
482 self.assertFailure(details)
484 def test_simple_failure(self):
485 self.simple_failure_keyword("failure")
487 def test_simple_failure_colon(self):
488 self.simple_failure_keyword("failure:")
490 def test_failure_empty_message(self):
491 self.protocol.lineReceived(_b("failure mcdonalds farm [\n"))
492 self.protocol.lineReceived(_b("]\n"))
494 details['traceback'] = Content(ContentType("text", "x-traceback",
495 {'charset': 'utf8'}), lambda:[_b("")])
496 self.assertFailure(details)
498 def failure_quoted_bracket(self, keyword):
499 self.protocol.lineReceived(_b("%s mcdonalds farm [\n" % keyword))
500 self.protocol.lineReceived(_b(" ]\n"))
501 self.protocol.lineReceived(_b("]\n"))
503 details['traceback'] = Content(ContentType("text", "x-traceback",
504 {'charset': 'utf8'}), lambda:[_b("]\n")])
505 self.assertFailure(details)
507 def test_failure_quoted_bracket(self):
508 self.failure_quoted_bracket("failure")
510 def test_failure_colon_quoted_bracket(self):
511 self.failure_quoted_bracket("failure:")
514 class TestTestProtocolServerAddxFail(unittest.TestCase):
515 """Tests for the xfail keyword.
517 In Python this can thunk through to Success due to stdlib limitations (see
521 def capture_expected_failure(self, test, err):
522 self._events.append((test, err))
524 def setup_python26(self):
525 """Setup a test object ready to be xfailed and thunk to success."""
526 self.client = Python26TestResult()
527 self.setup_protocol()
529 def setup_python27(self):
530 """Setup a test object ready to be xfailed."""
531 self.client = Python27TestResult()
532 self.setup_protocol()
534 def setup_python_ex(self):
535 """Setup a test object ready to be xfailed with details."""
536 self.client = ExtendedTestResult()
537 self.setup_protocol()
539 def setup_protocol(self):
540 """Setup the protocol based on self.client."""
541 self.protocol = subunit.TestProtocolServer(self.client)
542 self.protocol.lineReceived(_b("test mcdonalds farm\n"))
543 self.test = self.client._events[-1][-1]
545 def simple_xfail_keyword(self, keyword, as_success):
546 self.protocol.lineReceived(_b("%s mcdonalds farm\n" % keyword))
547 self.check_success_or_xfail(as_success)
549 def check_success_or_xfail(self, as_success, error_message=None):
552 ('startTest', self.test),
553 ('addSuccess', self.test),
554 ('stopTest', self.test),
555 ], self.client._events)
558 if error_message is not None:
559 details['traceback'] = Content(
560 ContentType("text", "x-traceback", {'charset': 'utf8'}),
561 lambda:[_b(error_message)])
562 if isinstance(self.client, ExtendedTestResult):
565 if error_message is not None:
566 value = subunit.RemoteError(details_to_str(details))
568 value = subunit.RemoteError()
570 ('startTest', self.test),
571 ('addExpectedFailure', self.test, value),
572 ('stopTest', self.test),
573 ], self.client._events)
575 def test_simple_xfail(self):
576 self.setup_python26()
577 self.simple_xfail_keyword("xfail", True)
578 self.setup_python27()
579 self.simple_xfail_keyword("xfail", False)
580 self.setup_python_ex()
581 self.simple_xfail_keyword("xfail", False)
583 def test_simple_xfail_colon(self):
584 self.setup_python26()
585 self.simple_xfail_keyword("xfail:", True)
586 self.setup_python27()
587 self.simple_xfail_keyword("xfail:", False)
588 self.setup_python_ex()
589 self.simple_xfail_keyword("xfail:", False)
591 def test_xfail_empty_message(self):
592 self.setup_python26()
593 self.empty_message(True)
594 self.setup_python27()
595 self.empty_message(False)
596 self.setup_python_ex()
597 self.empty_message(False, error_message="")
599 def empty_message(self, as_success, error_message="\n"):
600 self.protocol.lineReceived(_b("xfail mcdonalds farm [\n"))
601 self.protocol.lineReceived(_b("]\n"))
602 self.check_success_or_xfail(as_success, error_message)
604 def xfail_quoted_bracket(self, keyword, as_success):
605 # This tests it is accepted, but cannot test it is used today, because
606 # of not having a way to expose it in Python so far.
607 self.protocol.lineReceived(_b("%s mcdonalds farm [\n" % keyword))
608 self.protocol.lineReceived(_b(" ]\n"))
609 self.protocol.lineReceived(_b("]\n"))
610 self.check_success_or_xfail(as_success, "]\n")
612 def test_xfail_quoted_bracket(self):
613 self.setup_python26()
614 self.xfail_quoted_bracket("xfail", True)
615 self.setup_python27()
616 self.xfail_quoted_bracket("xfail", False)
617 self.setup_python_ex()
618 self.xfail_quoted_bracket("xfail", False)
620 def test_xfail_colon_quoted_bracket(self):
621 self.setup_python26()
622 self.xfail_quoted_bracket("xfail:", True)
623 self.setup_python27()
624 self.xfail_quoted_bracket("xfail:", False)
625 self.setup_python_ex()
626 self.xfail_quoted_bracket("xfail:", False)
629 class TestTestProtocolServerAddunexpectedSuccess(TestCase):
630 """Tests for the uxsuccess keyword."""
632 def capture_expected_failure(self, test, err):
633 self._events.append((test, err))
635 def setup_python26(self):
636 """Setup a test object ready to be xfailed and thunk to success."""
637 self.client = Python26TestResult()
638 self.setup_protocol()
640 def setup_python27(self):
641 """Setup a test object ready to be xfailed."""
642 self.client = Python27TestResult()
643 self.setup_protocol()
645 def setup_python_ex(self):
646 """Setup a test object ready to be xfailed with details."""
647 self.client = ExtendedTestResult()
648 self.setup_protocol()
650 def setup_protocol(self):
651 """Setup the protocol based on self.client."""
652 self.protocol = subunit.TestProtocolServer(self.client)
653 self.protocol.lineReceived(_b("test mcdonalds farm\n"))
654 self.test = self.client._events[-1][-1]
656 def simple_uxsuccess_keyword(self, keyword, as_fail):
657 self.protocol.lineReceived(_b("%s mcdonalds farm\n" % keyword))
658 self.check_fail_or_uxsuccess(as_fail)
660 def check_fail_or_uxsuccess(self, as_fail, error_message=None):
662 if error_message is not None:
663 details['traceback'] = Content(
664 ContentType("text", "x-traceback", {'charset': 'utf8'}),
665 lambda:[_b(error_message)])
666 if isinstance(self.client, ExtendedTestResult):
671 self.client._events[1] = self.client._events[1][:2]
672 # The value is generated within the extended to original decorator:
673 # todo use the testtools matcher to check on this.
675 ('startTest', self.test),
676 ('addFailure', self.test),
677 ('stopTest', self.test),
678 ], self.client._events)
681 ('startTest', self.test),
682 ('addUnexpectedSuccess', self.test, value),
683 ('stopTest', self.test),
684 ], self.client._events)
687 ('startTest', self.test),
688 ('addUnexpectedSuccess', self.test),
689 ('stopTest', self.test),
690 ], self.client._events)
692 def test_simple_uxsuccess(self):
693 self.setup_python26()
694 self.simple_uxsuccess_keyword("uxsuccess", True)
695 self.setup_python27()
696 self.simple_uxsuccess_keyword("uxsuccess", False)
697 self.setup_python_ex()
698 self.simple_uxsuccess_keyword("uxsuccess", False)
700 def test_simple_uxsuccess_colon(self):
701 self.setup_python26()
702 self.simple_uxsuccess_keyword("uxsuccess:", True)
703 self.setup_python27()
704 self.simple_uxsuccess_keyword("uxsuccess:", False)
705 self.setup_python_ex()
706 self.simple_uxsuccess_keyword("uxsuccess:", False)
708 def test_uxsuccess_empty_message(self):
709 self.setup_python26()
710 self.empty_message(True)
711 self.setup_python27()
712 self.empty_message(False)
713 self.setup_python_ex()
714 self.empty_message(False, error_message="")
716 def empty_message(self, as_fail, error_message="\n"):
717 self.protocol.lineReceived(_b("uxsuccess mcdonalds farm [\n"))
718 self.protocol.lineReceived(_b("]\n"))
719 self.check_fail_or_uxsuccess(as_fail, error_message)
721 def uxsuccess_quoted_bracket(self, keyword, as_fail):
722 self.protocol.lineReceived(_b("%s mcdonalds farm [\n" % keyword))
723 self.protocol.lineReceived(_b(" ]\n"))
724 self.protocol.lineReceived(_b("]\n"))
725 self.check_fail_or_uxsuccess(as_fail, "]\n")
727 def test_uxsuccess_quoted_bracket(self):
728 self.setup_python26()
729 self.uxsuccess_quoted_bracket("uxsuccess", True)
730 self.setup_python27()
731 self.uxsuccess_quoted_bracket("uxsuccess", False)
732 self.setup_python_ex()
733 self.uxsuccess_quoted_bracket("uxsuccess", False)
735 def test_uxsuccess_colon_quoted_bracket(self):
736 self.setup_python26()
737 self.uxsuccess_quoted_bracket("uxsuccess:", True)
738 self.setup_python27()
739 self.uxsuccess_quoted_bracket("uxsuccess:", False)
740 self.setup_python_ex()
741 self.uxsuccess_quoted_bracket("uxsuccess:", False)
744 class TestTestProtocolServerAddSkip(unittest.TestCase):
745 """Tests for the skip keyword.
747 In Python this meets the testtools extended TestResult contract.
748 (See https://launchpad.net/testtools).
752 """Setup a test object ready to be skipped."""
753 self.client = ExtendedTestResult()
754 self.protocol = subunit.TestProtocolServer(self.client)
755 self.protocol.lineReceived(_b("test mcdonalds farm\n"))
756 self.test = self.client._events[-1][-1]
758 def assertSkip(self, reason):
760 if reason is not None:
761 details['reason'] = Content(
762 ContentType("text", "plain"), lambda:[reason])
764 ('startTest', self.test),
765 ('addSkip', self.test, details),
766 ('stopTest', self.test),
767 ], self.client._events)
769 def simple_skip_keyword(self, keyword):
770 self.protocol.lineReceived(_b("%s mcdonalds farm\n" % keyword))
771 self.assertSkip(None)
773 def test_simple_skip(self):
774 self.simple_skip_keyword("skip")
776 def test_simple_skip_colon(self):
777 self.simple_skip_keyword("skip:")
779 def test_skip_empty_message(self):
780 self.protocol.lineReceived(_b("skip mcdonalds farm [\n"))
781 self.protocol.lineReceived(_b("]\n"))
782 self.assertSkip(_b(""))
784 def skip_quoted_bracket(self, keyword):
785 # This tests it is accepted, but cannot test it is used today, because
786 # of not having a way to expose it in Python so far.
787 self.protocol.lineReceived(_b("%s mcdonalds farm [\n" % keyword))
788 self.protocol.lineReceived(_b(" ]\n"))
789 self.protocol.lineReceived(_b("]\n"))
790 self.assertSkip(_b("]\n"))
792 def test_skip_quoted_bracket(self):
793 self.skip_quoted_bracket("skip")
795 def test_skip_colon_quoted_bracket(self):
796 self.skip_quoted_bracket("skip:")
799 class TestTestProtocolServerAddSuccess(unittest.TestCase):
802 self.client = ExtendedTestResult()
803 self.protocol = subunit.TestProtocolServer(self.client)
804 self.protocol.lineReceived(_b("test mcdonalds farm\n"))
805 self.test = subunit.RemotedTestCase("mcdonalds farm")
807 def simple_success_keyword(self, keyword):
808 self.protocol.lineReceived(_b("%s mcdonalds farm\n" % keyword))
810 ('startTest', self.test),
811 ('addSuccess', self.test),
812 ('stopTest', self.test),
813 ], self.client._events)
815 def test_simple_success(self):
816 self.simple_success_keyword("successful")
818 def test_simple_success_colon(self):
819 self.simple_success_keyword("successful:")
821 def assertSuccess(self, details):
823 ('startTest', self.test),
824 ('addSuccess', self.test, details),
825 ('stopTest', self.test),
826 ], self.client._events)
828 def test_success_empty_message(self):
829 self.protocol.lineReceived(_b("success mcdonalds farm [\n"))
830 self.protocol.lineReceived(_b("]\n"))
832 details['message'] = Content(ContentType("text", "plain"),
834 self.assertSuccess(details)
836 def success_quoted_bracket(self, keyword):
837 # This tests it is accepted, but cannot test it is used today, because
838 # of not having a way to expose it in Python so far.
839 self.protocol.lineReceived(_b("%s mcdonalds farm [\n" % keyword))
840 self.protocol.lineReceived(_b(" ]\n"))
841 self.protocol.lineReceived(_b("]\n"))
843 details['message'] = Content(ContentType("text", "plain"),
845 self.assertSuccess(details)
847 def test_success_quoted_bracket(self):
848 self.success_quoted_bracket("success")
850 def test_success_colon_quoted_bracket(self):
851 self.success_quoted_bracket("success:")
854 class TestTestProtocolServerProgress(unittest.TestCase):
855 """Test receipt of progress: directives."""
857 def test_progress_accepted_stdlib(self):
858 self.result = Python26TestResult()
859 self.stream = BytesIO()
860 self.protocol = subunit.TestProtocolServer(self.result,
862 self.protocol.lineReceived(_b("progress: 23"))
863 self.protocol.lineReceived(_b("progress: -2"))
864 self.protocol.lineReceived(_b("progress: +4"))
865 self.assertEqual(_b(""), self.stream.getvalue())
867 def test_progress_accepted_extended(self):
868 # With a progress capable TestResult, progress events are emitted.
869 self.result = ExtendedTestResult()
870 self.stream = BytesIO()
871 self.protocol = subunit.TestProtocolServer(self.result,
873 self.protocol.lineReceived(_b("progress: 23"))
874 self.protocol.lineReceived(_b("progress: push"))
875 self.protocol.lineReceived(_b("progress: -2"))
876 self.protocol.lineReceived(_b("progress: pop"))
877 self.protocol.lineReceived(_b("progress: +4"))
878 self.assertEqual(_b(""), self.stream.getvalue())
880 ('progress', 23, subunit.PROGRESS_SET),
881 ('progress', None, subunit.PROGRESS_PUSH),
882 ('progress', -2, subunit.PROGRESS_CUR),
883 ('progress', None, subunit.PROGRESS_POP),
884 ('progress', 4, subunit.PROGRESS_CUR),
885 ], self.result._events)
888 class TestTestProtocolServerStreamTags(unittest.TestCase):
889 """Test managing tags on the protocol level."""
892 self.client = ExtendedTestResult()
893 self.protocol = subunit.TestProtocolServer(self.client)
895 def test_initial_tags(self):
896 self.protocol.lineReceived(_b("tags: foo bar:baz quux\n"))
898 ('tags', set(["foo", "bar:baz", "quux"]), set()),
899 ], self.client._events)
901 def test_minus_removes_tags(self):
902 self.protocol.lineReceived(_b("tags: -bar quux\n"))
904 ('tags', set(["quux"]), set(["bar"])),
905 ], self.client._events)
907 def test_tags_do_not_get_set_on_test(self):
908 self.protocol.lineReceived(_b("test mcdonalds farm\n"))
909 test = self.client._events[0][-1]
910 self.assertEqual(None, getattr(test, 'tags', None))
912 def test_tags_do_not_get_set_on_global_tags(self):
913 self.protocol.lineReceived(_b("tags: foo bar\n"))
914 self.protocol.lineReceived(_b("test mcdonalds farm\n"))
915 test = self.client._events[-1][-1]
916 self.assertEqual(None, getattr(test, 'tags', None))
918 def test_tags_get_set_on_test_tags(self):
919 self.protocol.lineReceived(_b("test mcdonalds farm\n"))
920 test = self.client._events[-1][-1]
921 self.protocol.lineReceived(_b("tags: foo bar\n"))
922 self.protocol.lineReceived(_b("success mcdonalds farm\n"))
923 self.assertEqual(None, getattr(test, 'tags', None))
926 class TestTestProtocolServerStreamTime(unittest.TestCase):
927 """Test managing time information at the protocol level."""
929 def test_time_accepted_stdlib(self):
930 self.result = Python26TestResult()
931 self.stream = BytesIO()
932 self.protocol = subunit.TestProtocolServer(self.result,
934 self.protocol.lineReceived(_b("time: 2001-12-12 12:59:59Z\n"))
935 self.assertEqual(_b(""), self.stream.getvalue())
937 def test_time_accepted_extended(self):
938 self.result = ExtendedTestResult()
939 self.stream = BytesIO()
940 self.protocol = subunit.TestProtocolServer(self.result,
942 self.protocol.lineReceived(_b("time: 2001-12-12 12:59:59Z\n"))
943 self.assertEqual(_b(""), self.stream.getvalue())
945 ('time', datetime.datetime(2001, 12, 12, 12, 59, 59, 0,
947 ], self.result._events)
950 class TestRemotedTestCase(unittest.TestCase):
952 def test_simple(self):
953 test = subunit.RemotedTestCase("A test description")
954 self.assertRaises(NotImplementedError, test.setUp)
955 self.assertRaises(NotImplementedError, test.tearDown)
956 self.assertEqual("A test description",
957 test.shortDescription())
958 self.assertEqual("A test description",
960 self.assertEqual("A test description (subunit.RemotedTestCase)", "%s" % test)
961 self.assertEqual("<subunit.RemotedTestCase description="
962 "'A test description'>", "%r" % test)
963 result = unittest.TestResult()
965 self.assertEqual([(test, _remote_exception_str + ": "
966 "Cannot run RemotedTestCases.\n\n")],
968 self.assertEqual(1, result.testsRun)
969 another_test = subunit.RemotedTestCase("A test description")
970 self.assertEqual(test, another_test)
971 different_test = subunit.RemotedTestCase("ofo")
972 self.assertNotEqual(test, different_test)
973 self.assertNotEqual(another_test, different_test)
976 class TestRemoteError(unittest.TestCase):
979 error = subunit.RemoteError(_u("Something went wrong"))
980 another_error = subunit.RemoteError(_u("Something went wrong"))
981 different_error = subunit.RemoteError(_u("boo!"))
982 self.assertEqual(error, another_error)
983 self.assertNotEqual(error, different_error)
984 self.assertNotEqual(different_error, another_error)
986 def test_empty_constructor(self):
987 self.assertEqual(subunit.RemoteError(), subunit.RemoteError(_u("")))
990 class TestExecTestCase(unittest.TestCase):
992 class SampleExecTestCase(subunit.ExecTestCase):
994 def test_sample_method(self):
995 """sample-script.py"""
996 # the sample script runs three tests, one each
997 # that fails, errors and succeeds
999 def test_sample_method_args(self):
1000 """sample-script.py foo"""
1001 # sample that will run just one test.
1003 def test_construct(self):
1004 test = self.SampleExecTestCase("test_sample_method")
1005 self.assertEqual(test.script,
1006 subunit.join_dir(__file__, 'sample-script.py'))
1008 def test_args(self):
1009 result = unittest.TestResult()
1010 test = self.SampleExecTestCase("test_sample_method_args")
1012 self.assertEqual(1, result.testsRun)
1015 result = ExtendedTestResult()
1016 test = self.SampleExecTestCase("test_sample_method")
1018 mcdonald = subunit.RemotedTestCase("old mcdonald")
1019 bing = subunit.RemotedTestCase("bing crosby")
1021 bing_details['traceback'] = Content(ContentType("text", "x-traceback",
1022 {'charset': 'utf8'}), lambda:[_b("foo.c:53:ERROR invalid state\n")])
1023 an_error = subunit.RemotedTestCase("an error")
1026 ('startTest', mcdonald),
1027 ('addSuccess', mcdonald),
1028 ('stopTest', mcdonald),
1029 ('startTest', bing),
1030 ('addFailure', bing, bing_details),
1032 ('startTest', an_error),
1033 ('addError', an_error, error_details),
1034 ('stopTest', an_error),
1037 def test_debug(self):
1038 test = self.SampleExecTestCase("test_sample_method")
1041 def test_count_test_cases(self):
1042 """TODO run the child process and count responses to determine the count."""
1044 def test_join_dir(self):
1045 sibling = subunit.join_dir(__file__, 'foo')
1046 filedir = os.path.abspath(os.path.dirname(__file__))
1047 expected = os.path.join(filedir, 'foo')
1048 self.assertEqual(sibling, expected)
1051 class DoExecTestCase(subunit.ExecTestCase):
1053 def test_working_script(self):
1054 """sample-two-script.py"""
1057 class TestIsolatedTestCase(TestCase):
1059 class SampleIsolatedTestCase(subunit.IsolatedTestCase):
1066 TestIsolatedTestCase.SampleIsolatedTestCase.SETUP = True
1069 TestIsolatedTestCase.SampleIsolatedTestCase.TEARDOWN = True
1071 def test_sets_global_state(self):
1072 TestIsolatedTestCase.SampleIsolatedTestCase.TEST = True
1075 def test_construct(self):
1076 self.SampleIsolatedTestCase("test_sets_global_state")
1078 @skipIf(os.name != "posix", "Need a posix system for forking tests")
1080 result = unittest.TestResult()
1081 test = self.SampleIsolatedTestCase("test_sets_global_state")
1083 self.assertEqual(result.testsRun, 1)
1084 self.assertEqual(self.SampleIsolatedTestCase.SETUP, False)
1085 self.assertEqual(self.SampleIsolatedTestCase.TEARDOWN, False)
1086 self.assertEqual(self.SampleIsolatedTestCase.TEST, False)
1088 def test_debug(self):
1090 #test = self.SampleExecTestCase("test_sample_method")
1094 class TestIsolatedTestSuite(TestCase):
1096 class SampleTestToIsolate(unittest.TestCase):
1103 TestIsolatedTestSuite.SampleTestToIsolate.SETUP = True
1106 TestIsolatedTestSuite.SampleTestToIsolate.TEARDOWN = True
1108 def test_sets_global_state(self):
1109 TestIsolatedTestSuite.SampleTestToIsolate.TEST = True
1112 def test_construct(self):
1113 subunit.IsolatedTestSuite()
1115 @skipIf(os.name != "posix", "Need a posix system for forking tests")
1117 result = unittest.TestResult()
1118 suite = subunit.IsolatedTestSuite()
1119 sub_suite = unittest.TestSuite()
1120 sub_suite.addTest(self.SampleTestToIsolate("test_sets_global_state"))
1121 sub_suite.addTest(self.SampleTestToIsolate("test_sets_global_state"))
1122 suite.addTest(sub_suite)
1123 suite.addTest(self.SampleTestToIsolate("test_sets_global_state"))
1125 self.assertEqual(result.testsRun, 3)
1126 self.assertEqual(self.SampleTestToIsolate.SETUP, False)
1127 self.assertEqual(self.SampleTestToIsolate.TEARDOWN, False)
1128 self.assertEqual(self.SampleTestToIsolate.TEST, False)
1131 class TestTestProtocolClient(unittest.TestCase):
1135 self.protocol = subunit.TestProtocolClient(self.io)
1136 self.unicode_test = PlaceHolder(_u('\u2603'))
1137 self.test = TestTestProtocolClient("test_start_test")
1138 self.sample_details = {'something':Content(
1139 ContentType('text', 'plain'), lambda:[_b('serialised\nform')])}
1140 self.sample_tb_details = dict(self.sample_details)
1141 self.sample_tb_details['traceback'] = TracebackContent(
1142 subunit.RemoteError(_u("boo qux")), self.test)
1144 def test_start_test(self):
1145 """Test startTest on a TestProtocolClient."""
1146 self.protocol.startTest(self.test)
1147 self.assertEqual(self.io.getvalue(), _b("test: %s\n" % self.test.id()))
1149 def test_start_test_unicode_id(self):
1150 """Test startTest on a TestProtocolClient."""
1151 self.protocol.startTest(self.unicode_test)
1152 expected = _b("test: ") + _u('\u2603').encode('utf8') + _b("\n")
1153 self.assertEqual(expected, self.io.getvalue())
1155 def test_stop_test(self):
1156 # stopTest doesn't output anything.
1157 self.protocol.stopTest(self.test)
1158 self.assertEqual(self.io.getvalue(), _b(""))
1160 def test_add_success(self):
1161 """Test addSuccess on a TestProtocolClient."""
1162 self.protocol.addSuccess(self.test)
1164 self.io.getvalue(), _b("successful: %s\n" % self.test.id()))
1166 def test_add_outcome_unicode_id(self):
1167 """Test addSuccess on a TestProtocolClient."""
1168 self.protocol.addSuccess(self.unicode_test)
1169 expected = _b("successful: ") + _u('\u2603').encode('utf8') + _b("\n")
1170 self.assertEqual(expected, self.io.getvalue())
1172 def test_add_success_details(self):
1173 """Test addSuccess on a TestProtocolClient with details."""
1174 self.protocol.addSuccess(self.test, details=self.sample_details)
1176 self.io.getvalue(), _b("successful: %s [ multipart\n"
1177 "Content-Type: text/plain\n"
1179 "F\r\nserialised\nform0\r\n]\n" % self.test.id()))
1181 def test_add_failure(self):
1182 """Test addFailure on a TestProtocolClient."""
1183 self.protocol.addFailure(
1184 self.test, subunit.RemoteError(_u("boo qux")))
1187 _b(('failure: %s [\n' + _remote_exception_str + ': boo qux\n]\n')
1190 def test_add_failure_details(self):
1191 """Test addFailure on a TestProtocolClient with details."""
1192 self.protocol.addFailure(
1193 self.test, details=self.sample_tb_details)
1196 _b(("failure: %s [ multipart\n"
1197 "Content-Type: text/plain\n"
1199 "F\r\nserialised\nform0\r\n"
1200 "Content-Type: text/x-traceback;charset=utf8,language=python\n"
1201 "traceback\n" + _remote_exception_str_chunked + ": boo qux\n0\r\n"
1202 "]\n") % self.test.id()))
1204 def test_add_error(self):
1205 """Test stopTest on a TestProtocolClient."""
1206 self.protocol.addError(
1207 self.test, subunit.RemoteError(_u("phwoar crikey")))
1210 _b(('error: %s [\n' +
1211 _remote_exception_str + ": phwoar crikey\n"
1212 "]\n") % self.test.id()))
1214 def test_add_error_details(self):
1215 """Test stopTest on a TestProtocolClient with details."""
1216 self.protocol.addError(
1217 self.test, details=self.sample_tb_details)
1220 _b(("error: %s [ multipart\n"
1221 "Content-Type: text/plain\n"
1223 "F\r\nserialised\nform0\r\n"
1224 "Content-Type: text/x-traceback;charset=utf8,language=python\n"
1225 "traceback\n" + _remote_exception_str_chunked + ": boo qux\n0\r\n"
1226 "]\n") % self.test.id()))
1228 def test_add_expected_failure(self):
1229 """Test addExpectedFailure on a TestProtocolClient."""
1230 self.protocol.addExpectedFailure(
1231 self.test, subunit.RemoteError(_u("phwoar crikey")))
1234 _b(('xfail: %s [\n' +
1235 _remote_exception_str + ": phwoar crikey\n"
1236 "]\n") % self.test.id()))
1238 def test_add_expected_failure_details(self):
1239 """Test addExpectedFailure on a TestProtocolClient with details."""
1240 self.protocol.addExpectedFailure(
1241 self.test, details=self.sample_tb_details)
1244 _b(("xfail: %s [ multipart\n"
1245 "Content-Type: text/plain\n"
1247 "F\r\nserialised\nform0\r\n"
1248 "Content-Type: text/x-traceback;charset=utf8,language=python\n"
1249 "traceback\n" + _remote_exception_str_chunked + ": boo qux\n0\r\n"
1250 "]\n") % self.test.id()))
1253 def test_add_skip(self):
1254 """Test addSkip on a TestProtocolClient."""
1255 self.protocol.addSkip(
1256 self.test, "Has it really?")
1259 _b('skip: %s [\nHas it really?\n]\n' % self.test.id()))
1261 def test_add_skip_details(self):
1262 """Test addSkip on a TestProtocolClient with details."""
1263 details = {'reason':Content(
1264 ContentType('text', 'plain'), lambda:[_b('Has it really?')])}
1265 self.protocol.addSkip(self.test, details=details)
1268 _b("skip: %s [ multipart\n"
1269 "Content-Type: text/plain\n"
1271 "E\r\nHas it really?0\r\n"
1272 "]\n" % self.test.id()))
1274 def test_progress_set(self):
1275 self.protocol.progress(23, subunit.PROGRESS_SET)
1276 self.assertEqual(self.io.getvalue(), _b('progress: 23\n'))
1278 def test_progress_neg_cur(self):
1279 self.protocol.progress(-23, subunit.PROGRESS_CUR)
1280 self.assertEqual(self.io.getvalue(), _b('progress: -23\n'))
1282 def test_progress_pos_cur(self):
1283 self.protocol.progress(23, subunit.PROGRESS_CUR)
1284 self.assertEqual(self.io.getvalue(), _b('progress: +23\n'))
1286 def test_progress_pop(self):
1287 self.protocol.progress(1234, subunit.PROGRESS_POP)
1288 self.assertEqual(self.io.getvalue(), _b('progress: pop\n'))
1290 def test_progress_push(self):
1291 self.protocol.progress(1234, subunit.PROGRESS_PUSH)
1292 self.assertEqual(self.io.getvalue(), _b('progress: push\n'))
1294 def test_time(self):
1295 # Calling time() outputs a time signal immediately.
1297 datetime.datetime(2009,10,11,12,13,14,15, iso8601.Utc()))
1299 _b("time: 2009-10-11 12:13:14.000015Z\n"),
1302 def test_add_unexpected_success(self):
1303 """Test addUnexpectedSuccess on a TestProtocolClient."""
1304 self.protocol.addUnexpectedSuccess(self.test)
1306 self.io.getvalue(), _b("uxsuccess: %s\n" % self.test.id()))
1308 def test_add_unexpected_success_details(self):
1309 """Test addUnexpectedSuccess on a TestProtocolClient with details."""
1310 self.protocol.addUnexpectedSuccess(self.test, details=self.sample_details)
1312 self.io.getvalue(), _b("uxsuccess: %s [ multipart\n"
1313 "Content-Type: text/plain\n"
1315 "F\r\nserialised\nform0\r\n]\n" % self.test.id()))
1317 def test_tags_empty(self):
1318 self.protocol.tags(set(), set())
1319 self.assertEqual(_b(""), self.io.getvalue())
1321 def test_tags_add(self):
1322 self.protocol.tags(set(['foo']), set())
1323 self.assertEqual(_b("tags: foo\n"), self.io.getvalue())
1325 def test_tags_both(self):
1326 self.protocol.tags(set(['quux']), set(['bar']))
1327 self.assertEqual(_b("tags: quux -bar\n"), self.io.getvalue())
1329 def test_tags_gone(self):
1330 self.protocol.tags(set(), set(['bar']))
1331 self.assertEqual(_b("tags: -bar\n"), self.io.getvalue())
1335 loader = subunit.tests.TestUtil.TestLoader()
1336 result = loader.loadTestsFromName(__name__)