Hook addFailure to to details.
[third_party/subunit] / python / subunit / tests / test_test_protocol.py
1 #
2 #  subunit: extensions to Python unittest to get test results from subprocesses.
3 #  Copyright (C) 2005  Robert Collins <robertc@robertcollins.net>
4 #
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.
9 #  
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.
15 #
16
17 import datetime
18 import unittest
19 from StringIO import StringIO
20 import os
21 import sys
22
23 import subunit
24 from subunit.content import Content, TracebackContent
25 from subunit.content_type import ContentType
26 import subunit.iso8601 as iso8601
27
28
29 class MockTestProtocolServerClient(object):
30     """A mock protocol server client to test callbacks.
31     
32     Note that this is deliberately not Python 2.7 complete, to allow
33     testing compatibility - we need a TestResult that will not have new methods
34     like addExpectedFailure.
35     """
36
37     def __init__(self):
38         self.end_calls = []
39         self.error_calls = []
40         self.failure_calls = []
41         self.skip_calls = []
42         self.start_calls = []
43         self.success_calls = []
44         self.progress_calls = []
45         self._time = None
46         super(MockTestProtocolServerClient, self).__init__()
47
48     def addError(self, test, error):
49         self.error_calls.append((test, error))
50
51     def addFailure(self, test, error):
52         self.failure_calls.append((test, error))
53
54     def addSkip(self, test, reason):
55         self.skip_calls.append((test, reason))
56
57     def addSuccess(self, test):
58         self.success_calls.append(test)
59
60     def stopTest(self, test):
61         self.end_calls.append(test)
62
63     def startTest(self, test):
64         self.start_calls.append(test)
65
66     def progress(self, offset, whence):
67         self.progress_calls.append((offset, whence))
68
69     def time(self, time):
70         self._time = time
71
72
73 class MockExtendedTestProtocolServerClient(MockTestProtocolServerClient):
74     """An extended TestResult for testing which implements tags() etc."""
75
76     def __init__(self):
77         MockTestProtocolServerClient.__init__(self)
78         self.new_tags = set()
79         self.gone_tags = set()
80
81     def tags(self, new_tags, gone_tags):
82         self.new_tags = new_tags
83         self.gone_tags = gone_tags
84
85
86 class TestMockTestProtocolServer(unittest.TestCase):
87
88     def test_start_test(self):
89         protocol = MockTestProtocolServerClient()
90         protocol.startTest(subunit.RemotedTestCase("test old mcdonald"))
91         self.assertEqual(protocol.start_calls,
92                          [subunit.RemotedTestCase("test old mcdonald")])
93         self.assertEqual(protocol.end_calls, [])
94         self.assertEqual(protocol.error_calls, [])
95         self.assertEqual(protocol.failure_calls, [])
96         self.assertEqual(protocol.success_calls, [])
97
98     def test_add_error(self):
99         protocol = MockTestProtocolServerClient()
100         protocol.addError(subunit.RemotedTestCase("old mcdonald"),
101                           subunit.RemoteError("omg it works"))
102         self.assertEqual(protocol.start_calls, [])
103         self.assertEqual(protocol.end_calls, [])
104         self.assertEqual(protocol.error_calls, [(
105                             subunit.RemotedTestCase("old mcdonald"),
106                             subunit.RemoteError("omg it works"))])
107         self.assertEqual(protocol.failure_calls, [])
108         self.assertEqual(protocol.success_calls, [])
109
110     def test_add_failure(self):
111         protocol = MockTestProtocolServerClient()
112         protocol.addFailure(subunit.RemotedTestCase("old mcdonald"),
113                             subunit.RemoteError("omg it works"))
114         self.assertEqual(protocol.start_calls, [])
115         self.assertEqual(protocol.end_calls, [])
116         self.assertEqual(protocol.error_calls, [])
117         self.assertEqual(protocol.failure_calls, [
118                             (subunit.RemotedTestCase("old mcdonald"),
119                              subunit.RemoteError("omg it works"))])
120         self.assertEqual(protocol.success_calls, [])
121
122     def test_add_success(self):
123         protocol = MockTestProtocolServerClient()
124         protocol.addSuccess(subunit.RemotedTestCase("test old mcdonald"))
125         self.assertEqual(protocol.start_calls, [])
126         self.assertEqual(protocol.end_calls, [])
127         self.assertEqual(protocol.error_calls, [])
128         self.assertEqual(protocol.failure_calls, [])
129         self.assertEqual(protocol.success_calls,
130                          [subunit.RemotedTestCase("test old mcdonald")])
131
132     def test_end_test(self):
133         protocol = MockTestProtocolServerClient()
134         protocol.stopTest(subunit.RemotedTestCase("test old mcdonald"))
135         self.assertEqual(protocol.end_calls,
136                          [subunit.RemotedTestCase("test old mcdonald")])
137         self.assertEqual(protocol.error_calls, [])
138         self.assertEqual(protocol.failure_calls, [])
139         self.assertEqual(protocol.success_calls, [])
140         self.assertEqual(protocol.start_calls, [])
141
142     def test_progress(self):
143         protocol = MockTestProtocolServerClient()
144         protocol.progress(-1, subunit.PROGRESS_CUR)
145         self.assertEqual(protocol.progress_calls, [(-1, subunit.PROGRESS_CUR)])
146
147
148 class TestTestImports(unittest.TestCase):
149
150     def test_imports(self):
151         from subunit import DiscardStream
152         from subunit import TestProtocolServer
153         from subunit import RemotedTestCase
154         from subunit import RemoteError
155         from subunit import ExecTestCase
156         from subunit import IsolatedTestCase
157         from subunit import TestProtocolClient
158
159
160 class TestDiscardStream(unittest.TestCase):
161
162     def test_write(self):
163         subunit.DiscardStream().write("content")
164
165
166 class TestTestProtocolServerPipe(unittest.TestCase):
167
168     def test_story(self):
169         client = unittest.TestResult()
170         protocol = subunit.TestProtocolServer(client)
171         pipe = StringIO("test old mcdonald\n"
172                         "success old mcdonald\n"
173                         "test bing crosby\n"
174                         "failure bing crosby [\n"
175                         "foo.c:53:ERROR invalid state\n"
176                         "]\n"
177                         "test an error\n"
178                         "error an error\n")
179         protocol.readFrom(pipe)
180         mcdonald = subunit.RemotedTestCase("old mcdonald")
181         bing = subunit.RemotedTestCase("bing crosby")
182         an_error = subunit.RemotedTestCase("an error")
183         self.assertEqual(client.errors,
184                          [(an_error, 'RemoteException: \n\n')])
185         self.assertEqual(
186             client.failures,
187             [(bing, "RemoteException: foo.c:53:ERROR invalid state\n\n")])
188         self.assertEqual(client.testsRun, 3)
189
190
191 class TestTestProtocolServerStartTest(unittest.TestCase):
192
193     def setUp(self):
194         self.client = MockTestProtocolServerClient()
195         self.protocol = subunit.TestProtocolServer(self.client)
196
197     def test_start_test(self):
198         self.protocol.lineReceived("test old mcdonald\n")
199         self.assertEqual(self.client.start_calls,
200                          [subunit.RemotedTestCase("old mcdonald")])
201
202     def test_start_testing(self):
203         self.protocol.lineReceived("testing old mcdonald\n")
204         self.assertEqual(self.client.start_calls,
205                          [subunit.RemotedTestCase("old mcdonald")])
206
207     def test_start_test_colon(self):
208         self.protocol.lineReceived("test: old mcdonald\n")
209         self.assertEqual(self.client.start_calls,
210                          [subunit.RemotedTestCase("old mcdonald")])
211
212     def test_start_testing_colon(self):
213         self.protocol.lineReceived("testing: old mcdonald\n")
214         self.assertEqual(self.client.start_calls,
215                          [subunit.RemotedTestCase("old mcdonald")])
216
217
218 class TestTestProtocolServerPassThrough(unittest.TestCase):
219
220     def setUp(self):
221         self.stdout = StringIO()
222         self.test = subunit.RemotedTestCase("old mcdonald")
223         self.client = MockTestProtocolServerClient()
224         self.protocol = subunit.TestProtocolServer(self.client, self.stdout)
225
226     def keywords_before_test(self):
227         self.protocol.lineReceived("failure a\n")
228         self.protocol.lineReceived("failure: a\n")
229         self.protocol.lineReceived("error a\n")
230         self.protocol.lineReceived("error: a\n")
231         self.protocol.lineReceived("success a\n")
232         self.protocol.lineReceived("success: a\n")
233         self.protocol.lineReceived("successful a\n")
234         self.protocol.lineReceived("successful: a\n")
235         self.protocol.lineReceived("]\n")
236         self.assertEqual(self.stdout.getvalue(), "failure a\n"
237                                                  "failure: a\n"
238                                                  "error a\n"
239                                                  "error: a\n"
240                                                  "success a\n"
241                                                  "success: a\n"
242                                                  "successful a\n"
243                                                  "successful: a\n"
244                                                  "]\n")
245
246     def test_keywords_before_test(self):
247         self.keywords_before_test()
248         self.assertEqual(self.client.start_calls, [])
249         self.assertEqual(self.client.error_calls, [])
250         self.assertEqual(self.client.failure_calls, [])
251         self.assertEqual(self.client.success_calls, [])
252
253     def test_keywords_after_error(self):
254         self.protocol.lineReceived("test old mcdonald\n")
255         self.protocol.lineReceived("error old mcdonald\n")
256         self.keywords_before_test()
257         self.assertEqual(self.client.start_calls, [self.test])
258         self.assertEqual(self.client.end_calls, [self.test])
259         self.assertEqual(self.client.error_calls,
260                          [(self.test, subunit.RemoteError(""))])
261         self.assertEqual(self.client.failure_calls, [])
262         self.assertEqual(self.client.success_calls, [])
263
264     def test_keywords_after_failure(self):
265         self.protocol.lineReceived("test old mcdonald\n")
266         self.protocol.lineReceived("failure old mcdonald\n")
267         self.keywords_before_test()
268         self.assertEqual(self.client.start_calls, [self.test])
269         self.assertEqual(self.client.end_calls, [self.test])
270         self.assertEqual(self.client.error_calls, [])
271         self.assertEqual(self.client.failure_calls,
272                          [(self.test, subunit.RemoteError())])
273         self.assertEqual(self.client.success_calls, [])
274
275     def test_keywords_after_success(self):
276         self.protocol.lineReceived("test old mcdonald\n")
277         self.protocol.lineReceived("success old mcdonald\n")
278         self.keywords_before_test()
279         self.assertEqual(self.client.start_calls, [self.test])
280         self.assertEqual(self.client.end_calls, [self.test])
281         self.assertEqual(self.client.error_calls, [])
282         self.assertEqual(self.client.failure_calls, [])
283         self.assertEqual(self.client.success_calls, [self.test])
284
285     def test_keywords_after_test(self):
286         self.protocol.lineReceived("test old mcdonald\n")
287         self.protocol.lineReceived("test old mcdonald\n")
288         self.protocol.lineReceived("failure a\n")
289         self.protocol.lineReceived("failure: a\n")
290         self.protocol.lineReceived("error a\n")
291         self.protocol.lineReceived("error: a\n")
292         self.protocol.lineReceived("success a\n")
293         self.protocol.lineReceived("success: a\n")
294         self.protocol.lineReceived("successful a\n")
295         self.protocol.lineReceived("successful: a\n")
296         self.protocol.lineReceived("]\n")
297         self.protocol.lineReceived("failure old mcdonald\n")
298         self.assertEqual(self.stdout.getvalue(), "test old mcdonald\n"
299                                                  "failure a\n"
300                                                  "failure: a\n"
301                                                  "error a\n"
302                                                  "error: a\n"
303                                                  "success a\n"
304                                                  "success: a\n"
305                                                  "successful a\n"
306                                                  "successful: a\n"
307                                                  "]\n")
308         self.assertEqual(self.client.start_calls, [self.test])
309         self.assertEqual(self.client.end_calls, [self.test])
310         self.assertEqual(self.client.failure_calls,
311                          [(self.test, subunit.RemoteError())])
312         self.assertEqual(self.client.error_calls, [])
313         self.assertEqual(self.client.success_calls, [])
314
315     def test_keywords_during_failure(self):
316         self.protocol.lineReceived("test old mcdonald\n")
317         self.protocol.lineReceived("failure: old mcdonald [\n")
318         self.protocol.lineReceived("test old mcdonald\n")
319         self.protocol.lineReceived("failure a\n")
320         self.protocol.lineReceived("failure: a\n")
321         self.protocol.lineReceived("error a\n")
322         self.protocol.lineReceived("error: a\n")
323         self.protocol.lineReceived("success a\n")
324         self.protocol.lineReceived("success: a\n")
325         self.protocol.lineReceived("successful a\n")
326         self.protocol.lineReceived("successful: a\n")
327         self.protocol.lineReceived(" ]\n")
328         self.protocol.lineReceived("]\n")
329         self.assertEqual(self.stdout.getvalue(), "")
330         self.assertEqual(self.client.start_calls, [self.test])
331         self.assertEqual(self.client.failure_calls,
332                          [(self.test, subunit.RemoteError("test old mcdonald\n"
333                                                   "failure a\n"
334                                                   "failure: a\n"
335                                                   "error a\n"
336                                                   "error: a\n"
337                                                   "success a\n"
338                                                   "success: a\n"
339                                                   "successful a\n"
340                                                   "successful: a\n"
341                                                   "]\n"))])
342         self.assertEqual(self.client.end_calls, [self.test])
343         self.assertEqual(self.client.error_calls, [])
344         self.assertEqual(self.client.success_calls, [])
345
346     def test_stdout_passthrough(self):
347         """Lines received which cannot be interpreted as any protocol action
348         should be passed through to sys.stdout.
349         """
350         bytes = "randombytes\n"
351         self.protocol.lineReceived(bytes)
352         self.assertEqual(self.stdout.getvalue(), bytes)
353
354
355 class TestTestProtocolServerLostConnection(unittest.TestCase):
356
357     def setUp(self):
358         self.client = MockTestProtocolServerClient()
359         self.protocol = subunit.TestProtocolServer(self.client)
360         self.test = subunit.RemotedTestCase("old mcdonald")
361
362     def test_lost_connection_no_input(self):
363         self.protocol.lostConnection()
364         self.assertEqual(self.client.start_calls, [])
365         self.assertEqual(self.client.error_calls, [])
366         self.assertEqual(self.client.failure_calls, [])
367         self.assertEqual(self.client.success_calls, [])
368
369     def test_lost_connection_after_start(self):
370         self.protocol.lineReceived("test old mcdonald\n")
371         self.protocol.lostConnection()
372         self.assertEqual(self.client.start_calls, [self.test])
373         self.assertEqual(self.client.end_calls, [self.test])
374         self.assertEqual(self.client.error_calls, [
375             (self.test, subunit.RemoteError("lost connection during "
376                                             "test 'old mcdonald'"))])
377         self.assertEqual(self.client.failure_calls, [])
378         self.assertEqual(self.client.success_calls, [])
379
380     def test_lost_connected_after_error(self):
381         self.protocol.lineReceived("test old mcdonald\n")
382         self.protocol.lineReceived("error old mcdonald\n")
383         self.protocol.lostConnection()
384         self.assertEqual(self.client.start_calls, [self.test])
385         self.assertEqual(self.client.failure_calls, [])
386         self.assertEqual(self.client.end_calls, [self.test])
387         self.assertEqual(self.client.error_calls, [
388             (self.test, subunit.RemoteError(""))])
389         self.assertEqual(self.client.success_calls, [])
390
391     def test_lost_connection_during_error(self):
392         self.protocol.lineReceived("test old mcdonald\n")
393         self.protocol.lineReceived("error old mcdonald [\n")
394         self.protocol.lostConnection()
395         self.assertEqual(self.client.start_calls, [self.test])
396         self.assertEqual(self.client.end_calls, [self.test])
397         self.assertEqual(self.client.error_calls, [
398             (self.test, subunit.RemoteError("lost connection during error "
399                                             "report of test 'old mcdonald'"))])
400         self.assertEqual(self.client.failure_calls, [])
401         self.assertEqual(self.client.success_calls, [])
402
403     def test_lost_connected_after_failure(self):
404         self.protocol.lineReceived("test old mcdonald\n")
405         self.protocol.lineReceived("failure old mcdonald\n")
406         self.protocol.lostConnection()
407         test = subunit.RemotedTestCase("old mcdonald")
408         self.assertEqual(self.client.start_calls, [self.test])
409         self.assertEqual(self.client.end_calls, [self.test])
410         self.assertEqual(self.client.error_calls, [])
411         self.assertEqual(self.client.failure_calls,
412                          [(self.test, subunit.RemoteError())])
413         self.assertEqual(self.client.success_calls, [])
414
415     def test_lost_connection_during_failure(self):
416         self.protocol.lineReceived("test old mcdonald\n")
417         self.protocol.lineReceived("failure old mcdonald [\n")
418         self.protocol.lostConnection()
419         self.assertEqual(self.client.start_calls, [self.test])
420         self.assertEqual(self.client.end_calls, [self.test])
421         self.assertEqual(self.client.error_calls,
422                          [(self.test,
423                            subunit.RemoteError("lost connection during "
424                                                "failure report"
425                                                " of test 'old mcdonald'"))])
426         self.assertEqual(self.client.failure_calls, [])
427         self.assertEqual(self.client.success_calls, [])
428
429     def test_lost_connection_after_success(self):
430         self.protocol.lineReceived("test old mcdonald\n")
431         self.protocol.lineReceived("success old mcdonald\n")
432         self.protocol.lostConnection()
433         self.assertEqual(self.client.start_calls, [self.test])
434         self.assertEqual(self.client.end_calls, [self.test])
435         self.assertEqual(self.client.error_calls, [])
436         self.assertEqual(self.client.failure_calls, [])
437         self.assertEqual(self.client.success_calls, [self.test])
438
439     def test_lost_connection_during_skip(self):
440         self.protocol.lineReceived("test old mcdonald\n")
441         self.protocol.lineReceived("skip old mcdonald [\n")
442         self.protocol.lostConnection()
443         self.assertEqual(self.client.start_calls, [self.test])
444         self.assertEqual(self.client.end_calls, [self.test])
445         self.assertEqual(self.client.error_calls, [
446             (self.test, subunit.RemoteError("lost connection during skip "
447                                             "report of test 'old mcdonald'"))])
448         self.assertEqual(self.client.failure_calls, [])
449         self.assertEqual(self.client.success_calls, [])
450
451     def test_lost_connection_during_xfail(self):
452         self.protocol.lineReceived("test old mcdonald\n")
453         self.protocol.lineReceived("xfail old mcdonald [\n")
454         self.protocol.lostConnection()
455         self.assertEqual(self.client.start_calls, [self.test])
456         self.assertEqual(self.client.end_calls, [self.test])
457         self.assertEqual(self.client.error_calls, [
458             (self.test, subunit.RemoteError("lost connection during xfail "
459                                             "report of test 'old mcdonald'"))])
460         self.assertEqual(self.client.failure_calls, [])
461         self.assertEqual(self.client.success_calls, [])
462
463     def test_lost_connection_during_success(self):
464         self.protocol.lineReceived("test old mcdonald\n")
465         self.protocol.lineReceived("success old mcdonald [\n")
466         self.protocol.lostConnection()
467         self.assertEqual(self.client.start_calls, [self.test])
468         self.assertEqual(self.client.end_calls, [self.test])
469         self.assertEqual(self.client.error_calls, [
470             (self.test, subunit.RemoteError("lost connection during success "
471                                             "report of test 'old mcdonald'"))])
472         self.assertEqual(self.client.failure_calls, [])
473         self.assertEqual(self.client.success_calls, [])
474
475
476 class TestTestProtocolServerAddError(unittest.TestCase):
477
478     def setUp(self):
479         self.client = MockTestProtocolServerClient()
480         self.protocol = subunit.TestProtocolServer(self.client)
481         self.protocol.lineReceived("test mcdonalds farm\n")
482         self.test = subunit.RemotedTestCase("mcdonalds farm")
483
484     def simple_error_keyword(self, keyword):
485         self.protocol.lineReceived("%s mcdonalds farm\n" % keyword)
486         self.assertEqual(self.client.start_calls, [self.test])
487         self.assertEqual(self.client.end_calls, [self.test])
488         self.assertEqual(self.client.error_calls, [
489             (self.test, subunit.RemoteError(""))])
490         self.assertEqual(self.client.failure_calls, [])
491
492     def test_simple_error(self):
493         self.simple_error_keyword("error")
494
495     def test_simple_error_colon(self):
496         self.simple_error_keyword("error:")
497
498     def test_error_empty_message(self):
499         self.protocol.lineReceived("error mcdonalds farm [\n")
500         self.protocol.lineReceived("]\n")
501         self.assertEqual(self.client.start_calls, [self.test])
502         self.assertEqual(self.client.end_calls, [self.test])
503         self.assertEqual(self.client.error_calls, [
504             (self.test, subunit.RemoteError(""))])
505         self.assertEqual(self.client.failure_calls, [])
506
507     def error_quoted_bracket(self, keyword):
508         self.protocol.lineReceived("%s mcdonalds farm [\n" % keyword)
509         self.protocol.lineReceived(" ]\n")
510         self.protocol.lineReceived("]\n")
511         self.assertEqual(self.client.start_calls, [self.test])
512         self.assertEqual(self.client.end_calls, [self.test])
513         self.assertEqual(self.client.error_calls, [
514             (self.test, subunit.RemoteError("]\n"))])
515         self.assertEqual(self.client.failure_calls, [])
516
517     def test_error_quoted_bracket(self):
518         self.error_quoted_bracket("error")
519
520     def test_error_colon_quoted_bracket(self):
521         self.error_quoted_bracket("error:")
522
523
524 class TestTestProtocolServerAddFailure(unittest.TestCase):
525
526     def setUp(self):
527         self.client = MockTestProtocolServerClient()
528         self.protocol = subunit.TestProtocolServer(self.client)
529         self.protocol.lineReceived("test mcdonalds farm\n")
530         self.test = subunit.RemotedTestCase("mcdonalds farm")
531
532     def simple_failure_keyword(self, keyword):
533         self.protocol.lineReceived("%s mcdonalds farm\n" % keyword)
534         self.assertEqual(self.client.start_calls, [self.test])
535         self.assertEqual(self.client.end_calls, [self.test])
536         self.assertEqual(self.client.error_calls, [])
537         self.assertEqual(self.client.failure_calls,
538                          [(self.test, subunit.RemoteError())])
539
540     def test_simple_failure(self):
541         self.simple_failure_keyword("failure")
542
543     def test_simple_failure_colon(self):
544         self.simple_failure_keyword("failure:")
545
546     def test_failure_empty_message(self):
547         self.protocol.lineReceived("failure mcdonalds farm [\n")
548         self.protocol.lineReceived("]\n")
549         self.assertEqual(self.client.start_calls, [self.test])
550         self.assertEqual(self.client.end_calls, [self.test])
551         self.assertEqual(self.client.error_calls, [])
552         self.assertEqual(self.client.failure_calls,
553                          [(self.test, subunit.RemoteError())])
554
555     def failure_quoted_bracket(self, keyword):
556         self.protocol.lineReceived("%s mcdonalds farm [\n" % keyword)
557         self.protocol.lineReceived(" ]\n")
558         self.protocol.lineReceived("]\n")
559         self.assertEqual(self.client.start_calls, [self.test])
560         self.assertEqual(self.client.end_calls, [self.test])
561         self.assertEqual(self.client.error_calls, [])
562         self.assertEqual(self.client.failure_calls,
563                          [(self.test, subunit.RemoteError("]\n"))])
564
565     def test_failure_quoted_bracket(self):
566         self.failure_quoted_bracket("failure")
567
568     def test_failure_colon_quoted_bracket(self):
569         self.failure_quoted_bracket("failure:")
570
571
572 class TestTestProtocolServerAddxFail(unittest.TestCase):
573     """Tests for the xfail keyword.
574
575     In Python this can thunk through to Success due to stdlib limitations (see
576     README).
577     """
578
579     def capture_expected_failure(self, test, err):
580         self._calls.append((test, err))
581
582     def setup_python26(self):
583         """Setup a test object ready to be xfailed and thunk to success."""
584         self.client = MockTestProtocolServerClient()
585         self.setup_protocol()
586
587     def setup_python27(self):
588         """Setup a test object ready to be xfailed and thunk to success."""
589         self.client = MockTestProtocolServerClient()
590         self.client.addExpectedFailure = self.capture_expected_failure
591         self._calls = []
592         self.setup_protocol()
593
594     def setup_protocol(self):
595         """Setup the protocol based on self.client."""
596         self.protocol = subunit.TestProtocolServer(self.client)
597         self.protocol.lineReceived("test mcdonalds farm\n")
598         self.test = self.client.start_calls[-1]
599
600     def simple_xfail_keyword(self, keyword, as_success):
601         self.protocol.lineReceived("%s mcdonalds farm\n" % keyword)
602         self.assertEqual(self.client.start_calls, [self.test])
603         self.assertEqual(self.client.end_calls, [self.test])
604         self.assertEqual(self.client.error_calls, [])
605         self.assertEqual(self.client.failure_calls, [])
606         self.check_success_or_xfail(as_success)
607
608     def check_success_or_xfail(self, as_success):
609         if as_success:
610             self.assertEqual(self.client.success_calls, [self.test])
611         else:
612             self.assertEqual(1, len(self._calls))
613             self.assertEqual(self.test, self._calls[0][0])
614
615     def test_simple_xfail(self):
616         self.setup_python26()
617         self.simple_xfail_keyword("xfail", True)
618         self.setup_python27()
619         self.simple_xfail_keyword("xfail",  False)
620
621     def test_simple_xfail_colon(self):
622         self.setup_python26()
623         self.simple_xfail_keyword("xfail:", True)
624         self.setup_python27()
625         self.simple_xfail_keyword("xfail:", False)
626
627     def test_xfail_empty_message(self):
628         self.setup_python26()
629         self.empty_message(True)
630         self.setup_python27()
631         self.empty_message(False)
632
633     def empty_message(self, as_success):
634         self.protocol.lineReceived("xfail mcdonalds farm [\n")
635         self.protocol.lineReceived("]\n")
636         self.assertEqual(self.client.start_calls, [self.test])
637         self.assertEqual(self.client.end_calls, [self.test])
638         self.assertEqual(self.client.error_calls, [])
639         self.assertEqual(self.client.failure_calls, [])
640         self.check_success_or_xfail(as_success)
641
642     def xfail_quoted_bracket(self, keyword, as_success):
643         # This tests it is accepted, but cannot test it is used today, because
644         # of not having a way to expose it in Python so far.
645         self.protocol.lineReceived("%s mcdonalds farm [\n" % keyword)
646         self.protocol.lineReceived(" ]\n")
647         self.protocol.lineReceived("]\n")
648         self.assertEqual(self.client.start_calls, [self.test])
649         self.assertEqual(self.client.end_calls, [self.test])
650         self.assertEqual(self.client.error_calls, [])
651         self.assertEqual(self.client.failure_calls, [])
652         self.check_success_or_xfail(as_success)
653
654     def test_xfail_quoted_bracket(self):
655         self.setup_python26()
656         self.xfail_quoted_bracket("xfail", True)
657         self.setup_python27()
658         self.xfail_quoted_bracket("xfail", False)
659
660     def test_xfail_colon_quoted_bracket(self):
661         self.setup_python26()
662         self.xfail_quoted_bracket("xfail:", True)
663         self.setup_python27()
664         self.xfail_quoted_bracket("xfail:", False)
665
666
667 class TestTestProtocolServerAddSkip(unittest.TestCase):
668     """Tests for the skip keyword.
669
670     In Python this meets the testtools extended TestResult contract.
671     (See https://launchpad.net/testtools).
672     """
673
674     def setUp(self):
675         """Setup a test object ready to be skipped."""
676         self.client = MockTestProtocolServerClient()
677         self.protocol = subunit.TestProtocolServer(self.client)
678         self.protocol.lineReceived("test mcdonalds farm\n")
679         self.test = self.client.start_calls[-1]
680
681     def simple_skip_keyword(self, keyword):
682         self.protocol.lineReceived("%s mcdonalds farm\n" % keyword)
683         self.assertEqual(self.client.start_calls, [self.test])
684         self.assertEqual(self.client.end_calls, [self.test])
685         self.assertEqual(self.client.error_calls, [])
686         self.assertEqual(self.client.failure_calls, [])
687         self.assertEqual(self.client.success_calls, [])
688         self.assertEqual(self.client.skip_calls,
689             [(self.test, 'No reason given')])
690
691     def test_simple_skip(self):
692         self.simple_skip_keyword("skip")
693
694     def test_simple_skip_colon(self):
695         self.simple_skip_keyword("skip:")
696
697     def test_skip_empty_message(self):
698         self.protocol.lineReceived("skip mcdonalds farm [\n")
699         self.protocol.lineReceived("]\n")
700         self.assertEqual(self.client.start_calls, [self.test])
701         self.assertEqual(self.client.end_calls, [self.test])
702         self.assertEqual(self.client.error_calls, [])
703         self.assertEqual(self.client.failure_calls, [])
704         self.assertEqual(self.client.success_calls, [])
705         self.assertEqual(self.client.skip_calls,
706             [(self.test, "No reason given")])
707
708     def skip_quoted_bracket(self, keyword):
709         # This tests it is accepted, but cannot test it is used today, because
710         # of not having a way to expose it in Python so far.
711         self.protocol.lineReceived("%s mcdonalds farm [\n" % keyword)
712         self.protocol.lineReceived(" ]\n")
713         self.protocol.lineReceived("]\n")
714         self.assertEqual(self.client.start_calls, [self.test])
715         self.assertEqual(self.client.end_calls, [self.test])
716         self.assertEqual(self.client.error_calls, [])
717         self.assertEqual(self.client.failure_calls, [])
718         self.assertEqual(self.client.success_calls, [])
719         self.assertEqual(self.client.skip_calls,
720             [(self.test, "]\n")])
721
722     def test_skip_quoted_bracket(self):
723         self.skip_quoted_bracket("skip")
724
725     def test_skip_colon_quoted_bracket(self):
726         self.skip_quoted_bracket("skip:")
727
728
729 class TestTestProtocolServerAddSuccess(unittest.TestCase):
730
731     def setUp(self):
732         self.client = MockTestProtocolServerClient()
733         self.protocol = subunit.TestProtocolServer(self.client)
734         self.protocol.lineReceived("test mcdonalds farm\n")
735         self.test = subunit.RemotedTestCase("mcdonalds farm")
736
737     def simple_success_keyword(self, keyword):
738         self.protocol.lineReceived("%s mcdonalds farm\n" % keyword)
739         self.assertEqual(self.client.start_calls, [self.test])
740         self.assertEqual(self.client.end_calls, [self.test])
741         self.assertEqual(self.client.error_calls, [])
742         self.assertEqual(self.client.success_calls, [self.test])
743
744     def test_simple_success(self):
745         self.simple_success_keyword("failure")
746
747     def test_simple_success_colon(self):
748         self.simple_success_keyword("failure:")
749
750     def test_simple_success(self):
751         self.simple_success_keyword("successful")
752
753     def test_simple_success_colon(self):
754         self.simple_success_keyword("successful:")
755
756     def test_success_empty_message(self):
757         self.protocol.lineReceived("success mcdonalds farm [\n")
758         self.protocol.lineReceived("]\n")
759         self.assertEqual(self.client.start_calls, [self.test])
760         self.assertEqual(self.client.end_calls, [self.test])
761         self.assertEqual(self.client.error_calls, [])
762         self.assertEqual(self.client.failure_calls, [])
763         self.assertEqual(self.client.success_calls, [self.test])
764
765     def success_quoted_bracket(self, keyword):
766         # This tests it is accepted, but cannot test it is used today, because
767         # of not having a way to expose it in Python so far.
768         self.protocol.lineReceived("%s mcdonalds farm [\n" % keyword)
769         self.protocol.lineReceived(" ]\n")
770         self.protocol.lineReceived("]\n")
771         self.assertEqual(self.client.start_calls, [self.test])
772         self.assertEqual(self.client.end_calls, [self.test])
773         self.assertEqual(self.client.error_calls, [])
774         self.assertEqual(self.client.failure_calls, [])
775         self.assertEqual(self.client.success_calls, [self.test])
776
777     def test_success_quoted_bracket(self):
778         self.success_quoted_bracket("success")
779
780     def test_success_colon_quoted_bracket(self):
781         self.success_quoted_bracket("success:")
782
783
784 class TestTestProtocolServerProgress(unittest.TestCase):
785     """Test receipt of progress: directives."""
786
787     def test_progress_accepted_stdlib(self):
788         # With a stdlib TestResult, progress events are swallowed.
789         self.result = unittest.TestResult()
790         self.stream = StringIO()
791         self.protocol = subunit.TestProtocolServer(self.result,
792             stream=self.stream)
793         self.protocol.lineReceived("progress: 23")
794         self.protocol.lineReceived("progress: -2")
795         self.protocol.lineReceived("progress: +4")
796         self.assertEqual("", self.stream.getvalue())
797
798     def test_progress_accepted_extended(self):
799         # With a progress capable TestResult, progress events are emitted.
800         self.result = MockTestProtocolServerClient()
801         self.stream = StringIO()
802         self.protocol = subunit.TestProtocolServer(self.result,
803             stream=self.stream)
804         self.protocol.lineReceived("progress: 23")
805         self.protocol.lineReceived("progress: push")
806         self.protocol.lineReceived("progress: -2")
807         self.protocol.lineReceived("progress: pop")
808         self.protocol.lineReceived("progress: +4")
809         self.assertEqual("", self.stream.getvalue())
810         self.assertEqual(
811             [(23, subunit.PROGRESS_SET), (None, subunit.PROGRESS_PUSH),
812              (-2, subunit.PROGRESS_CUR), (None, subunit.PROGRESS_POP),
813              (4, subunit.PROGRESS_CUR)],
814             self.result.progress_calls)
815
816
817 class TestTestProtocolServerStreamTags(unittest.TestCase):
818     """Test managing tags on the protocol level."""
819
820     def setUp(self):
821         self.client = MockExtendedTestProtocolServerClient()
822         self.protocol = subunit.TestProtocolServer(self.client)
823
824     def test_initial_tags(self):
825         self.protocol.lineReceived("tags: foo bar:baz  quux\n")
826         self.assertEqual(set(["foo", "bar:baz", "quux"]),
827             self.client.new_tags)
828         self.assertEqual(set(), self.client.gone_tags)
829
830     def test_minus_removes_tags(self):
831         self.protocol.lineReceived("tags: foo bar\n")
832         self.assertEqual(set(["foo", "bar"]),
833             self.client.new_tags)
834         self.assertEqual(set(), self.client.gone_tags)
835         self.protocol.lineReceived("tags: -bar quux\n")
836         self.assertEqual(set(["quux"]), self.client.new_tags)
837         self.assertEqual(set(["bar"]), self.client.gone_tags)
838
839     def test_tags_do_not_get_set_on_test(self):
840         self.protocol.lineReceived("test mcdonalds farm\n")
841         test = self.client.start_calls[-1]
842         self.assertEqual(None, getattr(test, 'tags', None))
843
844     def test_tags_do_not_get_set_on_global_tags(self):
845         self.protocol.lineReceived("tags: foo bar\n")
846         self.protocol.lineReceived("test mcdonalds farm\n")
847         test = self.client.start_calls[-1]
848         self.assertEqual(None, getattr(test, 'tags', None))
849
850     def test_tags_get_set_on_test_tags(self):
851         self.protocol.lineReceived("test mcdonalds farm\n")
852         test = self.client.start_calls[-1]
853         self.protocol.lineReceived("tags: foo bar\n")
854         self.protocol.lineReceived("success mcdonalds farm\n")
855         self.assertEqual(None, getattr(test, 'tags', None))
856
857
858 class TestTestProtocolServerStreamTime(unittest.TestCase):
859     """Test managing time information at the protocol level."""
860
861     def test_time_accepted_stdlib(self):
862         self.result = unittest.TestResult()
863         self.stream = StringIO()
864         self.protocol = subunit.TestProtocolServer(self.result,
865             stream=self.stream)
866         self.protocol.lineReceived("time: 2001-12-12 12:59:59Z\n")
867         self.assertEqual("", self.stream.getvalue())
868
869     def test_time_accepted_extended(self):
870         self.result = MockTestProtocolServerClient()
871         self.stream = StringIO()
872         self.protocol = subunit.TestProtocolServer(self.result,
873             stream=self.stream)
874         self.protocol.lineReceived("time: 2001-12-12 12:59:59Z\n")
875         self.assertEqual("", self.stream.getvalue())
876         self.assertEqual(datetime.datetime(2001, 12, 12, 12, 59, 59, 0,
877             iso8601.Utc()), self.result._time)
878
879
880 class TestRemotedTestCase(unittest.TestCase):
881
882     def test_simple(self):
883         test = subunit.RemotedTestCase("A test description")
884         self.assertRaises(NotImplementedError, test.setUp)
885         self.assertRaises(NotImplementedError, test.tearDown)
886         self.assertEqual("A test description",
887                          test.shortDescription())
888         self.assertEqual("A test description",
889                          test.id())
890         self.assertEqual("A test description (subunit.RemotedTestCase)", "%s" % test)
891         self.assertEqual("<subunit.RemotedTestCase description="
892                          "'A test description'>", "%r" % test)
893         result = unittest.TestResult()
894         test.run(result)
895         self.assertEqual([(test, "RemoteException: "
896                                  "Cannot run RemotedTestCases.\n\n")],
897                          result.errors)
898         self.assertEqual(1, result.testsRun)
899         another_test = subunit.RemotedTestCase("A test description")
900         self.assertEqual(test, another_test)
901         different_test = subunit.RemotedTestCase("ofo")
902         self.assertNotEqual(test, different_test)
903         self.assertNotEqual(another_test, different_test)
904
905
906 class TestRemoteError(unittest.TestCase):
907
908     def test_eq(self):
909         error = subunit.RemoteError("Something went wrong")
910         another_error = subunit.RemoteError("Something went wrong")
911         different_error = subunit.RemoteError("boo!")
912         self.assertEqual(error, another_error)
913         self.assertNotEqual(error, different_error)
914         self.assertNotEqual(different_error, another_error)
915
916     def test_empty_constructor(self):
917         self.assertEqual(subunit.RemoteError(), subunit.RemoteError(""))
918
919
920 class TestExecTestCase(unittest.TestCase):
921
922     class SampleExecTestCase(subunit.ExecTestCase):
923
924         def test_sample_method(self):
925             """sample-script.py"""
926             # the sample script runs three tests, one each
927             # that fails, errors and succeeds
928
929         def test_sample_method_args(self):
930             """sample-script.py foo"""
931             # sample that will run just one test.
932
933     def test_construct(self):
934         test = self.SampleExecTestCase("test_sample_method")
935         self.assertEqual(test.script,
936                          subunit.join_dir(__file__, 'sample-script.py'))
937
938     def test_args(self):
939         result = unittest.TestResult()
940         test = self.SampleExecTestCase("test_sample_method_args")
941         test.run(result)
942         self.assertEqual(1, result.testsRun)
943
944     def test_run(self):
945         runner = MockTestProtocolServerClient()
946         test = self.SampleExecTestCase("test_sample_method")
947         test.run(runner)
948         mcdonald = subunit.RemotedTestCase("old mcdonald")
949         bing = subunit.RemotedTestCase("bing crosby")
950         an_error = subunit.RemotedTestCase("an error")
951         self.assertEqual(runner.error_calls,
952                          [(an_error, subunit.RemoteError())])
953         self.assertEqual(runner.failure_calls,
954                          [(bing,
955                            subunit.RemoteError(
956                             "foo.c:53:ERROR invalid state\n"))])
957         self.assertEqual(runner.start_calls, [mcdonald, bing, an_error])
958         self.assertEqual(runner.end_calls, [mcdonald, bing, an_error])
959
960     def test_debug(self):
961         test = self.SampleExecTestCase("test_sample_method")
962         test.debug()
963
964     def test_count_test_cases(self):
965         """TODO run the child process and count responses to determine the count."""
966
967     def test_join_dir(self):
968         sibling = subunit.join_dir(__file__, 'foo')
969         expected = '%s/foo' % (os.path.split(__file__)[0],)
970         self.assertEqual(sibling, expected)
971
972
973 class DoExecTestCase(subunit.ExecTestCase):
974
975     def test_working_script(self):
976         """sample-two-script.py"""
977
978
979 class TestIsolatedTestCase(unittest.TestCase):
980
981     class SampleIsolatedTestCase(subunit.IsolatedTestCase):
982
983         SETUP = False
984         TEARDOWN = False
985         TEST = False
986
987         def setUp(self):
988             TestIsolatedTestCase.SampleIsolatedTestCase.SETUP = True
989
990         def tearDown(self):
991             TestIsolatedTestCase.SampleIsolatedTestCase.TEARDOWN = True
992
993         def test_sets_global_state(self):
994             TestIsolatedTestCase.SampleIsolatedTestCase.TEST = True
995
996
997     def test_construct(self):
998         test = self.SampleIsolatedTestCase("test_sets_global_state")
999
1000     def test_run(self):
1001         result = unittest.TestResult()
1002         test = self.SampleIsolatedTestCase("test_sets_global_state")
1003         test.run(result)
1004         self.assertEqual(result.testsRun, 1)
1005         self.assertEqual(self.SampleIsolatedTestCase.SETUP, False)
1006         self.assertEqual(self.SampleIsolatedTestCase.TEARDOWN, False)
1007         self.assertEqual(self.SampleIsolatedTestCase.TEST, False)
1008
1009     def test_debug(self):
1010         pass
1011         #test = self.SampleExecTestCase("test_sample_method")
1012         #test.debug()
1013
1014
1015 class TestIsolatedTestSuite(unittest.TestCase):
1016
1017     class SampleTestToIsolate(unittest.TestCase):
1018
1019         SETUP = False
1020         TEARDOWN = False
1021         TEST = False
1022
1023         def setUp(self):
1024             TestIsolatedTestSuite.SampleTestToIsolate.SETUP = True
1025
1026         def tearDown(self):
1027             TestIsolatedTestSuite.SampleTestToIsolate.TEARDOWN = True
1028
1029         def test_sets_global_state(self):
1030             TestIsolatedTestSuite.SampleTestToIsolate.TEST = True
1031
1032
1033     def test_construct(self):
1034         suite = subunit.IsolatedTestSuite()
1035
1036     def test_run(self):
1037         result = unittest.TestResult()
1038         suite = subunit.IsolatedTestSuite()
1039         sub_suite = unittest.TestSuite()
1040         sub_suite.addTest(self.SampleTestToIsolate("test_sets_global_state"))
1041         sub_suite.addTest(self.SampleTestToIsolate("test_sets_global_state"))
1042         suite.addTest(sub_suite)
1043         suite.addTest(self.SampleTestToIsolate("test_sets_global_state"))
1044         suite.run(result)
1045         self.assertEqual(result.testsRun, 3)
1046         self.assertEqual(self.SampleTestToIsolate.SETUP, False)
1047         self.assertEqual(self.SampleTestToIsolate.TEARDOWN, False)
1048         self.assertEqual(self.SampleTestToIsolate.TEST, False)
1049
1050
1051 class TestTestProtocolClient(unittest.TestCase):
1052
1053     def setUp(self):
1054         self.io = StringIO()
1055         self.protocol = subunit.TestProtocolClient(self.io)
1056         self.test = TestTestProtocolClient("test_start_test")
1057         self.sample_details = {'something':Content(
1058             ContentType('text', 'plain'), lambda:['serialised\nform'])}
1059         self.sample_tb_details = dict(self.sample_details)
1060         self.sample_tb_details['traceback'] = TracebackContent(
1061             subunit.RemoteError("boo qux"))
1062
1063     def test_start_test(self):
1064         """Test startTest on a TestProtocolClient."""
1065         self.protocol.startTest(self.test)
1066         self.assertEqual(self.io.getvalue(), "test: %s\n" % self.test.id())
1067
1068     def test_stop_test(self):
1069         # stopTest doesn't output anything.
1070         self.protocol.stopTest(self.test)
1071         self.assertEqual(self.io.getvalue(), "")
1072
1073     def test_add_success(self):
1074         """Test addSuccess on a TestProtocolClient."""
1075         self.protocol.addSuccess(self.test)
1076         self.assertEqual(
1077             self.io.getvalue(), "successful: %s\n" % self.test.id())
1078
1079     def test_add_success_details(self):
1080         """Test addSuccess on a TestProtocolClient with details."""
1081         self.protocol.addSuccess(self.test, details=self.sample_details)
1082         self.assertEqual(
1083             self.io.getvalue(), "successful: %s [ multipart\n"
1084                 "Content-Type: text/plain\n"
1085                 "something\n"
1086                 "15\nserialised\nform0\n]\n" % self.test.id())
1087
1088     def test_add_failure(self):
1089         """Test addFailure on a TestProtocolClient."""
1090         self.protocol.addFailure(
1091             self.test, subunit.RemoteError("boo qux"))
1092         self.assertEqual(
1093             self.io.getvalue(),
1094             'failure: %s [\nRemoteException: boo qux\n]\n' % self.test.id())
1095
1096     def test_add_failure_details(self):
1097         """Test addFailure on a TestProtocolClient with details."""
1098         self.protocol.addFailure(
1099             self.test, details=self.sample_tb_details)
1100         self.assertEqual(
1101             self.io.getvalue(),
1102             "failure: %s [ multipart\n"
1103             "Content-Type: text/plain\n"
1104             "something\n"
1105             "15\nserialised\nform0\n"
1106             "Content-Type: text/x-traceback;language=python\n"
1107             "traceback\n"
1108             "25\nRemoteException: boo qux\n0\n"
1109             "]\n" % self.test.id())
1110
1111
1112     def test_add_error(self):
1113         """Test stopTest on a TestProtocolClient."""
1114         self.protocol.addError(
1115             self.test, subunit.RemoteError("phwoar crikey"))
1116         self.assertEqual(
1117             self.io.getvalue(),
1118             'error: %s [\n'
1119             "RemoteException: phwoar crikey\n"
1120             "]\n" % self.test.id())
1121
1122     def test_add_skip(self):
1123         """Test addSkip on a TestProtocolClient."""
1124         self.protocol.addSkip(
1125             self.test, "Has it really?")
1126         self.assertEqual(
1127             self.io.getvalue(),
1128             'skip: %s [\nHas it really?\n]\n' % self.test.id())
1129
1130     def test_progress_set(self):
1131         self.protocol.progress(23, subunit.PROGRESS_SET)
1132         self.assertEqual(self.io.getvalue(), 'progress: 23\n')
1133
1134     def test_progress_neg_cur(self):
1135         self.protocol.progress(-23, subunit.PROGRESS_CUR)
1136         self.assertEqual(self.io.getvalue(), 'progress: -23\n')
1137
1138     def test_progress_pos_cur(self):
1139         self.protocol.progress(23, subunit.PROGRESS_CUR)
1140         self.assertEqual(self.io.getvalue(), 'progress: +23\n')
1141
1142     def test_progress_pop(self):
1143         self.protocol.progress(1234, subunit.PROGRESS_POP)
1144         self.assertEqual(self.io.getvalue(), 'progress: pop\n')
1145
1146     def test_progress_push(self):
1147         self.protocol.progress(1234, subunit.PROGRESS_PUSH)
1148         self.assertEqual(self.io.getvalue(), 'progress: push\n')
1149
1150     def test_time(self):
1151         # Calling time() outputs a time signal immediately.
1152         self.protocol.time(
1153             datetime.datetime(2009,10,11,12,13,14,15, iso8601.Utc()))
1154         self.assertEqual(
1155             "time: 2009-10-11 12:13:14.000015Z\n",
1156             self.io.getvalue())
1157
1158
1159 def test_suite():
1160     loader = subunit.tests.TestUtil.TestLoader()
1161     result = loader.loadTestsFromName(__name__)
1162     return result