~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_selftest.py

  • Committer: Martin von Gagern
  • Date: 2011-06-01 12:53:56 UTC
  • mto: This revision was merged to the branch mainline in revision 6009.
  • Revision ID: martin.vgagern@gmx.net-20110601125356-lwozv2vecea6hxfz
Change from no_decorate to classify as name for the argument.

The command line switch remains as --no-classify, to keep backwards
compatibility.  Users are free to include --no-classify in an alias, and
still use --classify to change back.

Show diffs side-by-side

added added

removed removed

Lines of Context:
29
29
from testtools import (
30
30
    ExtendedToOriginalDecorator,
31
31
    MultiTestResult,
32
 
    __version__ as testtools_version,
33
32
    )
34
33
from testtools.content import Content
35
34
from testtools.content_type import ContentType
44
43
    branchbuilder,
45
44
    bzrdir,
46
45
    errors,
47
 
    hooks,
48
46
    lockdir,
49
47
    memorytree,
50
48
    osutils,
94
92
            DocTestMatches(u"...a test message\n", doctest.ELLIPSIS))
95
93
 
96
94
 
 
95
class TestUnicodeFilename(tests.TestCase):
 
96
 
 
97
    def test_probe_passes(self):
 
98
        """UnicodeFilename._probe passes."""
 
99
        # We can't test much more than that because the behaviour depends
 
100
        # on the platform.
 
101
        tests.UnicodeFilename._probe()
 
102
 
 
103
 
97
104
class TestTreeShape(tests.TestCaseInTempDir):
98
105
 
99
106
    def test_unicode_paths(self):
100
 
        self.requireFeature(features.UnicodeFilenameFeature)
 
107
        self.requireFeature(tests.UnicodeFilename)
101
108
 
102
109
        filename = u'hell\u00d8'
103
110
        self.build_tree_contents([(filename, 'contents of hello')])
619
626
    def test_dangling_locks_cause_failures(self):
620
627
        class TestDanglingLock(tests.TestCaseWithMemoryTransport):
621
628
            def test_function(self):
622
 
                t = self.get_transport_from_path('.')
 
629
                t = self.get_transport('.')
623
630
                l = lockdir.LockDir(t, 'lock')
624
631
                l.create()
625
632
                l.attempt_lock()
645
652
        # for the server
646
653
        url = self.get_readonly_url()
647
654
        url2 = self.get_readonly_url('foo/bar')
648
 
        t = transport.get_transport_from_url(url)
649
 
        t2 = transport.get_transport_from_url(url2)
 
655
        t = transport.get_transport(url)
 
656
        t2 = transport.get_transport(url2)
650
657
        self.assertIsInstance(t, ReadonlyTransportDecorator)
651
658
        self.assertIsInstance(t2, ReadonlyTransportDecorator)
652
659
        self.assertEqual(t2.base[:-1], t.abspath('foo/bar'))
660
667
        url = self.get_readonly_url()
661
668
        url2 = self.get_readonly_url('foo/bar')
662
669
        # the transport returned may be any HttpTransportBase subclass
663
 
        t = transport.get_transport_from_url(url)
664
 
        t2 = transport.get_transport_from_url(url2)
 
670
        t = transport.get_transport(url)
 
671
        t2 = transport.get_transport(url2)
665
672
        self.assertIsInstance(t, HttpTransportBase)
666
673
        self.assertIsInstance(t2, HttpTransportBase)
667
674
        self.assertEqual(t2.base[:-1], t.abspath('foo/bar'))
705
712
class TestChrootedTest(tests.ChrootedTestCase):
706
713
 
707
714
    def test_root_is_root(self):
708
 
        t = transport.get_transport_from_url(self.get_readonly_url())
 
715
        t = transport.get_transport(self.get_readonly_url())
709
716
        url = t.base
710
717
        self.assertEqual(url, t.clone('..').base)
711
718
 
713
720
class TestProfileResult(tests.TestCase):
714
721
 
