~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/__init__.py

merge from integration.

Show diffs side-by-side

added added

removed removed

Lines of Context:
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
17
17
 
 
18
# TODO: Perhaps there should be an API to find out if bzr running under the
 
19
# test suite -- some plugins might want to avoid making intrusive changes if
 
20
# this is the case.  However, we want behaviour under to test to diverge as
 
21
# little as possible, so this should be used rarely if it's added at all.
 
22
# (Suggestion from j-a-meinel, 2005-11-24)
 
23
 
18
24
from cStringIO import StringIO
19
25
import difflib
20
26
import errno
22
28
import os
23
29
import re
24
30
import shutil
 
31
import stat
25
32
import sys
26
33
import tempfile
27
34
import unittest
38
45
import bzrlib.plugin
39
46
import bzrlib.store
40
47
import bzrlib.trace
 
48
from bzrlib.transport import urlescape
 
49
import bzrlib.transport
 
50
from bzrlib.transport.readonly import ReadonlyServer
41
51
from bzrlib.trace import mutter
42
52
from bzrlib.tests.TestUtil import TestLoader, TestSuite
43
53
from bzrlib.tests.treeshape import build_tree_contents
66
76
        self._result = result
67
77
 
68
78
    def addError(self, test, err):
 
79
        if (isinstance(err[1], TestSkipped) and 
 
80
            getattr(self, "addSkipped", None) is not None):
 
81
            return self.addSkipped(test, err)    
69
82
        self._result.addError(test, err)
70
83
        self._result.stop()
71
84
 
157
170
    def printErrorList(self, flavour, errors):
158
171
        for test, err in errors:
159
172
            self.stream.writeln(self.separator1)
160
 
            self.stream.writeln("%s: %s" % (flavour,self.getDescription(test)))
161
 
            if hasattr(test, '_get_log'):
 
173
            self.stream.writeln("%s: %s" % (flavour, self.getDescription(test)))
 
174
            if getattr(test, '_get_log', None) is not None:
162
175
                print >>self.stream
163
176
                print >>self.stream, \
164
 
                        ('vvvv[log from %s]' % test).ljust(78,'-')
 
177
                        ('vvvv[log from %s]' % test.id()).ljust(78,'-')
165
178
                print >>self.stream, test._get_log()
166
179
                print >>self.stream, \
167
 
                        ('^^^^[log from %s]' % test).ljust(78,'-')
 
180
                        ('^^^^[log from %s]' % test.id()).ljust(78,'-')
168
181
            self.stream.writeln(self.separator2)
169
182
            self.stream.writeln("%s" % err)
170
183
 
225
238
    _log_file_name = None
226
239
    _log_contents = ''
227
240
 
 
241
    def __init__(self, methodName='testMethod'):
 
242
        super(TestCase, self).__init__(methodName)
 
243
        self._cleanups = []
 
244
 
228
245
    def setUp(self):
229
246
        unittest.TestCase.setUp(self)
230
 
        self._cleanups = []
231
247
        self._cleanEnvironment()
232
248
        bzrlib.trace.disable_default_logging()
233
249
        self._startLogFile()
283
299
            raise AssertionError("value(s) %r not present in container %r" % 
284
300
                                 (missing, superlist))
285
301
 
 
302
    def assertTransportMode(self, transport, path, mode):
 
303
        """Fail if a path does not have mode mode.
 
304
        
 
305
        If modes are not supported on this platform, the test is skipped.
 
306
        """
 
307
        if sys.platform == 'win32':
 
308
            return
 
309
        path_stat = transport.stat(path)
 
310
        actual_mode = stat.S_IMODE(path_stat.st_mode)
 
311
        self.assertEqual(mode, actual_mode,
 
312
            'mode of %r incorrect (%o != %o)' % (path, mode, actual_mode))
 
313
 
286
314
    def _startLogFile(self):
287
315
        """Send bzr and test log messages to a temporary file.
288
316
 
361
389
 
362
390
        This should only be called from TestCase.tearDown.
363
391
        """
 
