~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_selftest.py

merge trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2010 Canonical Ltd
 
1
# Copyright (C) 2005-2011 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
17
17
"""Tests for the test framework."""
18
18
 
19
19
from cStringIO import StringIO
20
 
from doctest import ELLIPSIS
 
20
import doctest
21
21
import os
22
22
import signal
23
23
import sys
26
26
import unittest
27
27
import warnings
28
28
 
29
 
from testtools import MultiTestResult
 
29
from testtools import (
 
30
    ExtendedToOriginalDecorator,
 
31
    MultiTestResult,
 
32
    )
 
33
from testtools.content import Content
30
34
from testtools.content_type import ContentType
31
35
from testtools.matchers import (
32
36
    DocTestMatches,
38
42
from bzrlib import (
39
43
    branchbuilder,
40
44
    bzrdir,
41
 
    debug,
42
45
    errors,
43
46
    lockdir,
44
47
    memorytree,
45
48
    osutils,
46
 
    progress,
47
49
    remote,
48
50
    repository,
49
51
    symbol_versioning,
53
55
    )
54
56
from bzrlib.repofmt import (
55
57
    groupcompress_repo,
56
 
    pack_repo,
57
 
    weaverepo,
58
58
    )
59
59
from bzrlib.symbol_versioning import (
60
60
    deprecated_function,
65
65
    features,
66
66
    test_lsprof,
67
67
    test_server,
68
 
    test_sftp_transport,
69
68
    TestUtil,
70
69
    )
71
 
from bzrlib.trace import note
 
70
from bzrlib.trace import note, mutter
72
71
from bzrlib.transport import memory
73
 
from bzrlib.version import _get_bzr_source_tree
74
72
 
75
73
 
76
74
def _test_ids(test_suite):
78
76
    return [t.id() for t in tests.iter_suite_tests(test_suite)]
79
77
 
80
78
 
81
 
class SelftestTests(tests.TestCase):
82
 
 
83
 
    def test_import_tests(self):
84
 
        mod = TestUtil._load_module_by_name('bzrlib.tests.test_selftest')
85
 
        self.assertEqual(mod.SelftestTests, SelftestTests)
86
 
 
87
 
    def test_import_test_failure(self):
88
 
        self.assertRaises(ImportError,
89
 
                          TestUtil._load_module_by_name,
90
 
                          'bzrlib.no-name-yet')
91
 
 
92
 
 
93
79
class MetaTestLog(tests.TestCase):
94
80
 
95
81
    def test_logging(self):
101
87
            "text", "plain", {"charset": "utf8"})))
102
88
        self.assertThat(u"".join(log.iter_text()), Equals(self.get_log()))
103
89
        self.assertThat(self.get_log(),
104
 
            DocTestMatches(u"...a test message\n", ELLIPSIS))
 
90
            DocTestMatches(u"...a test message\n", doctest.ELLIPSIS))
105
91
 
106
92
 
107
93
class TestUnicodeFilename(tests.TestCase):
326
312
        from bzrlib.tests.per_interrepository import make_scenarios
327
313
        server1 = "a"
328
314
        server2 = "b"
329
 
        formats = [("C0", "C1", "C2"), ("D0", "D1", "D2")]
 
315
        formats = [("C0", "C1", "C2", "C3"), ("D0", "D1", "D2", "D3")]
330
316
        scenarios = make_scenarios(server1, server2, formats)
331
317
        self.assertEqual([
332
318
            ('C0,str,str',
333
319
             {'repository_format': 'C1',
334
320
              'repository_format_to': 'C2',
335
321
              'transport_readonly_server': 'b',
336
 
              'transport_server': 'a'}),
 
322
              'transport_server': 'a',
 
323
              'extra_setup': 'C3'}),
337
324
            ('D0,str,str',
338
325
             {'repository_format': 'D1',
339
326
              'repository_format_to': 'D2',
340
327
              'transport_readonly_server': 'b',
341
 
              'transport_server': 'a'})],
 
328
              'transport_server': 'a',
 
329
              'extra_setup': 'D3'})],
342
330
            scenarios)
343
331
 
344
332
 
350
338
        from bzrlib.tests.per_workingtree import make_scenarios
351
339
        server1 = "a"
352
340
        server2 = "b"
