/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/tests/script.py

  • Committer: Robert Collins
  • Date: 2010-05-06 11:08:10 UTC
  • mto: This revision was merged to the branch mainline in revision 5223.
  • Revision ID: robertc@robertcollins.net-20100506110810-h3j07fh5gmw54s25
Cleaner matcher matching revised unlocking protocol.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2009, 2010, 2011 Canonical Ltd
 
1
# Copyright (C) 2009, 2010 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
24
24
import glob
25
25
import os
26
26
import shlex
27
 
import textwrap
 
27
from cStringIO import StringIO
28
28
 
29
 
from .. import (
 
29
from bzrlib import (
30
30
    osutils,
31
31
    tests,
32
32
    )
55
55
    Input lines start with '<'.
56
56
    Output lines start with nothing.
57
57
    Error lines start with '2>'.
58
 
 
59
 
    :return: A sequence of ([args], input, output, errors), where the args are
60
 
        split in to words, and the input, output, and errors are just strings,
61
 
        typically containing newlines.
62
58
    """
63
59
 
64
60
    commands = []
77
73
    cmd_line = 1
78
74
    lineno = 0
79
75
    input, output, error = None, None, None
80
 
    text = textwrap.dedent(text)
81
 
    lines = text.split('\n')
82
 
    # to make use of triple-quoted strings easier, we ignore a blank line
83
 
    # right at the start and right at the end; the rest are meaningful
84
 
    if lines and lines[0] == '':
85
 
        del lines[0]
86
 
    if lines and lines[-1] == '':
87
 
        del lines[-1]
88
 
    for line in lines:
 
76
    for line in text.split('\n'):
89
77
        lineno += 1
90
78
        # Keep a copy for error reporting
91
79
        orig = line
92
80
        comment =  line.find('#')
93
81
        if comment >= 0:
94
82
            # Delete comments
95
 
            # NB: this syntax means comments are allowed inside output, which
96
 
            # may be confusing...
97
83
            line = line[0:comment]
98
84
            line = line.rstrip()
99
 
            if line == '':
100
 
                continue
 
85
        if line == '':
 
86
            # Ignore empty lines
 
87
            continue
101
88
        if line.startswith('$'):
102
89
            # Time to output the current command
103
90
            add_command(cmd_cur, input, output, error)
177
164
    
178
165
    Can be used as:
179
166
 
180
 
    from breezy.tests import script
 
167
    from bzrlib.tests import script
181
168
 
182
169
    ...
183
170
 
184
171
        def test_bug_nnnnn(self):
185
172
            sr = script.ScriptRunner()
186
173
            sr.run_script(self, '''
187
 
            $ brz init
188
 
            $ brz do-this
 
174
            $ bzr init
 
175
            $ bzr do-this
189
176
            # Boom, error
190
177
            ''')
191
178
    """
194
181
        self.output_checker = doctest.OutputChecker()
195
182
        self.check_options = doctest.ELLIPSIS
196
183
 
197
 
    def run_script(self, test_case, text, null_output_matches_anything=False):
 
184
    def run_script(self, test_case, text):
198
185
        """Run a shell-like script as a test.
199
186
 
200
187
        :param test_case: A TestCase instance that should provide the fail(),
202
189
            attribute used as a jail root.
203
190
 
204
191
        :param text: A shell-like script (see _script_to_commands for syntax).
205
 
 
206
 
        :param null_output_matches_anything: For commands with no specified
207
 
            output, ignore any output that does happen, including output on
208
 
            standard error.
209
192
        """
210
 
        self.null_output_matches_anything = null_output_matches_anything
211
193
        for cmd, input, output, error in _script_to_commands(text):
212
194
            self.run_command(test_case, cmd, input, output, error)
213
195
 
216
198
        method = getattr(self, mname, None)
217
199
        if method is None:
218
200
            raise SyntaxError('Command not found "%s"' % (cmd[0],),
219
 
                              (None, 1, 1, ' '.join(cmd)))
 
201
                              None, 1, ' '.join(cmd))
220
202
        if input is None:
221
203
            str_input = ''
222
204
        else:
225
207
        retcode, actual_output, actual_error = method(test_case,
226
208
                                                      str_input, args)
227
209
 
228
 
        try:
229
 
            self._check_output(output, actual_output, test_case)
230
 
        except AssertionError as e:
231
 
            raise AssertionError(str(e) + " in stdout of command %s" % cmd)
232
 
        try:
233
 
            self._check_output(error, actual_error, test_case)
234
 
        except AssertionError as e:
235
 
            raise AssertionError(str(e) +
236
 
                " in stderr of running command %s" % cmd)
 
210
        self._check_output(output, actual_output, test_case)
 
211
        self._check_output(error, actual_error, test_case)
237
212
        if retcode and not error and actual_error:
238
213
            test_case.fail('In \n\t%s\nUnexpected error: %s'
239
214
                           % (' '.join(cmd), actual_error))
240
215
        return retcode, actual_output, actual_error
241
216
 
242
217
    def _check_output(self, expected, actual, test_case):
243
 
        if not actual:
244
 
            if expected is None:
245
 
                return
246
 
            elif expected == '...\n':
247
 
                return
248
 
            else:
249
 
                test_case.fail('expected output: %r, but found nothing'
250
 
                            % (expected,))
251
 
 
252
 
        null_output_matches_anything = getattr(
253
 
            self, 'null_output_matches_anything', False)
254
 
        if null_output_matches_anything and expected is None:
 
218
        if expected is None:
 
219
            # Specifying None means: any output is accepted
255
220
            return
256
 
 
257
 
        expected = expected or ''
 
221
        if actual is None:
 
222
            test_case.fail('We expected output: %r, but found None'
 
223
                           % (expected,))
