~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/script.py

(vila) Revise legal option names to be less drastic. (Vincent Ladeuil)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2009 Canonical Ltd
 
1
# Copyright (C) 2009, 2010, 2011 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
 
from cStringIO import StringIO
 
27
import textwrap
28
28
 
29
29
from bzrlib import (
30
30
    osutils,
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.
58
62
    """
59
63
 
60
64
    commands = []
73
77
    cmd_line = 1
74
78
    lineno = 0
75
79
    input, output, error = None, None, None
76
 
    for line in text.split('\n'):
 
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:
77
89
        lineno += 1
78
90
        # Keep a copy for error reporting
79
91
        orig = line
80
92
        comment =  line.find('#')
81
93
        if comment >= 0:
82
94
            # Delete comments
 
95
            # NB: this syntax means comments are allowed inside output, which
 
96
            # may be confusing...
83
97
            line = line[0:comment]
84
98
            line = line.rstrip()
85
 
        if line == '':
86
 
            # Ignore empty lines
87
 
            continue
 
99
            if line == '':
 
100
                continue
88
101
        if line.startswith('$'):
89
102
            # Time to output the current command
90
103
            add_command(cmd_cur, input, output, error)
181
194
        self.output_checker = doctest.OutputChecker()
182
195
        self.check_options = doctest.ELLIPSIS
183
196
 
184
 
    def run_script(self, test_case, text):
 
197
    def run_script(self, test_case, text, null_output_matches_anything=False):
185
198
        """Run a shell-like script as a test.
186
199
 
187
200
        :param test_case: A TestCase instance that should provide the fail(),
189
202
            attribute used as a jail root.
190
203
 
191
204
        :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.
192
209
        """
 
210
        self.null_output_matches_anything = null_output_matches_anything
193
211
        for cmd, input, output, error in _script_to_commands(text):
194
212
            self.run_command(test_case, cmd, input, output, error)
195
213
 
198
216
        method = getattr(self, mname, None)
199
217
        if method is None:
200
218
            raise SyntaxError('Command not found "%s"' % (cmd[0],),
201
 
                              None, 1, ' '.join(cmd))
 
219
                              (None, 1, 1, ' '.join(cmd)))
202
220
        if input is None:
203
221
            str_input = ''
204
222
        else:
207
225
        retcode, actual_output, actual_error = method(test_case,
208
226
                                                      str_input, args)
209
227
 
210
 
        self._check_output(output, actual_output, test_case)
211
 
        self._check_output(error, actual_error, test_case)
 
228
        try:
 
229
            self._check_output(output, actual_output, test_case)
 
230
        except AssertionError, 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, e:
 
235
            raise AssertionError(str(e) +
 
236
                " in stderr of running command %s" % cmd)
212
237
        if retcode and not error and actual_error:
213
238
            test_case.fail('In \n\t%s\nUnexpected error: %s'
214
239
                           % (' '.join(cmd), actual_error))
215
240
        return retcode, actual_output, actual_error
216
241
 
217
242
    def _check_output(self, expected, actual, test_case):
218
 
        if expected is None:
219
 
            # Specifying None means: any output is accepted
 
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:
220
255
            return
221
 
        if actual is None:
222
 
            test_case.fail('We expected output: %r, but found None'
223
 
                           % (expected,))
 
256
 
 
257
        expected = expected or ''
224
258
        matching = self.output_checker.check_output(
225
259
            expected, actual, self.check_options)
226
260
        if not matching:
230
264
            # 'expected' parameter. So we just fallback to our good old
231
265
            # assertEqualDiff since we know there *are* differences and the
232
266
            # output should be decently readable.
233
 
            test_case.assertEqualDiff(expected, actual)
 
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)
234
276
 
235
277
    def _pre_process_args(self, args):
236
278
        new_args = []
439
481
    def setUp(self):
440
482
        super(TestCaseWithMemoryTransportAndScript, self).setUp()
441
483
        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')
442
488
 
443
 
    def run_script(self, script):
444
 
        return self.script_runner.run_script(self, script)
 
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)
445
492
 
446
493
    def run_command(self, cmd, input, output, error):
447
494
        return self.script_runner.run_command(self, cmd, input, output, error)
468
515
    def setUp(self):
469
516
        super(TestCaseWithTransportAndScript, self).setUp()
470
517
        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')
471
522
 
472
 
    def run_script(self, script):
473
 
        return self.script_runner.run_script(self, script)
 
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)
474
526
 
475
527
    def run_command(self, cmd, input, output, error):
476
528
        return self.script_runner.run_command(self, cmd, input, output, error)
477
529
 
 
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