715
722
    def test_profiles_tests(self):
716
 
        self.requireFeature(features.lsprof_feature)
 
723
        self.requireFeature(test_lsprof.LSProfFeature)
717
724
        terminal = testtools.testresult.doubles.ExtendedTestResult()
718
725
        result = tests.ProfileResult(terminal)
719
726
        class Sample(tests.TestCase):
774
781
 
775
782
    def test_lsprofiling(self):
776
783
        """Verbose test result prints lsprof statistics from test cases."""
777
 
        self.requireFeature(features.lsprof_feature)
 
784
        self.requireFeature(test_lsprof.LSProfFeature)
778
785
        result_stream = StringIO()
779
786
        result = bzrlib.tests.VerboseTestResult(
780
787
            result_stream,
825
832
        self.assertEndsWith(sio.getvalue(), "OK    50002ms\n")
826
833
 
827
834
    def test_known_failure(self):
828
 
        """Using knownFailure should trigger several result actions."""
 
835
        """A KnownFailure being raised should trigger several result actions."""
829
836
        class InstrumentedTestResult(tests.ExtendedTestResult):
830
837
            def stopTestRun(self): pass
831
838
            def report_tests_starting(self): pass
834
841
        result = InstrumentedTestResult(None, None, None, None)
835
842
        class Test(tests.TestCase):
836
843
            def test_function(self):
837
 
                self.knownFailure('failed!')
 
844
                raise tests.KnownFailure('failed!')
838
845
        test = Test("test_function")
839
846
        test.run(result)
840
847
        # it should invoke 'report_known_failure'.
856
863
            descriptions=0,
857
864
            verbosity=2,
858
865
            )
859
 
        _get_test("test_xfail").run(result)
860
 
        self.assertContainsRe(result_stream.getvalue(),
861
 
            "\n\\S+\\.test_xfail\\s+XFAIL\\s+\\d+ms\n"
862
 
            "\\s*(?:Text attachment: )?reason"
863
 
            "(?:\n-+\n|: {{{)"
864
 
            "this_fails"
865
 
            "(?:\n-+\n|}}}\n)")
 
866
        test = self.get_passing_test()
 
867
        result.startTest(test)
 
868
        prefix = len(result_stream.getvalue())
 
869
        # the err parameter has the shape:
 
870
        # (class, exception object, traceback)
 
871
        # KnownFailures dont get their tracebacks shown though, so we
 
872
        # can skip that.
 
873
        err = (tests.KnownFailure, tests.KnownFailure('foo'), None)
 
874
        result.report_known_failure(test, err)
 
875
        output = result_stream.getvalue()[prefix:]
 
876
        lines = output.splitlines()
 
877
        self.assertContainsRe(lines[0], r'XFAIL *\d+ms$')
 
878
        if sys.version_info > (2, 7):
 
879
            self.expectFailure("_ExpectedFailure on 2.7 loses the message",
 
880
                self.assertNotEqual, lines[1], '    ')
 
881
        self.assertEqual(lines[1], '    foo')
 
882
        self.assertEqual(2, len(lines))
866
883
 
867
884
    def get_passing_test(self):
868
885
        """Return a test object that can't be run usefully."""
879
896
                self._call = test, feature
880
897
        result = InstrumentedTestResult(None, None, None, None)
881
898
        test = SampleTestCase('_test_pass')
882
 
        feature = features.Feature()
 
899
        feature = tests.Feature()
883
900
        result.startTest(test)
884
901
        result.addNotSupported(test, feature)
885
902
        # it should invoke 'report_unsupported'.
904
921
            verbosity=2,
905
922
            )
906
923
        test = self.get_passing_test()
907
 
        feature = features.Feature()
 
924
        feature = tests.Feature()
908
925
        result.startTest(test)
909
926
        prefix = len(result_stream.getvalue())
910
927
        result.report_unsupported(test, feature)