258
224
        matching = self.output_checker.check_output(
259
225
            expected, actual, self.check_options)
260
226
        if not matching:
264
230
            # 'expected' parameter. So we just fallback to our good old
265
231
            # assertEqualDiff since we know there *are* differences and the
266
232
            # output should be decently readable.
267
 
            #
268
 
            # As a special case, we allow output that's missing a final
269
 
            # newline to match an expected string that does have one, so that
270
 
            # we can match a prompt printed on one line, then input given on
271
 
            # the next line.
272
 
            if expected == actual + '\n':
273
 
                pass
274
 
            else:
275
 
                test_case.assertEqualDiff(expected, actual)
 
233
            test_case.assertEqualDiff(expected, actual)
276
234
 
277
235
    def _pre_process_args(self, args):
278
236
        new_args = []
314
272
            output = None
315
273
        return output
316
274
 
317
 
    def do_brz(self, test_case, input, args):
 
275
    def do_bzr(self, test_case, input, args):
318
276
        retcode, out, err = test_case._run_bzr_core(
319
277
            args, retcode=None, encoding=None, stdin=input, working_dir=None)
320
278
        return retcode, out, err
333
291
        for in_name in input_names:
334
292
            try:
335
293
                inputs.append(self._read_input(None, in_name))
336
 
            except IOError as e:
 
294
            except IOError, e:
337
295
                # Some filenames are illegal on Windows and generate EINVAL
338
296
                # rather than just saying the filename doesn't exist
339
297
                if e.errno in (errno.ENOENT, errno.EINVAL):
345
303
        # Handle output redirections
346
304
        try:
347
305
            output = self._write_output(output, out_name, out_mode)
348
 
        except IOError as e:
 
306
        except IOError, e:
349
307
            # If out_name cannot be created, we may get 'ENOENT', however if
350
308
            # out_name is something like '', we can get EINVAL
351
309
            if e.errno in (errno.ENOENT, errno.EINVAL):
366
324
        # Handle output redirections
367
325
        try:
368
326
            output = self._write_output(output, out_name, out_mode)
369
 
        except IOError as e:
 
327
        except IOError, e:
370
328
            if e.errno in (errno.ENOENT, errno.EINVAL):
371
329
                return 1, None, '%s: No such file or directory\n' % (out_name,)
372
330
            raise
423
381
            # FIXME: Should we put that in osutils ?
424
382
            try:
425
383
                os.remove(p)
426
 
            except OSError as e:
 
384
            except OSError, e:
427
385
                # Various OSes raises different exceptions (linux: EISDIR,
428
386
                #   win32: EACCES, OSX: EPERM) when invoked on a directory
429
387
                if e.errno in (errno.EISDIR, errno.EPERM, errno.EACCES):
457
415
            if os.path.isdir(dst):
458
416
                real_dst = os.path.join(dst, os.path.basename(src))
459
417
            os.rename(src, real_dst)
460
 
        except OSError as e:
 
418
        except OSError, e:
461
419
            if e.errno == errno.ENOENT:
462
420
                err = error('No such file or directory', src, dst)
463
421
            else:
481
439
    def setUp(self):
482
440
        super(TestCaseWithMemoryTransportAndScript, self).setUp()
483
441
        self.script_runner = ScriptRunner()
484
 
        # FIXME: See shelf_ui.Shelver._char_based. This allow using shelve in
485
 
        # scripts while providing a line-based input (better solution in
486
 
        # progress). -- vila 2011-09-28
487
 
        self.overrideEnv('INSIDE_EMACS', '1')
488
442
 
489
 
    def run_script(self, script, null_output_matches_anything=False):
490
 
        return self.script_runner.run_script(self, script, 
491
 
                   null_output_matches_anything=null_output_matches_anything)
 
443
    def run_script(self, script):
 
444
        return self.script_runner.run_script(self, script)
492
445
 
493
446
    def run_command(self, cmd, input, output, error):
494
447
        return self.script_runner.run_command(self, cmd, input, output, error)
499
452
 
500
453
    Can be used as:
501
454
 
502
 
    from breezy.tests import script
 
455
    from bzrlib.tests import script
503
456
 
504
457
 
505
458
    class TestBug(script.TestCaseWithTransportAndScript):
506
459
 
507
460
        def test_bug_nnnnn(self):
508
461
            self.run_script('''
509
 
            $ brz init
510
 
            $ brz do-this
 
462
            $ bzr init
 
463
            $ bzr do-this
511
464
            # Boom, error
512
465
            ''')
513
466
    """
515
468
    def setUp(self):
516
469
        super(TestCaseWithTransportAndScript, self).setUp()
517
470
        self.script_runner = ScriptRunner()
518
 
        # FIXME: See shelf_ui.Shelver._char_based. This allow using shelve in
519
 
        # scripts while providing a line-based input (better solution in
520
 
        # progress). -- vila 2011-09-28
521
 
        self.overrideEnv('INSIDE_EMACS', '1')
522
471
 
523
 
    def run_script(self, script, null_output_matches_anything=False):
524
 
        return self.script_runner.run_script(self, script,
525
 
                   null_output_matches_anything=null_output_matches_anything)
 
472
    def run_script(self, script):
 
473
        return self.script_runner.run_script(self, script)
526
474
 
527
475
    def run_command(self, cmd, input, output, error):
528
476
        return self.script_runner.run_command(self, cmd, input, output, error)
529
477
 
530
 
 
531
 
def run_script(test_case, script_string, null_output_matches_anything=False):
532
 
    """Run the given script within a testcase"""
533
 
    return ScriptRunner().run_script(test_case, script_string,
534
 
               null_output_matches_anything=null_output_matches_anything)
535