/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/selftest/__init__.py

  • Committer: Martin Pool
  • Date: 2005-07-06 04:09:02 UTC
  • Revision ID: mbp@sourcefrog.net-20050706040902-5b98f739e5ee1841
- avoid copying string lists when handling unmatched regions

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2005 by Canonical Ltd
 
2
 
 
3
# This program is free software; you can redistribute it and/or modify
 
4
# it under the terms of the GNU General Public License as published by
 
5
# the Free Software Foundation; either version 2 of the License, or
 
6
# (at your option) any later version.
 
7
 
 
8
# This program is distributed in the hope that it will be useful,
 
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
# GNU General Public License for more details.
 
12
 
 
13
# You should have received a copy of the GNU General Public License
 
14
# along with this program; if not, write to the Free Software
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
16
 
 
17
 
 
18
from unittest import TestResult, TestCase
 
19
 
 
20
try:
 
21
    import shutil
 
22
    from subprocess import call, Popen, PIPE
 
23
except ImportError, e:
 
24
    import sys
 
25
    sys.stderr.write("testbzr: sorry, this test suite requires the subprocess module\n"
 
26
                     "this is shipped with python2.4 and available separately for 2.3\n")
 
27
    raise
 
28
 
 
29
 
 
30
class CommandFailed(Exception):
 
31
    pass
 
32
 
 
33
 
 
34
class TestBase(TestCase):
 
35
    """Base class for bzr test cases.
 
36
 
 
37
    Just defines some useful helper functions; doesn't actually test
 
38
    anything.
 
39
    """
 
40
    
 
41
    # TODO: Special methods to invoke bzr, so that we can run it
 
42
    # through a specified Python intepreter
 
43
 
 
44
    OVERRIDE_PYTHON = None # to run with alternative python 'python'
 
45
    BZRPATH = 'bzr'
 
46
 
 
47
    _log_buf = ""
 
48
 
 
49
 
 
50
    def formcmd(self, cmd):
 
51
        if isinstance(cmd, basestring):
 
52
            cmd = cmd.split()
 
53
 
 
54
        if cmd[0] == 'bzr':
 
55
            cmd[0] = self.BZRPATH
 
56
            if self.OVERRIDE_PYTHON:
 
57
                cmd.insert(0, self.OVERRIDE_PYTHON)
 
58
 
 
59
        self.log('$ %r' % cmd)
 
60
 
 
61
        return cmd
 
62
 
 
63
 
 
64
    def runcmd(self, cmd, retcode=0):
 
65
        """Run one command and check the return code.
 
66
 
 
67
        Returns a tuple of (stdout,stderr) strings.
 
68
 
 
69
        If a single string is based, it is split into words.
 
70
        For commands that are not simple space-separated words, please
 
71
        pass a list instead."""
 
72
        cmd = self.formcmd(cmd)
 
73
 
 
74
        self.log('$ ' + ' '.join(cmd))
 
75
        actual_retcode = call(cmd, stdout=self.TEST_LOG, stderr=self.TEST_LOG)
 
76
 
 
77
        if retcode != actual_retcode:
 
78
            raise CommandFailed("test failed: %r returned %d, expected %d"
 
79
                                % (cmd, actual_retcode, retcode))
 
80
 
 
81
 
 
82
    def backtick(self, cmd, retcode=0):
 
83
        """Run a command and return its output"""
 
84
        cmd = self.formcmd(cmd)
 
85
        child = Popen(cmd, stdout=PIPE, stderr=self.TEST_LOG)
 
86
        outd, errd = child.communicate()
 
87
        self.log(outd)
 
88
        actual_retcode = child.wait()
 
89
 
 
90
        outd = outd.replace('\r', '')
 
91
 
 
92
        if retcode != actual_retcode:
 
93
            raise CommandFailed("test failed: %r returned %d, expected %d"
 
94
                                % (cmd, actual_retcode, retcode))
 
95
 
 
96
        return outd
 
97
 
 
98
 
 
99
 
 
100
    def build_tree(self, shape):
 
101
        """Build a test tree according to a pattern.
 
102
 
 
103
        shape is a sequence of file specifications.  If the final
 
104
        character is '/', a directory is created.
 
105
 
 
106
        This doesn't add anything to a branch.
 
107
        """
 