392
        # TODO: Perhaps this should keep running cleanups even if 
 
393
        # one of them fails?
364
394
        for cleanup_fn in reversed(self._cleanups):
365
395
            cleanup_fn()
366
396
 
467
497
        if stdin is None:
468
498
            stdin = StringIO("")
469
499
        if stdout is None:
470
 
            if hasattr(self, "_log_file"):
 
500
            if getattr(self, "_log_file", None) is not None:
471
501
                stdout = self._log_file
472
502
            else:
473
503
                stdout = StringIO()
474
504
        if stderr is None:
475
 
            if hasattr(self, "_log_file"):
 
505
            if getattr(self, "_log_file", None is not None):
476
506
                stderr = self._log_file
477
507
            else:
478
508
                stderr = StringIO()
554
584
            os.chdir(_currentdir)
555
585
        self.addCleanup(_leaveDirectory)
556
586
        
557
 
    def build_tree(self, shape, line_endings='native'):
 
587
    def build_tree(self, shape, line_endings='native', transport=None):
558
588
        """Build a test tree according to a pattern.
559
589
 
560
590
        shape is a sequence of file specifications.  If the final
565
595
                             in binary mode, exact contents are written
566
596
                             in native mode, the line endings match the
567
597
                             default platform endings.
 
598
 
 
599
        :param transport: A transport to write to, for building trees on 
 
600
                          VFS's. If the transport is readonly or None,
 
601
                          "." is opened automatically.
568
602
        """
569
603
        # XXX: It's OK to just create them using forward slashes on windows?
 
604
        if transport is None or transport.is_readonly():
 
605
            transport = bzrlib.transport.get_transport(".")
570
606
        for name in shape:
571
607
            self.assert_(isinstance(name, basestring))
572
608
            if name[-1] == '/':
573
 
                os.mkdir(name[:-1])
 
609
                transport.mkdir(urlescape(name[:-1]))
574
610
            else:
575
611
                if line_endings == 'binary':
576
 
                    f = file(name, 'wb')
 
612
                    end = '\n'
577
613
                elif line_endings == 'native':
578
 
                    f = file(name, 'wt')
 
614
                    end = os.linesep
579
615
                else:
580
616
                    raise BzrError('Invalid line ending request %r' % (line_endings,))
581
 
                print >>f, "contents of", name
582
 
                f.close()
 
617
                content = "contents of %s%s" % (name, end)
 
618
                transport.put(urlescape(name), StringIO(content))
583
619
 
584
620
    def build_tree_contents(self, shape):
585
621
        build_tree_contents(shape)
598
634
        self.assertEqualDiff(content, open(path, 'r').read())
599
635
 
600
636
 
 
637
class TestCaseWithTransport(TestCaseInTempDir):
 
638
    """A test case that provides get_url and get_readonly_url facilities.
 
639
 
 
640
    These back onto two transport servers, one for readonly access and one for
 
641
    read write access.
 
642
 
 
643
    If no explicit class is provided for readonly access, a
 
644
    ReadonlyTransportDecorator is used instead which allows the use of non disk
 
645
    based read write transports.
 
646
 
 
647
    If an explicit class is provided for readonly access, that server and the 
 
648
    readwrite one must both define get_url() as resolving to os.getcwd().
 
649
    """
 
650
 
 
651
    def __init__(self, methodName='testMethod'):
 
652
        super(TestCaseWithTransport, self).__init__(methodName)
 
653
        self.__readonly_server = None
 
654
        self.__server = None
 
655
        self.transport_server = bzrlib.transport.local.LocalRelpathServer
 
656
        self.transport_readonly_server = None
 
657
 
 
658
    def get_readonly_url(self, relpath=None):
 
659
        """Get a URL for the readonly transport.
 
660
 
 
661
        This will either be backed by '.' or a decorator to the transport 
 
662
        used by self.get_url()
 
663
        relpath provides for clients to get a path relative to the base url.
 
664
        These should only be downwards relative, not upwards.
 
665
        """
 
666
        if self.__readonly_server is None:
 
