~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_selftest.py

  • Committer: Wouter van Heyst
  • Date: 2006-06-06 12:06:20 UTC
  • mfrom: (1740 +trunk)
  • mto: This revision was merged to the branch mainline in revision 1752.
  • Revision ID: larstiq@larstiq.dyndns.org-20060606120620-50066b0951e4ef7c
merge bzr.dev 1740

Show diffs side-by-side

added added

removed removed

Lines of Context:
13
13
# along with this program; if not, write to the Free Software
14
14
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
15
15
 
16
 
"""Tests for the test framework
17
 
"""
 
16
"""Tests for the test framework."""
18
17
 
19
18
import os
 
19
from StringIO import StringIO
20
20
import sys
 
21
import time
21
22
import unittest
22
23
import warnings
23
24
 
24
25
import bzrlib
 
26
from bzrlib.progress import _BaseProgressBar
25
27
from bzrlib.tests import (
26
 
                          _load_module_by_name,
27
28
                          ChrootedTestCase,
28
29
                          TestCase,
29
30
                          TestCaseInTempDir,
30
31
                          TestCaseWithTransport,
31
32
                          TestSkipped,
 
33
                          TestSuite,
32
34
                          TextTestRunner,
33
35
                          )
 
36
from bzrlib.tests.TestUtil import _load_module_by_name
34
37
import bzrlib.errors as errors
35
38
 
36
39
 
67
70
        self.failUnlessExists(filename)
68
71
 
69
72
 
70
 
class TestSkippedTest(TestCase):
71
 
    """Try running a test which is skipped, make sure it's reported properly."""
72
 
 
73
 
    def test_skipped_test(self):
74
 
        # must be hidden in here so it's not run as a real test
75
 
        def skipping_test():
76
 
            raise TestSkipped('test intentionally skipped')
77
 
        runner = TextTestRunner(stream=self._log_file)
78
 
        test = unittest.FunctionTestCase(skipping_test)
79
 
        result = runner.run(test)
80
 
        self.assertTrue(result.wasSuccessful())
81
 
 
82
 
 
83
73
class TestTransportProviderAdapter(TestCase):
84
74
    """A group of tests that test the transport implementation adaption core.
85
75
 
385
375
        self.assertEqual(url, t.clone('..').base)
386
376
 
387
377
 
 
378
class MockProgress(_BaseProgressBar):
 
379
    """Progress-bar standin that records calls.
 
380
 
 
381
    Useful for testing pb using code.
 