923
940
            def addNotSupported(self, test, feature):
924
941
                self._call = test, feature
925
942
        result = InstrumentedTestResult(None, None, None, None)
926
 
        feature = features.Feature()
 
943
        feature = tests.Feature()
927
944
        class Test(tests.TestCase):
928
945
            def test_function(self):
929
946
                raise tests.UnavailableFeature(feature)
948
965
    def test_strict_with_known_failure(self):
949
966
        result = bzrlib.tests.TextTestResult(self._log_file, descriptions=0,
950
967
                                             verbosity=1)
951
 
        test = _get_test("test_xfail")
952
 
        test.run(result)
 
968
        test = self.get_passing_test()
 
969
        err = (tests.KnownFailure, tests.KnownFailure('foo'), None)
 
970
        result.addExpectedFailure(test, err)
953
971
        self.assertFalse(result.wasStrictlySuccessful())
954
972
        self.assertEqual(None, result._extractBenchmarkTime(test))
955
973
 
987
1005
        self.assertEquals(2, result.count)
988
1006
 
989
1007
 
 
1008
class TestUnicodeFilenameFeature(tests.TestCase):
 
1009
 
 
1010
    def test_probe_passes(self):
 
1011
        """UnicodeFilenameFeature._probe passes."""
 
1012
        # We can't test much more than that because the behaviour depends
 
1013
        # on the platform.
 
1014
        tests.UnicodeFilenameFeature._probe()
 
1015
 
 
1016
 
990
1017
class TestRunner(tests.TestCase):
991
1018
 
992
1019
    def dummy_test(self):
1062
1089
                self.expectFailure("No absolute truth", self.assertTrue, True)
1063
1090
        runner = tests.TextTestRunner(stream=StringIO())
1064
1091
        result = self.run_test_runner(runner, Test("test_truth"))
1065
 
        if testtools_version[:3] <= (0, 9, 11):
1066
 
            self.assertContainsRe(runner.stream.getvalue(),
1067
 
                "=+\n"
1068
 
                "FAIL: \\S+\.test_truth\n"
1069
 
                "-+\n"
1070
 
                "(?:.*\n)*"
1071
 
                "No absolute truth\n"
1072
 
                "(?:.*\n)*"
1073
 
                "-+\n"
1074
 
                "Ran 1 test in .*\n"
1075
 
                "\n"
1076
 
                "FAILED \\(failures=1\\)\n\\Z")
1077
 
        else:
1078
 
            self.assertContainsRe(runner.stream.getvalue(),
1079
 
                "=+\n"
1080
 
                "FAIL: \\S+\.test_truth\n"
1081
 
                "-+\n"
1082
 
                "Empty attachments:\n"
1083
 
                "  log\n"
1084
 
                "\n"
1085
 
                "reason: {{{No absolute truth}}}\n"
1086
 
                "-+\n"
1087
 
                "Ran 1 test in .*\n"
1088
 
                "\n"
1089
 
                "FAILED \\(failures=1\\)\n\\Z")
 
1092
        self.assertContainsRe(runner.stream.getvalue(),
 
1093
            "=+\n"
 
1094
            "FAIL: \\S+\.test_truth\n"
 
1095
            "-+\n"
 
1096
            "(?:.*\n)*"
 
1097
            "No absolute truth\n"
 
1098
            "(?:.*\n)*"
 
1099
            "-+\n"
 
1100
            "Ran 1 test in .*\n"
 
1101
            "\n"
 
1102
            "FAILED \\(failures=1\\)\n\\Z")
1090
1103
 
1091
1104
    def test_result_decorator(self):
1092
1105
        # decorate results
1177
1190
 
1178
1191
    def test_unsupported_features_listed(self):
1179
1192
        """When unsupported features are encountered they are detailed."""
1180
 
        class Feature1(features.Feature):
 
1193
        class Feature1(tests.Feature):
1181
1194
            def _probe(self): return False