108
        # XXX: It's OK to just create them using forward slashes on windows?
 
109
        import os
 
110
        for name in shape:
 
111
            assert isinstance(name, basestring)
 
112
            if name[-1] == '/':
 
113
                os.mkdir(name[:-1])
 
114
            else:
 
115
                f = file(name, 'wt')
 
116
                print >>f, "contents of", name
 
117
                f.close()
 
118
 
 
119
 
 
120
    def log(self, msg):
 
121
        """Log a message to a progress file"""
 
122
        self._log_buf = self._log_buf + str(msg) + '\n'
 
123
        print >>self.TEST_LOG, msg
 
124
 
 
125
 
 
126
    def check_inventory_shape(self, inv, shape):
 
127
        """
 
128
        Compare an inventory to a list of expected names.
 
129
 
 
130
        Fail if they are not precisely equal.
 
131
        """
 
132
        extras = []
 
133
        shape = list(shape)             # copy
 
134
        for path, ie in inv.entries():
 
135
            name = path.replace('\\', '/')
 
136
            if ie.kind == 'dir':
 
137
                name = name + '/'
 
138
            if name in shape:
 
139
                shape.remove(name)
 
140
            else:
 
141
                extras.append(name)
 
142
        if shape:
 
143
            self.fail("expected paths not found in inventory: %r" % shape)
 
144
        if extras:
 
145
            self.fail("unexpected paths found in inventory: %r" % extras)
 
146
 
 
147
 
 
148
    def check_file_contents(self, filename, expect):
 
149
        self.log("check contents of file %s" % filename)
 
150
        contents = file(filename, 'r').read()
 
151
        if contents != expect:
 
152
            self.log("expected: %r" % expected)
 
153
            self.log("actually: %r" % contents)
 
154
            self.fail("contents of %s not as expected")
 
155
            
 
156
 
 
157
 
 
158
class InTempDir(TestBase):
 
159
    """Base class for tests run in a temporary branch."""
 
160
    def setUp(self):
 
161
        import os
 
162
        self.test_dir = os.path.join(self.TEST_ROOT, self.__class__.__name__)
 
163
        os.mkdir(self.test_dir)
 
164
        os.chdir(self.test_dir)
 
165
        
 
166
    def tearDown(self):
 
167
        import os
 
168
        os.chdir(self.TEST_ROOT)
 
169
 
 
170
 
 
171
 
 
172
 
 
173
 
 
174
class _MyResult(TestResult):
 
175
    """
 
176
    Custom TestResult.
 
177
 
 
178
    No special behaviour for now.
 
179
    """
 
180
    def __init__(self, out):
 
181
        self.out = out
 
182
        TestResult.__init__(self)
 
183
 
 
184
    def startTest(self, test):
 
185
        # TODO: Maybe show test.shortDescription somewhere?
 
186
        print >>self.out, '%-60.60s' % test.id(),
 
187
        self.out.flush()
 
188
        TestResult.startTest(self, test)
 
189
 
 
190
    def stopTest(self, test):
 
191
        # print
 
192
        TestResult.stopTest(self, test)
 
193
 
 
194
 
 
195
    def addError(self, test, err):
 
196
        print >>self.out, 'ERROR'
 
197
        TestResult.addError(self, test, err)
 
198
        _show_test_failure('error', test, err, self.out)
 
199
 
 
200
    def addFailure(self, test, err):
 
201
        print >>self.out, 'FAILURE'
 
202
        TestResult.addFailure(self, test, err)
 
203
        _show_test_failure('failure', test, err, self.out)
 
204
 
 
205
    def addSuccess(self, test):
 
206
        print >>self.out, 'OK'
 
207
        TestResult.addSuccess(self, test)
 
208
 
 
209
 
 
210
 
 
211
def selftest():
 
212
    from unittest import TestLoader, TestSuite
 
213
    import bzrlib, bzrlib.store, bzrlib.inventory, bzrlib.branch, bzrlib.osutils, bzrlib.commands
 
214
 
 
215
    import bzrlib.selftest.whitebox
 
216
    import bzrlib.selftest.blackbox
 
217
    import bzrlib.selftest.versioning
 
218
    import bzrlib.selftest.testmerge3
 
219
    import bzrlib.merge_core
 
220
    from doctest import DocTestSuite
 