353
 
        formats = [workingtree.WorkingTreeFormat2(),
 
341
        formats = [workingtree.WorkingTreeFormat4(),
354
342
                   workingtree.WorkingTreeFormat3(),]
355
343
        scenarios = make_scenarios(server1, server2, formats)
356
344
        self.assertEqual([
357
 
            ('WorkingTreeFormat2',
 
345
            ('WorkingTreeFormat4',
358
346
             {'bzrdir_format': formats[0]._matchingbzrdir,
359
347
              'transport_readonly_server': 'b',
360
348
              'transport_server': 'a',
387
375
            )
388
376
        server1 = "a"
389
377
        server2 = "b"
390
 
        formats = [workingtree.WorkingTreeFormat2(),
 
378
        formats = [workingtree.WorkingTreeFormat4(),
391
379
                   workingtree.WorkingTreeFormat3(),]
392
380
        scenarios = make_scenarios(server1, server2, formats)
393
381
        self.assertEqual(7, len(scenarios))
394
 
        default_wt_format = workingtree.WorkingTreeFormat4._default_format
 
382
        default_wt_format = workingtree.format_registry.get_default()
395
383
        wt4_format = workingtree.WorkingTreeFormat4()
396
384
        wt5_format = workingtree.WorkingTreeFormat5()
397
385
        expected_scenarios = [
398
 
            ('WorkingTreeFormat2',
 
386
            ('WorkingTreeFormat4',
399
387
             {'bzrdir_format': formats[0]._matchingbzrdir,
400
388
              'transport_readonly_server': 'b',
401
389
              'transport_server': 'a',
461
449
        # ones to add.
462
450
        from bzrlib.tests.per_tree import (
463
451
            return_parameter,
464
 
            revision_tree_from_workingtree
465
452
            )
466
453
        from bzrlib.tests.per_intertree import (
467
454
            make_scenarios,
468
455
            )
469
 
        from bzrlib.workingtree import WorkingTreeFormat2, WorkingTreeFormat3
 
456
        from bzrlib.workingtree import WorkingTreeFormat3, WorkingTreeFormat4
470
457
        input_test = TestInterTreeScenarios(
471
458
            "test_scenarios")
472
459
        server1 = "a"
473
460
        server2 = "b"
474
 
        format1 = WorkingTreeFormat2()
 
461
        format1 = WorkingTreeFormat4()
475
462
        format2 = WorkingTreeFormat3()
476
463
        formats = [("1", str, format1, format2, "converter1"),
477
464
            ("2", int, format2, format1, "converter2")]
568
555
    def test_make_branch_and_memory_tree_with_format(self):
569
556
        """make_branch_and_memory_tree should accept a format option."""
570
557
        format = bzrdir.BzrDirMetaFormat1()
571
 
        format.repository_format = weaverepo.RepositoryFormat7()
 
558
        format.repository_format = repository.format_registry.get_default()
572
559
        tree = self.make_branch_and_memory_tree('dir', format=format)
573
560
        # Guard against regression into MemoryTransport leaking
574
561
        # files to disk instead of keeping them in memory.
588
575
        # Use a repo layout that doesn't conform to a 'named' layout, to ensure
589
576
        # that the format objects are used.
590
577
        format = bzrdir.BzrDirMetaFormat1()
591
 
        repo_format = weaverepo.RepositoryFormat7()
 
578
        repo_format = repository.format_registry.get_default()
592
579
        format.repository_format = repo_format
593
580
        builder = self.make_branch_builder('dir', format=format)
594
581
        the_branch = builder.get_branch()
625
612
        result = test.run()
626
613
        total_failures = result.errors + result.failures
627
614
        if self._lock_check_thorough:
628
 
            self.assertLength(1, total_failures)
 
615
            self.assertEqual(1, len(total_failures))
629
616
        else:
630
617
            # When _lock_check_thorough is disabled, then we don't trigger a
631
618
            # failure
632
 
            self.assertLength(0, total_failures)
 
619
            self.assertEqual(0, len(total_failures))
633
620
 
634
621
 
635
622
class TestTestCaseWithTransport(tests.TestCaseWithTransport):
847
834
        self.assertContainsRe(output,
848
835
            r"LSProf output for <type 'unicode'>\(\('world',\), {'errors': 'replace'}\)\n")
849
836
 
 
837
    def test_uses_time_from_testtools(self):
 
838
        """Test case timings in verbose results should use testtools times"""
 
839
        import datetime
 
840
        class TimeAddedVerboseTestResult(tests.VerboseTestResult):
 
841
            def startTest(self, test):
 
842
                self.time(datetime.datetime.utcfromtimestamp(1.145))
 
843
                super(TimeAddedVerboseTestResult, self).startTest(test)
 
844
            def addSuccess(self, test):
 
845
                self.time(datetime.datetime.utcfromtimestamp(51.147))
 
846
                super(TimeAddedVerboseTestResult, self).addSuccess(test)
 
847
            def report_tests_starting(self): pass
 
848
        sio = StringIO()
 
849
        self.get_passing_test().run(TimeAddedVerboseTestResult(sio, 0, 2))
 
850
        self.assertEndsWith(sio.getvalue(), "OK    50002ms\n")
 
851
 
850
852
    def test_known_failure(self):
851
853
        """A KnownFailure being raised should trigger several result actions."""
852
854
        class InstrumentedTestResult(tests.ExtendedTestResult):
1102
1104
    def test_result_decorator(self):
1103
1105
        # decorate results
1104
1106
        calls = []
1105
 
        class LoggingDecorator(tests.ForwardingResult):
 
1107
        class LoggingDecorator(ExtendedToOriginalDecorator):
1106
1108
            def startTest(self, test):
1107
 
                tests.ForwardingResult.startTest(self, test)
 
1109
                ExtendedToOriginalDecorator.startTest(self, test)
1108
1110
                calls.append('start')
1109
1111
        test = unittest.FunctionTestCase(lambda:None)
1110
1112
        stream = StringIO()
1234
1236
        self.assertContainsRe(output_string, "--date [0-9.]+")
1235
1237
        self.assertLength(1, self._get_source_tree_calls)
1236
1238
 
 
1239
    def test_verbose_test_count(self):
 
1240
        """A verbose test run reports the right test count at the start"""
 
1241
        suite = TestUtil.TestSuite([
 
1242
            unittest.FunctionTestCase(lambda:None),
 
1243
            unittest.FunctionTestCase(lambda:None)])
 
1244
        self.assertEqual(suite.countTestCases(), 2)
 
1245
        stream = StringIO()
 
1246
        runner = tests.TextTestRunner(stream=stream, verbosity=2)
 
1247
        # Need to use the CountingDecorator as that's what sets num_tests
 
1248
        result = self.run_test_runner(runner, tests.CountingDecorator(suite))
 
1249
        self.assertStartsWith(stream.getvalue(), "running 2 tests")
 
1250
 
1237
1251
    def test_startTestRun(self):
1238
1252
        """run should call result.startTestRun()"""
1239
1253
        calls = []
1240
 
        class LoggingDecorator(tests.ForwardingResult):
 
1254
        class LoggingDecorator(ExtendedToOriginalDecorator):
1241
1255
            def startTestRun(self):
1242
 
                tests.ForwardingResult.startTestRun(self)
 
1256
                ExtendedToOriginalDecorator.startTestRun(self)
1243
1257
                calls.append('startTestRun')
1244
1258
        test = unittest.FunctionTestCase(lambda:None)
1245
1259
        stream = StringIO()
1251
1265
    def test_stopTestRun(self):
1252
1266
        """run should call result.stopTestRun()"""
1253
1267
        calls = []
1254
 
        class LoggingDecorator(tests.ForwardingResult):
 
1268
        class LoggingDecorator(ExtendedToOriginalDecorator):
1255
1269
            def stopTestRun(self):
1256
 
                tests.ForwardingResult.stopTestRun(self)
 
1270
                ExtendedToOriginalDecorator.stopTestRun(self)
1257
1271
                calls.append('stopTestRun')
1258
1272
        test = unittest.FunctionTestCase(lambda:None)
1259
1273
        stream = StringIO()
1262
1276
        result = self.run_test_runner(runner, test)
1263
1277
        self.assertLength(1, calls)
1264
1278
 
 
1279
    def test_unicode_test_output_on_ascii_stream(self):
 
1280
        """Showing results should always succeed even on an ascii console"""
 
1281
        class FailureWithUnicode(tests.TestCase):
 
1282
            def test_log_unicode(self):
 
1283
                self.log(u"\u2606")
 
1284
                self.fail("Now print that log!")
 
1285
        out = StringIO()
 
1286
        self.overrideAttr(osutils, "get_terminal_encoding",
 
1287
            lambda trace=False: "ascii")
 
1288
        result = self.run_test_runner(tests.TextTestRunner(stream=out),
 
1289
            FailureWithUnicode("test_log_unicode"))
 
1290
        self.assertContainsRe(out.getvalue(),
 
1291
            "Text attachment: log\n"
 
1292
            "-+\n"
 
1293
            "\d+\.\d+  \\\\u2606\n"
 
1294
            "-+\n")
 
1295
 
1265
1296
 
1266
1297
class SampleTestCase(tests.TestCase):
1267
1298
 
1676
1707
        self.assertEqual('original', obj.test_attr)
1677
1708
 
1678
1709
 
 
1710
class _MissingFeature(tests.Feature):
 
1711
    def _probe(self):
 
1712
        return False
 
1713
missing_feature = _MissingFeature()
 
1714
 
 
1715
 
 
1716
def _get_test(name):
 
1717
    """Get an instance of a specific example test.
 
1718
 
 
1719
    We protect this in a function so that they don't auto-run in the test
 
1720
    suite.
 
1721
    """
 
1722
 
 
1723
    class ExampleTests(tests.TestCase):
 
1724
 
 
1725
        def test_fail(self):
 
1726
            mutter('this was a failing test')
 
1727
            self.fail('this test will fail')
 
1728
 
 
1729
        def test_error(self):
 
1730
            mutter('this test errored')
 
1731
            raise RuntimeError('gotcha')
 
1732
 
 
1733
        def test_missing_feature(self):
 
1734
            mutter('missing the feature')
 
1735
            self.requireFeature(missing_feature)
 
1736
 
 
1737
        def test_skip(self):
 
1738
            mutter('this test will be skipped')
 
1739
            raise tests.TestSkipped('reason')
 
1740
 
 
1741
        def test_success(self):
 
1742
            mutter('this test succeeds')
 
1743
 
 
1744
        def test_xfail(self):
 
1745
            mutter('test with expected failure')
 
1746
            self.knownFailure('this_fails')
 
1747
 
 
1748
        def test_unexpected_success(self):
 
1749
            mutter('test with unexpected success')
 
1750
            self.expectFailure('should_fail', lambda: None)
 
1751
 
 
1752
    return ExampleTests(name)
 
1753
 
 
1754
 
 
1755
class TestTestCaseLogDetails(tests.TestCase):
 
1756
 
 
1757
    def _run_test(self, test_name):
 
1758
        test = _get_test(test_name)
 
1759
        result = testtools.TestResult()
 
1760
        test.run(result)
 
1761
        return result
 
1762
 
 
1763
    def test_fail_has_log(self):
 
1764
        result = self._run_test('test_fail')
 
1765
        self.assertEqual(1, len(result.failures))
 
1766
        result_content = result.failures[0][1]
 
1767
        self.assertContainsRe(result_content, 'Text attachment: log')
 
1768
        self.assertContainsRe(result_content, 'this was a failing test')
 
1769
 
 
1770
    def test_error_has_log(self):
 
1771
        result = self._run_test('test_error')
 
1772
        self.assertEqual(1, len(result.errors))
 
1773
        result_content = result.errors[0][1]
 
1774
        self.assertContainsRe(result_content, 'Text attachment: log')
 
1775
        self.assertContainsRe(result_content, 'this test errored')
 
1776
 
 
1777
    def test_skip_has_no_log(self):
 
1778
        result = self._run_test('test_skip')
 
1779
        self.assertEqual(['reason'], result.skip_reasons.keys())
 
1780
        skips = result.skip_reasons['reason']
 
1781
        self.assertEqual(1, len(skips))
 
1782
        test = skips[0]
 
1783
        self.assertFalse('log' in test.getDetails())
 
1784
 
 
1785
    def test_missing_feature_has_no_log(self):
 
1786
        # testtools doesn't know about addNotSupported, so it just gets
 
1787
        # considered as a skip
 
1788
        result = self._run_test('test_missing_feature')
 
1789
        self.assertEqual([missing_feature], result.skip_reasons.keys())
 
1790
        skips = result.skip_reasons[missing_feature]
 
1791
        self.assertEqual(1, len(skips))
 
1792
        test = skips[0]
 
1793
        self.assertFalse('log' in test.getDetails())
 
1794
 
 
1795
    def test_xfail_has_no_log(self):
 
1796
        result = self._run_test('test_xfail')
 
1797
        self.assertEqual(1, len(result.expectedFailures))
 
1798
        result_content = result.expectedFailures[0][1]
 
1799
        self.assertNotContainsRe(result_content, 'Text attachment: log')
 
1800
        self.assertNotContainsRe(result_content, 'test with expected failure')
 
1801
 
 
1802
    def test_unexpected_success_has_log(self):
 
1803
        result = self._run_test('test_unexpected_success')
 
1804
        self.assertEqual(1, len(result.unexpectedSuccesses))
 
1805
        # Inconsistency, unexpectedSuccesses is a list of tests,
 
1806
        # expectedFailures is a list of reasons?
 
1807
        test = result.unexpectedSuccesses[0]
 
1808
        details = test.getDetails()
 
1809
        self.assertTrue('log' in details)
 
1810
 
 
1811
 
 
1812
class TestTestCloning(tests.TestCase):
 
1813
    """Tests that test cloning of TestCases (as used by multiply_tests)."""
 
1814
 
 
1815
    def test_cloned_testcase_does_not_share_details(self):
 
1816
        """A TestCase cloned with clone_test does not share mutable attributes
 
1817
        such as details or cleanups.
 
1818
        """
 
1819
        class Test(tests.TestCase):
 
1820
            def test_foo(self):
 
1821
                self.addDetail('foo', Content('text/plain', lambda: 'foo'))
 
1822
        orig_test = Test('test_foo')
 
1823
        cloned_test = tests.clone_test(orig_test, orig_test.id() + '(cloned)')
 
1824
        orig_test.run(unittest.TestResult())
 
1825
        self.assertEqual('foo', orig_test.getDetails()['foo'].iter_bytes())
 
1826
        self.assertEqual(None, cloned_test.getDetails().get('foo'))
 
1827
 
 
1828
    def test_double_apply_scenario_preserves_first_scenario(self):
 
1829
        """Applying two levels of scenarios to a test preserves the attributes
 
1830
        added by both scenarios.
 
1831
        """
 
1832
        class Test(tests.TestCase):
 
1833
            def test_foo(self):
 
1834
                pass
 
1835
        test = Test('test_foo')
 
1836
        scenarios_x = [('x=1', {'x': 1}), ('x=2', {'x': 2})]
 
1837
        scenarios_y = [('y=1', {'y': 1}), ('y=2', {'y': 2})]
 
1838
        suite = tests.multiply_tests(test, scenarios_x, unittest.TestSuite())
 
1839
        suite = tests.multiply_tests(suite, scenarios_y, unittest.TestSuite())
 
1840
        all_tests = list(tests.iter_suite_tests(suite))
 
1841
        self.assertLength(4, all_tests)
 
1842
        all_xys = sorted((t.x, t.y) for t in all_tests)
 
1843
        self.assertEqual([(1, 1), (1, 2), (2, 1), (2, 2)], all_xys)
 
1844
 
 
1845
 
1679
1846
# NB: Don't delete this; it's not actually from 0.11!
1680
1847
@deprecated_function(deprecated_in((0, 11, 0)))
1681
1848
def sample_deprecated_function():
1808
1975
    def test_make_branch_and_tree_with_format(self):
1809
1976
        # we should be able to supply a format to make_branch_and_tree
1810
1977
        self.make_branch_and_tree('a', format=bzrlib.bzrdir.BzrDirMetaFormat1())
1811
 
        self.make_branch_and_tree('b', format=bzrlib.bzrdir.BzrDirFormat6())
1812
1978
        self.assertIsInstance(bzrlib.bzrdir.BzrDir.open('a')._format,
1813
1979
                              bzrlib.bzrdir.BzrDirMetaFormat1)
1814
 
        self.assertIsInstance(bzrlib.bzrdir.BzrDir.open('b')._format,
1815
 
                              bzrlib.bzrdir.BzrDirFormat6)
1816
1980
 
1817
1981
    def test_make_branch_and_memory_tree(self):
1818
1982
        # we should be able to get a new branch and a mutable tree from
1835
1999
                tree.branch.repository.bzrdir.root_transport)
1836
2000
 
1837
2001
 
1838
 
class SelfTestHelper:
 
2002
class SelfTestHelper(object):
1839
2003
 
1840
2004
    def run_selftest(self, **kwargs):
1841
2005
        """Run selftest returning its output."""
1901
2065
            def __call__(test, result):
1902
2066
                test.run(result)
1903
2067
            def run(test, result):
1904
 
                self.assertIsInstance(result, tests.ForwardingResult)
 
2068
                self.assertIsInstance(result, ExtendedToOriginalDecorator)
1905
2069
                calls.append("called")
1906
2070
            def countTestCases(self):
1907
2071
                return 1
1992
2156
            load_list='missing file name', list_only=True)
1993
2157
 
1994
2158
 
 
2159
class TestSubunitLogDetails(tests.TestCase, SelfTestHelper):
 
2160
 
 
2161
    _test_needs_features = [features.subunit]
 
2162
 
 
2163
    def run_subunit_stream(self, test_name):
 
2164
        from subunit import ProtocolTestCase
 
2165
        def factory():
 
2166
            return TestUtil.TestSuite([_get_test(test_name)])
 
2167
        stream = self.run_selftest(runner_class=tests.SubUnitBzrRunner,
 
2168
            test_suite_factory=factory)
 
2169
        test = ProtocolTestCase(stream)
 
2170
        result = testtools.TestResult()
 
2171
        test.run(result)
 
2172
        content = stream.getvalue()
 
2173
        return content, result
 
2174
 
 
2175
    def test_fail_has_log(self):
 
2176
        content, result = self.run_subunit_stream('test_fail')
 
2177
        self.assertEqual(1, len(result.failures))
 
2178
        self.assertContainsRe(content, '(?m)^log$')
 
2179
        self.assertContainsRe(content, 'this test will fail')
 
2180
 
 
2181
    def test_error_has_log(self):
 
2182
        content, result = self.run_subunit_stream('test_error')
 
2183
        self.assertContainsRe(content, '(?m)^log$')
 
2184
        self.assertContainsRe(content, 'this test errored')
 
2185
 
 
2186
    def test_skip_has_no_log(self):
 
2187
        content, result = self.run_subunit_stream('test_skip')
 
2188
        self.assertNotContainsRe(content, '(?m)^log$')
 
2189
        self.assertNotContainsRe(content, 'this test will be skipped')
 
2190
        self.assertEqual(['reason'], result.skip_reasons.keys())
 
2191
        skips = result.skip_reasons['reason']
 
2192
        self.assertEqual(1, len(skips))
 
2193
        test = skips[0]
 
2194
        # RemotedTestCase doesn't preserve the "details"
 
2195
        ## self.assertFalse('log' in test.getDetails())
 
2196
 
 
2197
    def test_missing_feature_has_no_log(self):
 
2198
        content, result = self.run_subunit_stream('test_missing_feature')
 
2199
        self.assertNotContainsRe(content, '(?m)^log$')
 
2200
        self.assertNotContainsRe(content, 'missing the feature')
 
2201
        self.assertEqual(['_MissingFeature\n'], result.skip_reasons.keys())
 
2202
        skips = result.skip_reasons['_MissingFeature\n']
 
2203
        self.assertEqual(1, len(skips))
 
2204
        test = skips[0]
 
2205
        # RemotedTestCase doesn't preserve the "details"
 
2206
        ## self.assertFalse('log' in test.getDetails())
 
2207
 
 
2208
    def test_xfail_has_no_log(self):
 
2209
        content, result = self.run_subunit_stream('test_xfail')
 
2210
        self.assertNotContainsRe(content, '(?m)^log$')
 
2211
        self.assertNotContainsRe(content, 'test with expected failure')
 
2212
        self.assertEqual(1, len(result.expectedFailures))
 
2213
        result_content = result.expectedFailures[0][1]
 
2214
        self.assertNotContainsRe(result_content, 'Text attachment: log')
 
2215
        self.assertNotContainsRe(result_content, 'test with expected failure')
 
2216
 
 
2217
    def test_unexpected_success_has_log(self):
 
2218
        content, result = self.run_subunit_stream('test_unexpected_success')
 
2219
        self.assertContainsRe(content, '(?m)^log$')
 
2220
        self.assertContainsRe(content, 'test with unexpected success')
 
2221
        self.expectFailure('subunit treats "unexpectedSuccess"'
 
2222
                           ' as a plain success',
 
2223
            self.assertEqual, 1, len(result.unexpectedSuccesses))
 
2224
        self.assertEqual(1, len(result.unexpectedSuccesses))
 
2225
        test = result.unexpectedSuccesses[0]
 
2226
        # RemotedTestCase doesn't preserve the "details"
 
2227
        ## self.assertTrue('log' in test.getDetails())
 
2228
 
 
2229
    def test_success_has_no_log(self):
 
2230
        content, result = self.run_subunit_stream('test_success')
 
2231
        self.assertEqual(1, result.testsRun)
 
2232
        self.assertNotContainsRe(content, '(?m)^log$')
 
2233
        self.assertNotContainsRe(content, 'this test succeeds')
 
2234
 
 
2235
 
1995
2236
class TestRunBzr(tests.TestCase):
1996
2237
 
1997
2238
    out = ''
2960
3201
        tpr.register('bar', 'bBB.aAA.rRR')
2961
3202
        self.assertEquals('bbb.aaa.rrr', tpr.get('bar'))
2962
3203
        self.assertThat(self.get_log(),
2963
 
            DocTestMatches("...bar...bbb.aaa.rrr...BB.aAA.rRR", ELLIPSIS))
 
3204
            DocTestMatches("...bar...bbb.aaa.rrr...BB.aAA.rRR",
 
3205
                           doctest.ELLIPSIS))
2964
3206
 
2965
3207
    def test_get_unknown_prefix(self):
2966
3208
        tpr = self._get_registry()
3001
3243
        class Test(unittest.TestCase):
3002
3244
            def runTest(self):
3003
3245
                pass
3004
 
            addCleanup = None # for when on Python 2.7 with native addCleanup
3005
3246
        result = self.LeakRecordingResult()
3006
3247
        test = Test()
3007
 
        self.assertIs(getattr(test, "addCleanup", None), None)
3008
3248
        result.startTestRun()
3009
3249
        test.run(result)
3010
3250
        result.stopTestRun()
3074
3314
        self.assertContainsString(result.stream.getvalue(), "leaking threads")
3075
3315
 
3076
3316
 
 
3317
class TestPostMortemDebugging(tests.TestCase):
 
3318
    """Check post mortem debugging works when tests fail or error"""
 
3319
 
 
3320
    class TracebackRecordingResult(tests.ExtendedTestResult):
 
3321
        def __init__(self):
 
3322
            tests.ExtendedTestResult.__init__(self, StringIO(), 0, 1)
 
3323
            self.postcode = None
 
3324
        def _post_mortem(self, tb=None):
 
3325
            """Record the code object at the end of the current traceback"""
 
3326
            tb = tb or sys.exc_info()[2]
 
3327
            if tb is not None:
 
3328
                next = tb.tb_next
 
3329
                while next is not None:
 
3330
                    tb = next
 
3331
                    next = next.tb_next
 
3332
                self.postcode = tb.tb_frame.f_code
 
3333
        def report_error(self, test, err):
 
3334
            pass
 
3335
        def report_failure(self, test, err):
 
3336
            pass
 
3337
 
 
3338
    def test_location_unittest_error(self):
 
3339
        """Needs right post mortem traceback with erroring unittest case"""
 
3340
        class Test(unittest.TestCase):
 
3341
            def runTest(self):
 
3342
                raise RuntimeError
 
3343
        result = self.TracebackRecordingResult()
 
3344
        Test().run(result)
 
3345
        self.assertEqual(result.postcode, Test.runTest.func_code)
 
3346
 
 
3347
    def test_location_unittest_failure(self):
 
3348
        """Needs right post mortem traceback with failing unittest case"""
 
3349
        class Test(unittest.TestCase):
 
3350
            def runTest(self):
 
3351
                raise self.failureException
 
3352
        result = self.TracebackRecordingResult()
 
3353
        Test().run(result)
 
3354
        self.assertEqual(result.postcode, Test.runTest.func_code)
 
3355
 
 
3356
    def test_location_bt_error(self):
 
3357
        """Needs right post mortem traceback with erroring bzrlib.tests case"""
 
3358
        class Test(tests.TestCase):
 
3359
            def test_error(self):
 
3360
                raise RuntimeError
 
3361
        result = self.TracebackRecordingResult()
 
3362
        Test("test_error").run(result)
 
3363
        self.assertEqual(result.postcode, Test.test_error.func_code)
 
3364
 
 
3365
    def test_location_bt_failure(self):
 
3366
        """Needs right post mortem traceback with failing bzrlib.tests case"""
 
3367
        class Test(tests.TestCase):
 
3368
            def test_failure(self):
 
3369
                raise self.failureException
 
3370
        result = self.TracebackRecordingResult()
 
3371
        Test("test_failure").run(result)
 
3372
        self.assertEqual(result.postcode, Test.test_failure.func_code)
 
3373
 
 
3374
    def test_env_var_triggers_post_mortem(self):
 
3375
        """Check pdb.post_mortem is called iff BZR_TEST_PDB is set"""
 
3376
        import pdb
 
3377
        result = tests.ExtendedTestResult(StringIO(), 0, 1)
 
3378
        post_mortem_calls = []
 
3379
        self.overrideAttr(pdb, "post_mortem", post_mortem_calls.append)
 
3380
        self.overrideEnv('BZR_TEST_PDB', None)
 
3381
        result._post_mortem(1)
 
3382
        self.overrideEnv('BZR_TEST_PDB', 'on')
 
3383
        result._post_mortem(2)
 
3384
        self.assertEqual([2], post_mortem_calls)
 
3385
 
 
3386
 
3077
3387
class TestRunSuite(tests.TestCase):
3078
3388
 
3079
3389
    def test_runner_class(self):
3090
3400
                                                self.verbosity)
3091
3401
        tests.run_suite(suite, runner_class=MyRunner, stream=StringIO())
3092
3402
        self.assertLength(1, calls)
 
3403
 
 
3404
 
 
3405
class TestEnvironHandling(tests.TestCase):
 
3406
 
 
3407
    def test_overrideEnv_None_called_twice_doesnt_leak(self):
 
3408
        self.failIf('MYVAR' in os.environ)
 
3409
        self.overrideEnv('MYVAR', '42')
 
3410
        # We use an embedded test to make sure we fix the _captureVar bug
 
3411
        class Test(tests.TestCase):
 
3412
            def test_me(self):
 
3413
                # The first call save the 42 value
 
3414
                self.overrideEnv('MYVAR', None)
 
3415
                self.assertEquals(None, os.environ.get('MYVAR'))
 
3416
                # Make sure we can call it twice
 
3417
                self.overrideEnv('MYVAR', None)
 
3418
                self.assertEquals(None, os.environ.get('MYVAR'))
 
3419
        output = StringIO()
 
3420
        result = tests.TextTestResult(output, 0, 1)
 
3421
        Test('test_me').run(result)
 
3422
        if not result.wasStrictlySuccessful():
 
3423
            self.fail(output.getvalue())
 
3424
        # We get our value back
 
3425
        self.assertEquals('42', os.environ.get('MYVAR'))
 
3426
 
 
3427
 
 
3428
class TestIsolatedEnv(tests.TestCase):
 
3429
    """Test isolating tests from os.environ.
 
3430
 
 
3431
    Since we use tests that are already isolated from os.environ a bit of care
 
3432
    should be taken when designing the tests to avoid bootstrap side-effects.
 
3433
    The tests start an already clean os.environ which allow doing valid
 
3434
    assertions about which variables are present or not and design tests around
 
3435
    these assertions.
 
3436
    """
 
3437
 
 
3438
    class ScratchMonkey(tests.TestCase):
 
3439
 
 
3440
        def test_me(self):
 
3441
            pass
 
3442
 
 
3443
    def test_basics(self):
 
3444
        # Make sure we know the definition of BZR_HOME: not part of os.environ
 
3445
        # for tests.TestCase.
 
3446
        self.assertTrue('BZR_HOME' in tests.isolated_environ)
 
3447
        self.assertEquals(None, tests.isolated_environ['BZR_HOME'])
 
3448
        # Being part of isolated_environ, BZR_HOME should not appear here
 
3449
        self.assertFalse('BZR_HOME' in os.environ)
 
3450
        # Make sure we know the definition of LINES: part of os.environ for
 
3451
        # tests.TestCase
 
3452
        self.assertTrue('LINES' in tests.isolated_environ)
 
3453
        self.assertEquals('25', tests.isolated_environ['LINES'])
 
3454
        self.assertEquals('25', os.environ['LINES'])
 
3455
 
 
3456
    def test_injecting_unknown_variable(self):
 
3457
        # BZR_HOME is known to be absent from os.environ
 
3458
        test = self.ScratchMonkey('test_me')
 
3459
        tests.override_os_environ(test, {'BZR_HOME': 'foo'})
 
3460
        self.assertEquals('foo', os.environ['BZR_HOME'])
 
3461
        tests.restore_os_environ(test)
 
3462
        self.assertFalse('BZR_HOME' in os.environ)
 
3463
 
 
3464
    def test_injecting_known_variable(self):
 
3465
        test = self.ScratchMonkey('test_me')
 
3466
        # LINES is known to be present in os.environ
 
3467
        tests.override_os_environ(test, {'LINES': '42'})
 
3468
        self.assertEquals('42', os.environ['LINES'])
 
3469
        tests.restore_os_environ(test)
 
3470
        self.assertEquals('25', os.environ['LINES'])
 
3471
 
 
3472
    def test_deleting_variable(self):
 
3473
        test = self.ScratchMonkey('test_me')
 
3474
        # LINES is known to be present in os.environ
 
3475
        tests.override_os_environ(test, {'LINES': None})
 
3476
        self.assertTrue('LINES' not in os.environ)
 
3477
        tests.restore_os_environ(test)
 
3478
        self.assertEquals('25', os.environ['LINES'])
 
3479
 
 
3480
 
 
3481
class TestDocTestSuiteIsolation(tests.TestCase):
 
3482
    """Test that `tests.DocTestSuite` isolates doc tests from os.environ.
 
3483
 
 
3484
    Since tests.TestCase alreay provides an isolation from os.environ, we use
 
3485
    the clean environment as a base for testing. To precisely capture the
 
3486
    isolation provided by tests.DocTestSuite, we use doctest.DocTestSuite to
 
3487
    compare against.
 
3488
 
 
3489
    We want to make sure `tests.DocTestSuite` respect `tests.isolated_environ`,
 
3490
    not `os.environ` so each test overrides it to suit its needs.
 
3491
 
 
3492
    """
 
3493
 
 
3494
    def get_doctest_suite_for_string(self, klass, string):
 
3495
        class Finder(doctest.DocTestFinder):
 
3496
 
 
3497
            def find(*args, **kwargs):
 
3498
                test = doctest.DocTestParser().get_doctest(
 
3499
                    string, {}, 'foo', 'foo.py', 0)
 
3500
                return [test]
 
3501
 
 
3502
        suite = klass(test_finder=Finder())
 
3503
        return suite
 
3504
 
 
3505
    def run_doctest_suite_for_string(self, klass, string):
 
3506
        suite = self.get_doctest_suite_for_string(klass, string)
 
3507
        output = StringIO()
 
3508
        result = tests.TextTestResult(output, 0, 1)
 
3509
        suite.run(result)
 
3510
        return result, output
 
3511
 
 
3512
    def assertDocTestStringSucceds(self, klass, string):
 
3513
        result, output = self.run_doctest_suite_for_string(klass, string)
 
3514
        if not result.wasStrictlySuccessful():
 
3515
            self.fail(output.getvalue())
 
3516
 
 
3517
    def assertDocTestStringFails(self, klass, string):
 
3518
        result, output = self.run_doctest_suite_for_string(klass, string)
 
3519
        if result.wasStrictlySuccessful():
 
3520
            self.fail(output.getvalue())
 
3521
 
 
3522
    def test_injected_variable(self):
 
3523
        self.overrideAttr(tests, 'isolated_environ', {'LINES': '42'})
 
3524
        test = """
 
3525
            >>> import os
 
3526
            >>> os.environ['LINES']
 
3527
            '42'
 
3528
            """
 
3529
        # doctest.DocTestSuite fails as it sees '25'
 
3530
        self.assertDocTestStringFails(doctest.DocTestSuite, test)
 
3531
        # tests.DocTestSuite sees '42'
 
3532
        self.assertDocTestStringSucceds(tests.IsolatedDocTestSuite, test)
 
3533
 
 
3534
    def test_deleted_variable(self):
 
3535
        self.overrideAttr(tests, 'isolated_environ', {'LINES': None})
 
3536
        test = """
 
3537
            >>> import os
 
3538
            >>> os.environ.get('LINES')
 
3539
            """
 
3540
        # doctest.DocTestSuite fails as it sees '25'
 
3541
        self.assertDocTestStringFails(doctest.DocTestSuite, test)
 
3542
        # tests.DocTestSuite sees None
 
3543
        self.assertDocTestStringSucceds(tests.IsolatedDocTestSuite, test)