1182
 
        class Feature2(features.Feature):
 
1195
        class Feature2(tests.Feature):
1183
1196
            def _probe(self): return False
1184
1197
        # create sample tests
1185
1198
        test1 = SampleTestCase('_test_pass')
1251
1264
            lambda trace=False: "ascii")
1252
1265
        result = self.run_test_runner(tests.TextTestRunner(stream=out),
1253
1266
            FailureWithUnicode("test_log_unicode"))
1254
 
        if testtools_version[:3] > (0, 9, 11):
1255
 
            self.assertContainsRe(out.getvalue(), "log: {{{\d+\.\d+  \\\\u2606}}}")
1256
 
        else:
1257
 
            self.assertContainsRe(out.getvalue(),
1258
 
                "Text attachment: log\n"
1259
 
                "-+\n"
1260
 
                "\d+\.\d+  \\\\u2606\n"
1261
 
                "-+\n")
 
1267
        self.assertContainsRe(out.getvalue(),
 
1268
            "Text attachment: log\n"
 
1269
            "-+\n"
 
1270
            "\d+\.\d+  \\\\u2606\n"
 
1271
            "-+\n")
1262
1272
 
1263
1273
 
1264
1274
class SampleTestCase(tests.TestCase):
1465
1475
 
1466
1476
        Each self.time() call is individually and separately profiled.
1467
1477
        """
1468
 
        self.requireFeature(features.lsprof_feature)
 
1478
        self.requireFeature(test_lsprof.LSProfFeature)
1469
1479
        # overrides the class member with an instance member so no cleanup
1470
1480
        # needed.
1471
1481
        self._gather_lsprof_in_benchmarks = True
1490
1500
        transport_server = memory.MemoryServer()
1491
1501
        transport_server.start_server()
1492
1502
        self.addCleanup(transport_server.stop_server)
1493
 
        t = transport.get_transport_from_url(transport_server.get_url())
 
1503
        t = transport.get_transport(transport_server.get_url())
1494
1504
        bzrdir.BzrDir.create(t.base)
1495
1505
        self.assertRaises(errors.BzrError,
1496
1506
            bzrdir.BzrDir.open_from_transport, t)
1501
1511
 
1502
1512
    def test_requireFeature_available(self):
1503
1513
        """self.requireFeature(available) is a no-op."""
1504
 
        class Available(features.Feature):
 
1514
        class Available(tests.Feature):
1505
1515
            def _probe(self):return True
1506
1516
        feature = Available()
1507
1517
        self.requireFeature(feature)
1508
1518
 
1509
1519
    def test_requireFeature_unavailable(self):
1510
1520
        """self.requireFeature(unavailable) raises UnavailableFeature."""
1511
 
        class Unavailable(features.Feature):
 
1521
        class Unavailable(tests.Feature):
1512
1522
            def _probe(self):return False
1513
1523
        feature = Unavailable()
1514
1524
        self.assertRaises(tests.UnavailableFeature,
1673
1683
        test.run(unittest.TestResult())
1674
1684
        self.assertEqual('original', obj.test_attr)
1675
1685
 
1676
 
    def test_recordCalls(self):
1677
 
        from bzrlib.tests import test_selftest
1678
 
        calls = self.recordCalls(
1679
 
            test_selftest, '_add_numbers')
1680
 
        self.assertEqual(test_selftest._add_numbers(2, 10),
1681
 
            12)
1682
 
        self.assertEquals(calls, [((2, 10), {})])
1683
 
 
1684
 
 
1685
 
def _add_numbers(a, b):
1686
 
    return a + b
1687
 
 
1688
 
 
1689
 
class _MissingFeature(features.Feature):
 
1686
 
 
1687
class _MissingFeature(tests.Feature):
1690
1688
    def _probe(self):
1691
1689
        return False
1692
1690
missing_feature = _MissingFeature()
1743
1741
        result = self._run_test('test_fail')
1744
1742
        self.assertEqual(1, len(result.failures))
1745
1743
        result_content = result.failures[0][1]
1746
 
        if testtools_version < (0, 9, 12):
1747
 
            self.assertContainsRe(result_content, 'Text attachment: log')
 
1744
        self.assertContainsRe(result_content, 'Text attachment: log')
1748
1745
        self.assertContainsRe(result_content, 'this was a failing test')
1749
1746
 
1750
1747
    def test_error_has_log(self):
1751
1748
        result = self._run_test('test_error')
1752
1749
        self.assertEqual(1, len(result.errors))
1753
1750
        result_content = result.errors[0][1]
1754
 
        if testtools_version < (0, 9, 12):
1755
 
            self.assertContainsRe(result_content, 'Text attachment: log')
 
1751
        self.assertContainsRe(result_content, 'Text attachment: log')
1756
1752
        self.assertContainsRe(result_content, 'this test errored')
1757
1753
 
1758
1754
    def test_skip_has_no_log(self):
2040
2036
        self.assertLength(2, output.readlines())
2041
2037
 
2042
2038
    def test_lsprof_tests(self):
2043
 
        self.requireFeature(features.lsprof_feature)
 
2039
        self.requireFeature(test_lsprof.LSProfFeature)
2044
2040
        results = []
2045
2041
        class Test(object):
2046
2042
            def __call__(test, result):
2509
2505
 
2510
2506
 
2511
2507
class TestStartBzrSubProcess(tests.TestCase):
2512
 
    """Stub test start_bzr_subprocess."""
2513
2508
 
2514
 
    def _subprocess_log_cleanup(self):
2515
 
        """Inhibits the base version as we don't produce a log file."""
 