382
    """
 
383
 
 
384
    def __init__(self):
 
385
        _BaseProgressBar.__init__(self)
 
386
        self.calls = []
 
387
 
 
388
    def tick(self):
 
389
        self.calls.append(('tick',))
 
390
 
 
391
    def update(self, msg=None, current=None, total=None):
 
392
        self.calls.append(('update', msg, current, total))
 
393
 
 
394
    def clear(self):
 
395
        self.calls.append(('clear',))
 
396
 
 
397
 
 
398
class TestTestResult(TestCase):
 
399
 
 
400
    def test_progress_bar_style_quiet(self):
 
401
        # test using a progress bar.
 
402
        dummy_test = TestTestResult('test_progress_bar_style_quiet')
 
403
        dummy_error = (Exception, None, [])
 
404
        mypb = MockProgress()
 
405
        mypb.update('Running tests', 0, 4)
 
406
        last_calls = mypb.calls[:]
 
407
        result = bzrlib.tests._MyResult(self._log_file,
 
408
                                        descriptions=0,
 
409
                                        verbosity=1,
 
410
                                        pb=mypb)
 
411
        self.assertEqual(last_calls, mypb.calls)
 
412
 
 
413
        # an error 
 
414
        result.startTest(dummy_test)
 
415
        # starting a test prints the test name
 
416
        self.assertEqual(last_calls + [('update', '...tyle_quiet', 0, None)], mypb.calls)
 
417
        last_calls = mypb.calls[:]
 
418
        result.addError(dummy_test, dummy_error)
 
419
        self.assertEqual(last_calls + [('update', 'ERROR        ', 1, None)], mypb.calls)
 
420
        last_calls = mypb.calls[:]
 
421
 
 
422
        # a failure
 
423
        result.startTest(dummy_test)
 
424
        self.assertEqual(last_calls + [('update', '...tyle_quiet', 1, None)], mypb.calls)
 
425
        last_calls = mypb.calls[:]
 
426
        result.addFailure(dummy_test, dummy_error)
 
427
        self.assertEqual(last_calls + [('update', 'FAIL         ', 2, None)], mypb.calls)
 
428
        last_calls = mypb.calls[:]
 
429
 
 
430
        # a success
 
431
        result.startTest(dummy_test)
 
432
        self.assertEqual(last_calls + [('update', '...tyle_quiet', 2, None)], mypb.calls)
 
433
        last_calls = mypb.calls[:]
 
434
        result.addSuccess(dummy_test)
 
435
        self.assertEqual(last_calls + [('update', 'OK           ', 3, None)], mypb.calls)
 
436
        last_calls = mypb.calls[:]
 
437
 
 
438
        # a skip
 
439
        result.startTest(dummy_test)
 
440
        self.assertEqual(last_calls + [('update', '...tyle_quiet', 3, None)], mypb.calls)
 
441
        last_calls = mypb.calls[:]
 
442
        result.addSkipped(dummy_test, dummy_error)
 
443
        self.assertEqual(last_calls + [('update', 'SKIP         ', 4, None)], mypb.calls)
 
444
        last_calls = mypb.calls[:]
 
445
 
 
446
    def test_elapsed_time_with_benchmarking(self):
 
447
        result = bzrlib.tests._MyResult(self._log_file,
 
448
                                        descriptions=0,
 
449
                                        verbosity=1,
 
450
                                        )
 
451
        result._recordTestStartTime()
 
452
        time.sleep(0.003)
 
453
        result.extractBenchmarkTime(self)
 
454
        timed_string = result._testTimeString()
 
455
        # without explicit benchmarking, we should get a simple time.
 
456
        self.assertContainsRe(timed_string, "^         [ 1-9][0-9]ms$")
 
457
        # if a benchmark time is given, we want a x of y style result.
 
458
        self.time(time.sleep, 0.001)
 
459
        result.extractBenchmarkTime(self)
 
460
        timed_string = result._testTimeString()
 
461
        self.assertContainsRe(timed_string, "^    [0-9]ms/   [ 1-9][0-9]ms$")
 
462
        # extracting the time from a non-bzrlib testcase sets to None
 
463
        result._recordTestStartTime()
 
464
        result.extractBenchmarkTime(
 
465
            unittest.FunctionTestCase(self.test_elapsed_time_with_benchmarking))
 
466
        timed_string = result._testTimeString()
 
467
        self.assertContainsRe(timed_string, "^          [0-9]ms$")
 
468
        # cheat. Yes, wash thy mouth out with soap.
 
469
        self._benchtime = None
 
470
 
 
471
    def _time_hello_world_encoding(self):
 
472
        """Profile two sleep calls
 
473
        
 
474
        This is used to exercise the test framework.
 