221
    import os
 
222
    import shutil
 
223
    import time
 
224
    import sys
 
225
 
 
226
    TestBase.BZRPATH = os.path.join(os.path.realpath(os.path.dirname(bzrlib.__path__[0])), 'bzr')
 
227
    print '%-30s %s' % ('bzr binary', TestBase.BZRPATH)
 
228
 
 
229
    _setup_test_log()
 
230
    _setup_test_dir()
 
231
    print
 
232
 
 
233
    suite = TestSuite()
 
234
    tl = TestLoader()
 
235
 
 
236
    # should also test bzrlib.merge_core, but they seem to be out of date with
 
237
    # the code.
 
238
 
 
239
    for m in bzrlib.selftest.whitebox, \
 
240
            bzrlib.selftest.versioning, \
 
241
            bzrlib.selftest.testmerge3:
 
242
        suite.addTest(tl.loadTestsFromModule(m))
 
243
 
 
244
    for m in bzrlib.store, bzrlib.inventory, bzrlib.branch, bzrlib.osutils, \
 
245
            bzrlib.commands, \
 
246
            bzrlib.merge3:
 
247
        suite.addTest(DocTestSuite(m))
 
248
 
 
249
    suite.addTest(bzrlib.selftest.blackbox.suite())
 
250
 
 
251
    # save stdout & stderr so there's no leakage from code-under-test
 
252
    real_stdout = sys.stdout
 
253
    real_stderr = sys.stderr
 
254
    sys.stdout = sys.stderr = TestBase.TEST_LOG
 
255
    try:
 
256
        result = _MyResult(real_stdout)
 
257
        suite.run(result)
 
258
    finally:
 
259
        sys.stdout = real_stdout
 
260
        sys.stderr = real_stderr
 
261
 
 
262
    _show_results(result)
 
263
 
 
264
    return result.wasSuccessful()
 
265
 
 
266
 
 
267
 
 
268
 
 
269
def _setup_test_log():
 
270
    import time
 
271
    import os
 
272
    
 
273
    log_filename = os.path.abspath('testbzr.log')
 
274
    TestBase.TEST_LOG = open(log_filename, 'wt', buffering=1) # line buffered
 
275
 
 
276
    print >>TestBase.TEST_LOG, "bzr tests run at " + time.ctime()
 
277
    print '%-30s %s' % ('test log', log_filename)
 
278
 
 
279
 
 
280
def _setup_test_dir():
 
281
    import os
 
282
    import shutil
 
283
    
 
284
    TestBase.ORIG_DIR = os.getcwdu()
 
285
    TestBase.TEST_ROOT = os.path.abspath("testbzr.tmp")
 
286
 
 
287
    print '%-30s %s' % ('running tests in', TestBase.TEST_ROOT)
 
288
 
 
289
    if os.path.exists(TestBase.TEST_ROOT):
 
290
        shutil.rmtree(TestBase.TEST_ROOT)
 
291
    os.mkdir(TestBase.TEST_ROOT)
 
292
    os.chdir(TestBase.TEST_ROOT)
 
293
 
 
294
    # make a fake bzr directory there to prevent any tests propagating
 
295
    # up onto the source directory's real branch
 
296
    os.mkdir(os.path.join(TestBase.TEST_ROOT, '.bzr'))
 
297
 
 
298
    
 
299
 
 
300
def _show_results(result):
 
301
     print
 
302
     print '%4d tests run' % result.testsRun
 
303
     print '%4d errors' % len(result.errors)
 
304
     print '%4d failures' % len(result.failures)
 
305
 
 
306
 
 
307
 
 
308
def _show_test_failure(kind, case, exc_info, out):
 
309
    from traceback import print_exception
 
310
    
 
311
    print >>out, '-' * 60
 
312
    print >>out, case
 
313
    
 
314
    desc = case.shortDescription()
 
315
    if desc:
 
316
        print >>out, '   (%s)' % desc
 
317
         
 
318
    print_exception(exc_info[0], exc_info[1], exc_info[2], None, out)
 
319
        
 
320
    if isinstance(case, TestBase):
 
321
        print >>out
 
322
        print >>out, 'log from this test:'
 
323
        print >>out, case._log_buf
 
324
         
 
325
    print >>out, '-' * 60
 
326
    
 
327