2509
    def check_popen_state(self):
 
2510
        """Replace to make assertions when popen is called."""
2516
2511
 
2517
2512
    def _popen(self, *args, **kwargs):
2518
 
        """Override the base version to record the command that is run.
2519
 
 
2520
 
        From there we can ensure it is correct without spawning a real process.
2521
 
        """
 
2513
        """Record the command that is run, so that we can ensure it is correct"""
2522
2514
        self.check_popen_state()
2523
2515
        self._popen_args = args
2524
2516
        self._popen_kwargs = kwargs
2525
2517
        raise _DontSpawnProcess()
2526
2518
 
2527
 
    def check_popen_state(self):
2528
 
        """Replace to make assertions when popen is called."""
2529
 
 
2530
2519
    def test_run_bzr_subprocess_no_plugins(self):
2531
2520
        self.assertRaises(_DontSpawnProcess, self.start_bzr_subprocess, [])
2532
2521
        command = self._popen_args[0]
2536
2525
 
2537
2526
    def test_allow_plugins(self):
2538
2527
        self.assertRaises(_DontSpawnProcess, self.start_bzr_subprocess, [],
2539
 
                          allow_plugins=True)
 
2528
            allow_plugins=True)
2540
2529
        command = self._popen_args[0]
2541
2530
        self.assertEqual([], command[2:])
2542
2531
 
2547
2536
            self.assertEqual('set variable', os.environ['EXISTANT_ENV_VAR'])
2548
2537
        self.check_popen_state = check_environment
2549
2538
        self.assertRaises(_DontSpawnProcess, self.start_bzr_subprocess, [],
2550
 
                          env_changes={'EXISTANT_ENV_VAR':'set variable'})
 
2539
            env_changes={'EXISTANT_ENV_VAR':'set variable'})
2551
2540
        # not set in theparent
2552
2541
        self.assertFalse('EXISTANT_ENV_VAR' in os.environ)
2553
2542
 
2559
2548
        os.environ['EXISTANT_ENV_VAR'] = 'set variable'
2560
2549
        self.check_popen_state = check_environment
2561
2550
        self.assertRaises(_DontSpawnProcess, self.start_bzr_subprocess, [],
2562
 
                          env_changes={'EXISTANT_ENV_VAR':None})
 