475
        """
 
476
        self.time(unicode, 'hello', errors='replace')
 
477
        self.time(unicode, 'world', errors='replace')
 
478
 
 
479
    def test_lsprofiling(self):
 
480
        """Verbose test result prints lsprof statistics from test cases."""
 
481
        try:
 
482
            import bzrlib.lsprof
 
483
        except ImportError:
 
484
            raise TestSkipped("lsprof not installed.")
 
485
        result_stream = StringIO()
 
486
        result = bzrlib.tests._MyResult(
 
487
            unittest._WritelnDecorator(result_stream),
 
488
            descriptions=0,
 
489
            verbosity=2,
 
490
            )
 
491
        # we want profile a call of some sort and check it is output by
 
492
        # addSuccess. We dont care about addError or addFailure as they
 
493
        # are not that interesting for performance tuning.
 
494
        # make a new test instance that when run will generate a profile
 
495
        example_test_case = TestTestResult("_time_hello_world_encoding")
 
496
        example_test_case._gather_lsprof_in_benchmarks = True
 
497
        # execute the test, which should succeed and record profiles
 
498
        example_test_case.run(result)
 
499
        # lsprofile_something()
 
500
        # if this worked we want 
 
501
        # LSProf output for <built in function unicode> (['hello'], {'errors': 'replace'})
 
502
        #    CallCount    Recursive    Total(ms)   Inline(ms) module:lineno(function)
 
503
        # (the lsprof header)
 
504
        # ... an arbitrary number of lines
 
505
        # and the function call which is time.sleep.
 
506
        #           1        0            ???         ???       ???(sleep) 
 
507
        # and then repeated but with 'world', rather than 'hello'.
 
508
        # this should appear in the output stream of our test result.
 
509
        self.assertContainsRe(result_stream.getvalue(), 
 
510
            r"LSProf output for <type 'unicode'>\(\('hello',\), {'errors': 'replace'}\)\n"
 
511
            r" *CallCount *Recursive *Total\(ms\) *Inline\(ms\) *module:lineno\(function\)\n"
 
512
            r"( +1 +0 +0\.\d+ +0\.\d+ +<method 'disable' of '_lsprof\.Profiler' objects>\n)?"
 
513
            r"LSProf output for <type 'unicode'>\(\('world',\), {'errors': 'replace'}\)\n"
 
514
            r" *CallCount *Recursive *Total\(ms\) *Inline\(ms\) *module:lineno\(function\)\n"
 
515
            r"( +1 +0 +0\.\d+ +0\.\d+ +<method 'disable' of '_lsprof\.Profiler' objects>\n)?"
 
516
            )
 
517
 
 
518
 
 
519
class TestRunner(TestCase):
 
520
 
 
521
    def dummy_test(self):
 
522
        pass
 
523
 
 
524
    def run_test_runner(self, testrunner, test):
 
525
        """Run suite in testrunner, saving global state and restoring it.
 
526
 
 
527
        This current saves and restores:
 
528
        TestCaseInTempDir.TEST_ROOT
 
529
        
 
530
        There should be no tests in this file that use bzrlib.tests.TextTestRunner
 
531
        without using this convenience method, because of our use of global state.
 
532
        """
 
533
        old_root = TestCaseInTempDir.TEST_ROOT
 
534
        try:
 
535
            TestCaseInTempDir.TEST_ROOT = None
 
536
            return testrunner.run(test)
 
537
        finally:
 
538
            TestCaseInTempDir.TEST_ROOT = old_root
 
539
 
 
540
    def test_accepts_and_uses_pb_parameter(self):
 
541
        test = TestRunner('dummy_test')
 
542
        mypb = MockProgress()
 
543
        self.assertEqual([], mypb.calls)
 
544
        runner = TextTestRunner(stream=self._log_file, pb=mypb)
 
545
        result = self.run_test_runner(runner, test)
 
546
        self.assertEqual(1, result.testsRun)
 
547
        self.assertEqual(('update', 'Running tests', 0, 1), mypb.calls[0])
 
548
        self.assertEqual(('update', '...dummy_test', 0, None), mypb.calls[1])
 
549
        self.assertEqual(('update', 'OK           ', 1, None), mypb.calls[2])
 
550
        self.assertEqual(('update', 'Cleaning up', 0, 1), mypb.calls[3])
 
551
        self.assertEqual(('clear',), mypb.calls[4])
 
552
        self.assertEqual(5, len(mypb.calls))
 
553
 
 
554
    def test_skipped_test(self):
 
555
        # run a test that is skipped, and check the suite as a whole still
 
556
        # succeeds.
 
557
        # skipping_test must be hidden in here so it's not run as a real test
 
558
        def skipping_test():
 
559
            raise TestSkipped('test intentionally skipped')
 
560
        runner = TextTestRunner(stream=self._log_file, keep_output=True)
 
561
        test = unittest.FunctionTestCase(skipping_test)
 
562
        result = self.run_test_runner(runner, test)
 
563
        self.assertTrue(result.wasSuccessful())
 
564
 
 
565
 
 
566
class TestTestCase(TestCase):
 
567
    """Tests that test the core bzrlib TestCase."""
 
568
 
 
569
    def inner_test(self):
 
570
        # the inner child test
 
571
        note("inner_test")
 
572
 
 
573
    def outer_child(self):
 
574
        # the outer child test
 
575
        note("outer_start")
 
576
        self.inner_test = TestTestCase("inner_child")
 
577
        result = bzrlib.tests._MyResult(self._log_file,
 
578
                                        descriptions=0,
 
579
                                        verbosity=1)
 
580
        self.inner_test.run(result)
 
581
        note("outer finish")
 
582
 
 
583
    def test_trace_nesting(self):
 
584
        # this tests that each test case nests its trace facility correctly.
 
585
        # we do this by running a test case manually. That test case (A)
 
586
        # should setup a new log, log content to it, setup a child case (B),
 
587
        # which should log independently, then case (A) should log a trailer
 
588
        # and return.
 
589
        # we do two nested children so that we can verify the state of the 
 
590
        # logs after the outer child finishes is correct, which a bad clean
 
591
        # up routine in tearDown might trigger a fault in our test with only
 
592
        # one child, we should instead see the bad result inside our test with
 
593
        # the two children.
 
594
        # the outer child test
 
595
        original_trace = bzrlib.trace._trace_file
 
596
        outer_test = TestTestCase("outer_child")
 
597
        result = bzrlib.tests._MyResult(self._log_file,
 
598
                                        descriptions=0,
 
599
                                        verbosity=1)
 
600
        outer_test.run(result)
 
601
        self.assertEqual(original_trace, bzrlib.trace._trace_file)
 
602
 
 
603
    def method_that_times_a_bit_twice(self):
 
604
        # call self.time twice to ensure it aggregates
 
605
        self.time(time.sleep, 0.007)
 
606
        self.time(time.sleep, 0.007)
 
607
 
 
608
    def test_time_creates_benchmark_in_result(self):
 
609
        """Test that the TestCase.time() method accumulates a benchmark time."""
 
610
        sample_test = TestTestCase("method_that_times_a_bit_twice")
 
611
        output_stream = StringIO()
 
612
        result = bzrlib.tests._MyResult(
 
613
            unittest._WritelnDecorator(output_stream),
 
614
            descriptions=0,
 
615
            verbosity=2)
 
616
        sample_test.run(result)
 
617
        self.assertContainsRe(
 
618
            output_stream.getvalue(),
 
619
            "[1-9][0-9]ms/   [1-9][0-9]ms\n$")
 
620
        
 
621
    def test__gather_lsprof_in_benchmarks(self):
 
622
        """When _gather_lsprof_in_benchmarks is on, accumulate profile data.
 