667
            if self.transport_readonly_server is None:
 
668
                # readonly decorator requested
 
669
                # bring up the server
 
670
                self.get_url()
 
671
                self.__readonly_server = ReadonlyServer()
 
672
                self.__readonly_server.setUp(self.__server)
 
673
            else:
 
674
                self.__readonly_server = self.transport_readonly_server()
 
675
                self.__readonly_server.setUp()
 
676
            self.addCleanup(self.__readonly_server.tearDown)
 
677
        base = self.__readonly_server.get_url()
 
678
        if relpath is not None:
 
679
            if not base.endswith('/'):
 
680
                base = base + '/'
 
681
            base = base + relpath
 
682
        return base
 
683
 
 
684
    def get_url(self, relpath=None):
 
685
        """Get a URL for the readwrite transport.
 
686
 
 
687
        This will either be backed by '.' or to an equivalent non-file based
 
688
        facility.
 
689
        relpath provides for clients to get a path relative to the base url.
 
690
        These should only be downwards relative, not upwards.
 
691
        """
 
692
        if self.__server is None:
 
693
            self.__server = self.transport_server()
 
694
            self.__server.setUp()
 
695
            self.addCleanup(self.__server.tearDown)
 
696
        base = self.__server.get_url()
 
697
        if relpath is not None:
 
698
            if not base.endswith('/'):
 
699
                base = base + '/'
 
700
            base = base + relpath
 
701
        return base
 
702
 
 
703
    
 
704
 
 
705
 
601
706
def filter_suite_by_re(suite, pattern):
602
707
    result = TestSuite()
603
708
    filter_re = re.compile(pattern)
705
810
                   'bzrlib.tests.test_workingtree',
706
811
                   'bzrlib.tests.test_xml',
707
812
                   ]
 
813
    test_branch_implementations = [
 
814
        'bzrlib.tests.test_branch_implementations']
 
815
    test_transport_implementations = [
 
816
        'bzrlib.tests.test_transport_implementations']
708
817
 
709
818
    TestCase.BZRPATH = osutils.pathjoin(
710
819
            osutils.realpath(osutils.dirname(bzrlib.__path__[0])), 'bzr')
717
826
    # actually wrong, just "no such module".  We should probably override that
718
827
    # class, but for the moment just load them ourselves. (mbp 20051202)
719
828
    loader = TestLoader()
 
829
    from bzrlib.transport import TransportTestProviderAdapter
 
830
    adapter = TransportTestProviderAdapter()
 
831
    for mod_name in test_transport_implementations:
 
832
        mod = _load_module_by_name(mod_name)
 
833
        for test in iter_suite_tests(loader.loadTestsFromModule(mod)):
 
834
            suite.addTests(adapter.adapt(test))
 
835
    from bzrlib.branch import BranchTestProviderAdapter
 
836
    adapter = BranchTestProviderAdapter(
 
837
        bzrlib.transport.local.LocalRelpathServer,
 
838
        # None here will cause a readonly decorator to be created
 
839
        # by the TestCaseWithTransport.get_readonly_transport method.
 
840
        None,
 
841
        bzrlib.branch.BzrBranchFormat._formats.values())
 
842
    for mod_name in test_branch_implementations:
 
843
        mod = _load_module_by_name(mod_name)
 
844
        for test in iter_suite_tests(loader.loadTestsFromModule(mod)):
 
845
            suite.addTests(adapter.adapt(test))
720
846
    for mod_name in testmod_names:
721
847
        mod = _load_module_by_name(mod_name)
722
848
        suite.addTest(loader.loadTestsFromModule(mod))
727
853
    for m in (MODULES_TO_DOCTEST):
728
854
        suite.addTest(DocTestSuite(m))
729
855
    for name, plugin in bzrlib.plugin.all_plugins().items():
730
 
        if hasattr(plugin, 'test_suite'):
 
856
        if getattr(plugin, 'test_suite', None) is not None:
731
857
            suite.addTest(plugin.test_suite())
732
858
    return suite
733
859