2551
            env_changes={'EXISTANT_ENV_VAR':None})
2563
2552
        # Still set in parent
2564
2553
        self.assertEqual('set variable', os.environ['EXISTANT_ENV_VAR'])
2565
2554
        del os.environ['EXISTANT_ENV_VAR']
2570
2559
            self.assertFalse('NON_EXISTANT_ENV_VAR' in os.environ)
2571
2560
        self.check_popen_state = check_environment
2572
2561
        self.assertRaises(_DontSpawnProcess, self.start_bzr_subprocess, [],
2573
 
                          env_changes={'NON_EXISTANT_ENV_VAR':None})
 
2562
            env_changes={'NON_EXISTANT_ENV_VAR':None})
2574
2563
 
2575
2564
    def test_working_dir(self):
2576
2565
        """Test that we can specify the working dir for the child"""
2579
2568
        chdirs = []
2580
2569
        def chdir(path):
2581
2570
            chdirs.append(path)
2582
 
        self.overrideAttr(os, 'chdir', chdir)
2583
 
        def getcwd():
2584
 
            return 'current'
2585
 
        self.overrideAttr(osutils, 'getcwd', getcwd)
2586
 
        self.assertRaises(_DontSpawnProcess, self.start_bzr_subprocess, [],
2587
 
                          working_dir='foo')
 
2571
        os.chdir = chdir
 
2572
        try:
 
2573
            def getcwd():
 
2574
                return 'current'
 
2575
            osutils.getcwd = getcwd
 
2576
            try:
 
2577
                self.assertRaises(_DontSpawnProcess, self.start_bzr_subprocess, [],
 
2578
                    working_dir='foo')
 
2579
            finally:
 
2580
                osutils.getcwd = orig_getcwd
 
2581
        finally:
 
2582
            os.chdir = orig_chdir
2588
2583
        self.assertEqual(['foo', 'current'], chdirs)
2589
2584
 
2590
2585
    def test_get_bzr_path_with_cwd_bzrlib(self):
2610
2605
        self.assertEqual('bzr: interrupted\n', result[1])
2611
2606
 
2612
2607
 
 
2608
class TestFeature(tests.TestCase):
 
2609
 
 
2610
    def test_caching(self):
 
2611
        """Feature._probe is called by the feature at most once."""
 
2612
        class InstrumentedFeature(tests.Feature):
 
2613
            def __init__(self):
 
2614
                super(InstrumentedFeature, self).__init__()
 
2615
                self.calls = []
 
2616
            def _probe(self):
 
2617
                self.calls.append('_probe')
 
2618
                return False
 
2619
        feature = InstrumentedFeature()
 
2620
        feature.available()
 
2621
        self.assertEqual(['_probe'], feature.calls)
 
2622
        feature.available()
 
2623
        self.assertEqual(['_probe'], feature.calls)
 
2624
 
 
2625
    def test_named_str(self):
 
2626
        """Feature.__str__ should thunk to feature_name()."""
 
2627
        class NamedFeature(tests.Feature):
 
2628
            def feature_name(self):
 
2629
                return 'symlinks'
 
2630
        feature = NamedFeature()
 
2631
        self.assertEqual('symlinks', str(feature))
 
2632
 
 
2633
    def test_default_str(self):
 
2634
        """Feature.__str__ should default to __class__.__name__."""
 
2635
        class NamedFeature(tests.Feature):
 
2636
            pass
 
2637
        feature = NamedFeature()
 
2638
        self.assertEqual('NamedFeature', str(feature))
 
2639
 
 
2640
 
 
2641
class TestUnavailableFeature(tests.TestCase):
 
2642
 
 
2643
    def test_access_feature(self):
 
2644
        feature = tests.Feature()
 
2645
        exception = tests.UnavailableFeature(feature)
 
2646
        self.assertIs(feature, exception.args[0])
 