623
        
 
624
        Each self.time() call is individually and separately profiled.
 
625
        """
 
626
        try:
 
627
            import bzrlib.lsprof
 
628
        except ImportError:
 
629
            raise TestSkipped("lsprof not installed.")
 
630
        # overrides the class member with an instance member so no cleanup 
 
631
        # needed.
 
632
        self._gather_lsprof_in_benchmarks = True
 
633
        self.time(time.sleep, 0.000)
 
634
        self.time(time.sleep, 0.003)
 
635
        self.assertEqual(2, len(self._benchcalls))
 
636
        self.assertEqual((time.sleep, (0.000,), {}), self._benchcalls[0][0])
 
637
        self.assertEqual((time.sleep, (0.003,), {}), self._benchcalls[1][0])
 
638
        self.assertIsInstance(self._benchcalls[0][1], bzrlib.lsprof.Stats)
 
639
        self.assertIsInstance(self._benchcalls[1][1], bzrlib.lsprof.Stats)
 
640
 
 
641
 
388
642
class TestExtraAssertions(TestCase):
389
643
    """Tests for new test assertions in bzrlib test suite"""
390
644
 
410
664
                              bzrlib.bzrdir.BzrDirMetaFormat1)
411
665
        self.assertIsInstance(bzrlib.bzrdir.BzrDir.open('b')._format,
412
666
                              bzrlib.bzrdir.BzrDirFormat6)
 
667
 
 
668
 
 
669
class TestSelftest(TestCase):
 
670
    """Tests of bzrlib.tests.selftest."""
 
671
 
 
672
    def test_selftest_benchmark_parameter_invokes_test_suite__benchmark__(self):
 
673
        factory_called = []
 
674
        def factory():
 
675
            factory_called.append(True)
 
676
            return TestSuite()
 
677
        out = StringIO()
 
678
        err = StringIO()
 
679
        self.apply_redirected(out, err, None, bzrlib.tests.selftest, 
 
680
            test_suite_factory=factory)
 
681
        self.assertEqual([True], factory_called)