2647
 
 
2648
 
 
2649
simple_thunk_feature = tests._CompatabilityThunkFeature(
 
2650
    deprecated_in((2, 1, 0)),
 
2651
    'bzrlib.tests.test_selftest',
 
2652
    'simple_thunk_feature','UnicodeFilename',
 
2653
    replacement_module='bzrlib.tests'
 
2654
    )
 
2655
 
 
2656
class Test_CompatibilityFeature(tests.TestCase):
 
2657
 
 
2658
    def test_does_thunk(self):
 
2659
        res = self.callDeprecated(
 
2660
            ['bzrlib.tests.test_selftest.simple_thunk_feature was deprecated'
 
2661
             ' in version 2.1.0. Use bzrlib.tests.UnicodeFilename instead.'],
 
2662
            simple_thunk_feature.available)
 
2663
        self.assertEqual(tests.UnicodeFilename.available(), res)
 
2664
 
 
2665
 
 
2666
class TestModuleAvailableFeature(tests.TestCase):
 
2667
 
 
2668
    def test_available_module(self):
 
2669
        feature = tests.ModuleAvailableFeature('bzrlib.tests')
 
2670
        self.assertEqual('bzrlib.tests', feature.module_name)
 
2671
        self.assertEqual('bzrlib.tests', str(feature))
 
2672
        self.assertTrue(feature.available())
 
2673
        self.assertIs(tests, feature.module)
 
2674
 
 
2675
    def test_unavailable_module(self):
 
2676
        feature = tests.ModuleAvailableFeature('bzrlib.no_such_module_exists')
 
2677
        self.assertEqual('bzrlib.no_such_module_exists', str(feature))
 
2678
        self.assertFalse(feature.available())
 
2679
        self.assertIs(None, feature.module)
 
2680
 
 
2681
 
2613
2682
class TestSelftestFiltering(tests.TestCase):
2614
2683
 
2615
2684
    def setUp(self):
3490
3559
 
3491
3560
    def test_mutiple_excludes(self):
3492
3561
        self.assertTestList(['c'], '-x', 'a', '-x', 'b')
3493
 
 
3494
 
 
3495
 
class TestCounterHooks(tests.TestCase, SelfTestHelper):
3496
 
 
3497
 
    _test_needs_features = [features.subunit]
3498
 
 
3499
 
    def setUp(self):
3500
 
        super(TestCounterHooks, self).setUp()
3501
 
        class Test(tests.TestCase):
3502
 
 
3503
 
            def setUp(self):
3504
 
                super(Test, self).setUp()
3505
 
                self.hooks = hooks.Hooks()
3506
 
                self.hooks.add_hook('myhook', 'Foo bar blah', (2,4))
3507
 
                self.install_counter_hook(self.hooks, 'myhook')
3508
 
 
3509
 
            def no_hook(self):
3510
 
                pass
3511
 
 
3512
 
            def run_hook_once(self):
3513
 
                for hook in self.hooks['myhook']:
3514
 
                    hook(self)
3515
 
 
3516
 
        self.test_class = Test
3517
 
 
3518
 
    def assertHookCalls(self, expected_calls, test_name):
3519
 
        test = self.test_class(test_name)
3520
 
        result = unittest.TestResult()
3521
 
        test.run(result)
3522
 
        self.assertTrue(hasattr(test, '_counters'))
3523
 
        self.assertTrue(test._counters.has_key('myhook'))
3524
 
        self.assertEquals(expected_calls, test._counters['myhook'])
3525
 
 
3526
 
    def test_no_hook(self):
3527
 
        self.assertHookCalls(0, 'no_hook')
3528
 
 
3529
 
    def test_run_hook_once(self):
3530
 
        tt = features.testtools
3531
 
        if tt.module.__version__ < (0, 9, 8):
3532
 
            raise tests.TestSkipped('testtools-0.9.8 required for addDetail')
3533
 
        self.assertHookCalls(1, 'run_hook_once')