/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
5557.1.15 by John Arbash Meinel
Merge bzr.dev 5597 to resolve NEWS, aka bzr-2.3.txt
1
# Copyright (C) 2009, 2010, 2011 Canonical Ltd
4665.5.1 by Vincent Ladeuil
Start some shell-like capability to write tests.
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
4665.5.20 by Vincent Ladeuil
Fixed as per Martin's review.
16
4665.5.9 by Vincent Ladeuil
Start adding doc.
17
"""Shell-like test scripts.
18
4665.5.21 by Vincent Ladeuil
Fix some typos mentioned by Martin.
19
See developers/testing.html for more explanations.
4665.5.9 by Vincent Ladeuil
Start adding doc.
20
"""
4665.5.1 by Vincent Ladeuil
Start some shell-like capability to write tests.
21
4665.5.12 by Vincent Ladeuil
Support '...' in expected strings.
22
import doctest
4665.5.17 by Vincent Ladeuil
Implement 'rm' command.
23
import errno
4665.5.19 by Vincent Ladeuil
Implement globbing and enhance cat to accept multiple files.
24
import glob
7065.3.8 by Jelmer Vernooij
Fix tests.
25
import logging
4665.5.5 by Vincent Ladeuil
Implement 'cd' and 'mkdir'.
26
import os
4665.5.1 by Vincent Ladeuil
Start some shell-like capability to write tests.
27
import shlex
7065.3.1 by Jelmer Vernooij
Some refactoring.
28
import sys
5283.1.2 by Martin Pool
ScriptRunner strips consistent leading indentation from scripts
29
import textwrap
4665.5.1 by Vincent Ladeuil
Start some shell-like capability to write tests.
30
6624 by Jelmer Vernooij
Merge Python3 porting work ('py3 pokes')
31
from .. import (
4665.5.5 by Vincent Ladeuil
Implement 'cd' and 'mkdir'.
32
    osutils,
33
    tests,
7065.3.8 by Jelmer Vernooij
Fix tests.
34
    trace,
4665.5.5 by Vincent Ladeuil
Implement 'cd' and 'mkdir'.
35
    )
7065.3.1 by Jelmer Vernooij
Some refactoring.
36
from ..tests import ui_testing
4665.5.4 by Vincent Ladeuil
Implement a 'cat' command.
37
4665.5.1 by Vincent Ladeuil
Start some shell-like capability to write tests.
38
4665.5.2 by Vincent Ladeuil
Handle simple, double and back quotes.
39
def split(s):
40
    """Split a command line respecting quotes."""
41
    scanner = shlex.shlex(s)
42
    scanner.quotes = '\'"`'
43
    scanner.whitespace_split = True
44
    for t in list(scanner):
4665.5.19 by Vincent Ladeuil
Implement globbing and enhance cat to accept multiple files.
45
        yield t
4665.5.2 by Vincent Ladeuil
Handle simple, double and back quotes.
46
47
48
def _script_to_commands(text, file_name=None):
4665.5.1 by Vincent Ladeuil
Start some shell-like capability to write tests.
49
    """Turn a script into a list of commands with their associated IOs.
50
4665.5.21 by Vincent Ladeuil
Fix some typos mentioned by Martin.
51
    Each command appears on a line by itself starting with '$ '. It can be
52
    associated with an input that will feed it and an expected output.
53
4665.5.1 by Vincent Ladeuil
Start some shell-like capability to write tests.
54
    Comments starts with '#' until the end of line.
55
    Empty lines are ignored.
4665.5.21 by Vincent Ladeuil
Fix some typos mentioned by Martin.
56
4665.5.1 by Vincent Ladeuil
Start some shell-like capability to write tests.
57
    Input and output are full lines terminated by a '\n'.
4665.5.21 by Vincent Ladeuil
Fix some typos mentioned by Martin.
58
4665.5.1 by Vincent Ladeuil
Start some shell-like capability to write tests.
59
    Input lines start with '<'.
4665.5.21 by Vincent Ladeuil
Fix some typos mentioned by Martin.
60
    Output lines start with nothing.
4665.5.3 by Vincent Ladeuil
Separate error from normal output.
61
    Error lines start with '2>'.
5417.1.4 by Martin Pool
doc
62
63
    :return: A sequence of ([args], input, output, errors), where the args are
64
        split in to words, and the input, output, and errors are just strings,
65
        typically containing newlines.
4665.5.1 by Vincent Ladeuil
Start some shell-like capability to write tests.
66
    """
4665.5.7 by Vincent Ladeuil
Simplify output/errors handling.
67
4665.5.1 by Vincent Ladeuil
Start some shell-like capability to write tests.
68
    commands = []
4665.5.7 by Vincent Ladeuil
Simplify output/errors handling.
69
70
    def add_command(cmd, input, output, error):
71
        if cmd is not None:
72
            if input is not None:
73
                input = ''.join(input)
74
            if output is not None:
75
                output = ''.join(output)
76
            if error is not None:
77
                error = ''.join(error)
78
            commands.append((cmd, input, output, error))
79
4665.5.1 by Vincent Ladeuil
Start some shell-like capability to write tests.
80
    cmd_cur = None
81
    cmd_line = 1
82
    lineno = 0
4665.5.3 by Vincent Ladeuil
Separate error from normal output.
83
    input, output, error = None, None, None
5283.1.2 by Martin Pool
ScriptRunner strips consistent leading indentation from scripts
84
    text = textwrap.dedent(text)
5417.1.5 by Martin Pool
Better handling of blank lines in test scripts
85
    lines = text.split('\n')
86
    # to make use of triple-quoted strings easier, we ignore a blank line
87
    # right at the start and right at the end; the rest are meaningful
88
    if lines and lines[0] == '':
89
        del lines[0]
90
    if lines and lines[-1] == '':
91
        del lines[-1]
92
    for line in lines:
4665.5.1 by Vincent Ladeuil
Start some shell-like capability to write tests.
93
        lineno += 1
94
        # Keep a copy for error reporting
95
        orig = line
7143.15.2 by Jelmer Vernooij
Run autopep8.
96
        comment = line.find('#')
4665.5.1 by Vincent Ladeuil
Start some shell-like capability to write tests.
97
        if comment >= 0:
98
            # Delete comments
5417.1.5 by Martin Pool
Better handling of blank lines in test scripts
99
            # NB: this syntax means comments are allowed inside output, which
100
            # may be confusing...
4665.5.1 by Vincent Ladeuil
Start some shell-like capability to write tests.
101
            line = line[0:comment]
102
            line = line.rstrip()
5417.1.5 by Martin Pool
Better handling of blank lines in test scripts
103
            if line == '':
104
                continue
4665.5.20 by Vincent Ladeuil
Fixed as per Martin's review.
105
        if line.startswith('$'):
106
            # Time to output the current command
107
            add_command(cmd_cur, input, output, error)
108
            # And start a new one
109
            cmd_cur = list(split(line[1:]))
110
            cmd_line = lineno
111
            input, output, error = None, None, None
112
        elif line.startswith('<'):
4665.5.1 by Vincent Ladeuil
Start some shell-like capability to write tests.
113
            if input is None:
114
                if cmd_cur is None:
115
                    raise SyntaxError('No command for that input',
116
                                      (file_name, lineno, 1, orig))
117
                input = []
118
            input.append(line[1:] + '\n')
4665.5.3 by Vincent Ladeuil
Separate error from normal output.
119
        elif line.startswith('2>'):
120
            if error is None:
121
                if cmd_cur is None:
122
                    raise SyntaxError('No command for that error',
123
                                      (file_name, lineno, 1, orig))
124
                error = []
125
            error.append(line[2:] + '\n')
4665.5.1 by Vincent Ladeuil
Start some shell-like capability to write tests.
126
        else:
4889.1.1 by Martin Pool
Clearer syntax error message from ScriptRunner
127
            # can happen if the first line is not recognized as a command, eg
128
            # if the prompt has leading whitespace
4665.5.20 by Vincent Ladeuil
Fixed as per Martin's review.
129
            if output is None:
130
                if cmd_cur is None:
4889.1.1 by Martin Pool
Clearer syntax error message from ScriptRunner
131
                    raise SyntaxError('No command for line %r' % (line,),
4665.5.20 by Vincent Ladeuil
Fixed as per Martin's review.
132
                                      (file_name, lineno, 1, orig))
133
                output = []
134
            output.append(line + '\n')
4665.5.1 by Vincent Ladeuil
Start some shell-like capability to write tests.
135
    # Add the last seen command
4665.5.7 by Vincent Ladeuil
Simplify output/errors handling.
136
    add_command(cmd_cur, input, output, error)
4665.5.1 by Vincent Ladeuil
Start some shell-like capability to write tests.
137
    return commands
4665.5.4 by Vincent Ladeuil
Implement a 'cat' command.
138
139
4665.5.8 by Vincent Ladeuil
Implement 'echo' command.
140
def _scan_redirection_options(args):
141
    """Recognize and process input and output redirections.
142
143
    :param args: The command line arguments
144
7195.5.1 by Martin
Fix remaining whitespace lint in codebase
145
    :return: A tuple containing:
4665.5.8 by Vincent Ladeuil
Implement 'echo' command.
146
        - The file name redirected from or None
147
        - The file name redirected to or None
148
        - The mode to open the output file or None
149
        - The reamining arguments
150
    """
4665.5.18 by Vincent Ladeuil
Better redirection handling.
151
    def redirected_file_name(direction, name, args):
152
        if name == '':
153
            try:
154
                name = args.pop(0)
155
            except IndexError:
156
                # We leave the error handling to higher levels, an empty name
157
                # can't be legal.
158
                name = ''
159
        return name
160
4665.5.8 by Vincent Ladeuil
Implement 'echo' command.
161
    remaining = []
162
    in_name = None
163
    out_name, out_mode = None, None
4665.5.18 by Vincent Ladeuil
Better redirection handling.
164
    while args:
165
        arg = args.pop(0)
4665.5.8 by Vincent Ladeuil
Implement 'echo' command.
166
        if arg.startswith('<'):
4665.5.18 by Vincent Ladeuil
Better redirection handling.
167
            in_name = redirected_file_name('<', arg[1:], args)
4665.5.8 by Vincent Ladeuil
Implement 'echo' command.
168
        elif arg.startswith('>>'):
4665.5.18 by Vincent Ladeuil
Better redirection handling.
169
            out_name = redirected_file_name('>>', arg[2:], args)
7045.1.1 by Jelmer Vernooij
Fix another 300 tests.
170
            out_mode = 'a+'
4665.5.18 by Vincent Ladeuil
Better redirection handling.
171
        elif arg.startswith('>',):
172
            out_name = redirected_file_name('>', arg[1:], args)
7045.1.1 by Jelmer Vernooij
Fix another 300 tests.
173
            out_mode = 'w+'
4665.5.8 by Vincent Ladeuil
Implement 'echo' command.
174
        else:
175
            remaining.append(arg)
176
    return in_name, out_name, out_mode, remaining
177
178
4665.5.10 by Vincent Ladeuil
Start separating the script runner from the test case.
179
class ScriptRunner(object):
4665.5.24 by Vincent Ladeuil
Scripts can be used without imposing a test base class.
180
    """Run a shell-like script from a test.
7143.15.2 by Jelmer Vernooij
Run autopep8.
181
4665.5.24 by Vincent Ladeuil
Scripts can be used without imposing a test base class.
182
    Can be used as:
183
6622.1.34 by Jelmer Vernooij
Rename brzlib => breezy.
184
    from breezy.tests import script
4665.5.24 by Vincent Ladeuil
Scripts can be used without imposing a test base class.
185
186
    ...
187
188
        def test_bug_nnnnn(self):
189
            sr = script.ScriptRunner()
190
            sr.run_script(self, '''
6622.1.29 by Jelmer Vernooij
Fix some more tests.
191
            $ brz init
192
            $ brz do-this
4665.5.24 by Vincent Ladeuil
Scripts can be used without imposing a test base class.
193
            # Boom, error
194
            ''')
195
    """
4665.5.4 by Vincent Ladeuil
Implement a 'cat' command.
196
4665.5.23 by Vincent Ladeuil
Revert the jail_root parameter addition.
197
    def __init__(self):
4665.5.12 by Vincent Ladeuil
Support '...' in expected strings.
198
        self.output_checker = doctest.OutputChecker()
199
        self.check_options = doctest.ELLIPSIS
4665.5.4 by Vincent Ladeuil
Implement a 'cat' command.
200
5531.1.2 by Vincent Ladeuil
s/blank_output/null_output/
201
    def run_script(self, test_case, text, null_output_matches_anything=False):
4665.5.24 by Vincent Ladeuil
Scripts can be used without imposing a test base class.
202
        """Run a shell-like script as a test.
203
204
        :param test_case: A TestCase instance that should provide the fail(),
205
            assertEqualDiff and _run_bzr_core() methods as well as a 'test_dir'
206
            attribute used as a jail root.
207
208
        :param text: A shell-like script (see _script_to_commands for syntax).
5509.1.2 by Neil Martinsen-Burrell
address vilas review comments
209
5531.1.2 by Vincent Ladeuil
s/blank_output/null_output/
210
        :param null_output_matches_anything: For commands with no specified
5509.1.3 by Neil Martinsen-Burrell
change option name and mention the effect on standard error
211
            output, ignore any output that does happen, including output on
212
            standard error.
4665.5.24 by Vincent Ladeuil
Scripts can be used without imposing a test base class.
213
        """
5531.1.2 by Vincent Ladeuil
s/blank_output/null_output/
214
        self.null_output_matches_anything = null_output_matches_anything
4665.5.4 by Vincent Ladeuil
Implement a 'cat' command.
215
        for cmd, input, output, error in _script_to_commands(text):
4665.5.24 by Vincent Ladeuil
Scripts can be used without imposing a test base class.
216
            self.run_command(test_case, cmd, input, output, error)
4665.5.22 by Vincent Ladeuil
Try to relax the test_case/script runner coupling.
217
4665.5.24 by Vincent Ladeuil
Scripts can be used without imposing a test base class.
218
    def run_command(self, test_case, cmd, input, output, error):
4665.5.22 by Vincent Ladeuil
Try to relax the test_case/script runner coupling.
219
        mname = 'do_' + cmd[0]
220
        method = getattr(self, mname, None)
221
        if method is None:
222
            raise SyntaxError('Command not found "%s"' % (cmd[0],),
5508.2.1 by Martin
In shell-like tests raise a valid SyntaxError if a command is not found
223
                              (None, 1, 1, ' '.join(cmd)))
4665.5.22 by Vincent Ladeuil
Try to relax the test_case/script runner coupling.
224
        if input is None:
225
            str_input = ''
226
        else:
227
            str_input = ''.join(input)
228
        args = list(self._pre_process_args(cmd[1:]))
229
        retcode, actual_output, actual_error = method(test_case,
230
                                                      str_input, args)
231
5422.3.1 by Martin Pool
Blank scriptrunner output only matches blank
232
        try:
233
            self._check_output(output, actual_output, test_case)
6619.3.2 by Jelmer Vernooij
Apply 2to3 except fix.
234
        except AssertionError as e:
5422.3.1 by Martin Pool
Blank scriptrunner output only matches blank
235
            raise AssertionError(str(e) + " in stdout of command %s" % cmd)
236
        try:
237
            self._check_output(error, actual_error, test_case)
6619.3.2 by Jelmer Vernooij
Apply 2to3 except fix.
238
        except AssertionError as e:
7143.15.2 by Jelmer Vernooij
Run autopep8.
239
            raise AssertionError(str(e)
240
                                 + " in stderr of running command %s" % cmd)
4665.5.22 by Vincent Ladeuil
Try to relax the test_case/script runner coupling.
241
        if retcode and not error and actual_error:
242
            test_case.fail('In \n\t%s\nUnexpected error: %s'
243
                           % (' '.join(cmd), actual_error))
244
        return retcode, actual_output, actual_error
245
246
    def _check_output(self, expected, actual, test_case):
5422.3.1 by Martin Pool
Blank scriptrunner output only matches blank
247
        if not actual:
248
            if expected is None:
249
                return
250
            elif expected == '...\n':
251
                return
252
            else:
253
                test_case.fail('expected output: %r, but found nothing'
7143.15.2 by Jelmer Vernooij
Run autopep8.
254
                               % (expected,))
5509.1.1 by Neil Martinsen-Burrell
add ignore_blanks to run_script to recover old behavior
255
5531.1.2 by Vincent Ladeuil
s/blank_output/null_output/
256
        null_output_matches_anything = getattr(
257
            self, 'null_output_matches_anything', False)
258
        if null_output_matches_anything and expected is None:
5509.1.1 by Neil Martinsen-Burrell
add ignore_blanks to run_script to recover old behavior
259
            return
5531.1.2 by Vincent Ladeuil
s/blank_output/null_output/
260
5422.3.1 by Martin Pool
Blank scriptrunner output only matches blank
261
        expected = expected or ''
4665.5.12 by Vincent Ladeuil
Support '...' in expected strings.
262
        matching = self.output_checker.check_output(
263
            expected, actual, self.check_options)
264
        if not matching:
265
            # Note that we can't use output_checker.output_difference() here
4665.5.15 by Vincent Ladeuil
Catch the retcode for all commands.
266
            # because... the API is broken ('expected' must be a doctest
267
            # specific object of which a 'want' attribute will be our
268
            # 'expected' parameter. So we just fallback to our good old
269
            # assertEqualDiff since we know there *are* differences and the
270
            # output should be decently readable.
5417.1.1 by Martin Pool
ScriptRunner can now cope with commands that prompt for input.
271
            #
272
            # As a special case, we allow output that's missing a final
273
            # newline to match an expected string that does have one, so that
274
            # we can match a prompt printed on one line, then input given on
275
            # the next line.
276
            if expected == actual + '\n':
277
                pass
278
            else:
5422.3.5 by Martin Pool
Go back to using assertEqualDiff when a script fails
279
                test_case.assertEqualDiff(expected, actual)
4665.5.5 by Vincent Ladeuil
Implement 'cd' and 'mkdir'.
280
4665.5.19 by Vincent Ladeuil
Implement globbing and enhance cat to accept multiple files.
281
    def _pre_process_args(self, args):
282
        new_args = []
283
        for arg in args:
284
            # Strip the simple and double quotes since we don't care about
285
            # them.  We leave the backquotes in place though since they have a
286
            # different semantic.
7143.15.2 by Jelmer Vernooij
Run autopep8.
287
            if arg[0] in ('"', "'") and arg[0] == arg[-1]:
4665.5.19 by Vincent Ladeuil
Implement globbing and enhance cat to accept multiple files.
288
                yield arg[1:-1]
289
            else:
290
                if glob.has_magic(arg):
291
                    matches = glob.glob(arg)
292
                    if matches:
293
                        # We care more about order stability than performance
294
                        # here
295
                        matches.sort()
296
                        for m in matches:
297
                            yield m
298
                else:
299
                    yield arg
300
4665.5.8 by Vincent Ladeuil
Implement 'echo' command.
301
    def _read_input(self, input, in_name):
4665.5.4 by Vincent Ladeuil
Implement a 'cat' command.
302
        if in_name is not None:
7045.1.1 by Jelmer Vernooij
Fix another 300 tests.
303
            infile = open(in_name, 'r')
4665.5.4 by Vincent Ladeuil
Implement a 'cat' command.
304
            try:
4665.5.8 by Vincent Ladeuil
Implement 'echo' command.
305
                # Command redirection takes precedence over provided input
4665.5.4 by Vincent Ladeuil
Implement a 'cat' command.
306
                input = infile.read()
307
            finally:
308
                infile.close()
4665.5.8 by Vincent Ladeuil
Implement 'echo' command.
309
        return input
310
311
    def _write_output(self, output, out_name, out_mode):
4665.5.4 by Vincent Ladeuil
Implement a 'cat' command.
312
        if out_name is not None:
4665.5.8 by Vincent Ladeuil
Implement 'echo' command.
313
            outfile = open(out_name, out_mode)
4665.5.4 by Vincent Ladeuil
Implement a 'cat' command.
314
            try:
315
                outfile.write(output)
316
            finally:
317
                outfile.close()
4665.5.5 by Vincent Ladeuil
Implement 'cd' and 'mkdir'.
318
            output = None
4665.5.8 by Vincent Ladeuil
Implement 'echo' command.
319
        return output
320
6622.1.29 by Jelmer Vernooij
Fix some more tests.
321
    def do_brz(self, test_case, input, args):
7065.3.1 by Jelmer Vernooij
Some refactoring.
322
        encoding = osutils.get_user_encoding()
7479.2.1 by Jelmer Vernooij
Drop python2 support.
323
        stdout = ui_testing.StringIOWithEncoding()
324
        stderr = ui_testing.StringIOWithEncoding()
325
        stdout.encoding = stderr.encoding = encoding
326
        handler = logging.StreamHandler(stderr)
7065.3.8 by Jelmer Vernooij
Fix tests.
327
        handler.setLevel(logging.INFO)
7065.3.1 by Jelmer Vernooij
Some refactoring.
328
7065.3.8 by Jelmer Vernooij
Fix tests.
329
        logger = logging.getLogger('')
330
        logger.addHandler(handler)
331
        try:
332
            retcode = test_case._run_bzr_core(
333
                args, encoding=encoding, stdin=input, stdout=stdout,
334
                stderr=stderr, working_dir=None)
335
        finally:
336
            logger.removeHandler(handler)
7065.3.1 by Jelmer Vernooij
Some refactoring.
337
338
        return retcode, stdout.getvalue(), stderr.getvalue()
4665.5.8 by Vincent Ladeuil
Implement 'echo' command.
339
4665.5.22 by Vincent Ladeuil
Try to relax the test_case/script runner coupling.
340
    def do_cat(self, test_case, input, args):
4665.5.8 by Vincent Ladeuil
Implement 'echo' command.
341
        (in_name, out_name, out_mode, args) = _scan_redirection_options(args)
4665.5.19 by Vincent Ladeuil
Implement globbing and enhance cat to accept multiple files.
342
        if args and in_name is not None:
343
            raise SyntaxError('Specify a file OR use redirection')
344
345
        inputs = []
346
        if input:
347
            inputs.append(input)
348
        input_names = args
349
        if in_name:
350
            args.append(in_name)
351
        for in_name in input_names:
352
            try:
353
                inputs.append(self._read_input(None, in_name))
6619.3.2 by Jelmer Vernooij
Apply 2to3 except fix.
354
            except IOError as e:
4789.18.1 by John Arbash Meinel
Rework test_script a little bit.
355
                # Some filenames are illegal on Windows and generate EINVAL
356
                # rather than just saying the filename doesn't exist
357
                if e.errno in (errno.ENOENT, errno.EINVAL):
4665.5.19 by Vincent Ladeuil
Implement globbing and enhance cat to accept multiple files.
358
                    return (1, None,
359
                            '%s: No such file or directory\n' % (in_name,))
4789.18.1 by John Arbash Meinel
Rework test_script a little bit.
360
                raise
4665.5.8 by Vincent Ladeuil
Implement 'echo' command.
361
        # Basically cat copy input to output
4665.5.19 by Vincent Ladeuil
Implement globbing and enhance cat to accept multiple files.
362
        output = ''.join(inputs)
4665.5.8 by Vincent Ladeuil
Implement 'echo' command.
363
        # Handle output redirections
4665.5.18 by Vincent Ladeuil
Better redirection handling.
364
        try:
365
            output = self._write_output(output, out_name, out_mode)
6619.3.2 by Jelmer Vernooij
Apply 2to3 except fix.
366
        except IOError as e:
4789.18.1 by John Arbash Meinel
Rework test_script a little bit.
367
            # If out_name cannot be created, we may get 'ENOENT', however if
368
            # out_name is something like '', we can get EINVAL
369
            if e.errno in (errno.ENOENT, errno.EINVAL):
4665.5.18 by Vincent Ladeuil
Better redirection handling.
370
                return 1, None, '%s: No such file or directory\n' % (out_name,)
4789.18.1 by John Arbash Meinel
Rework test_script a little bit.
371
            raise
4665.5.15 by Vincent Ladeuil
Catch the retcode for all commands.
372
        return 0, output, None
4665.5.8 by Vincent Ladeuil
Implement 'echo' command.
373
4665.5.22 by Vincent Ladeuil
Try to relax the test_case/script runner coupling.
374
    def do_echo(self, test_case, input, args):
4665.5.8 by Vincent Ladeuil
Implement 'echo' command.
375
        (in_name, out_name, out_mode, args) = _scan_redirection_options(args)
4789.18.1 by John Arbash Meinel
Rework test_script a little bit.
376
        if input or in_name:
377
            raise SyntaxError('echo doesn\'t read from stdin')
4665.5.8 by Vincent Ladeuil
Implement 'echo' command.
378
        if args:
4665.5.20 by Vincent Ladeuil
Fixed as per Martin's review.
379
            input = ' '.join(args)
4665.5.8 by Vincent Ladeuil
Implement 'echo' command.
380
        # Always append a \n'
381
        input += '\n'
382
        # Process output
383
        output = input
384
        # Handle output redirections
4665.5.18 by Vincent Ladeuil
Better redirection handling.
385
        try:
386
            output = self._write_output(output, out_name, out_mode)
6619.3.2 by Jelmer Vernooij
Apply 2to3 except fix.
387
        except IOError as e:
4789.18.1 by John Arbash Meinel
Rework test_script a little bit.
388
            if e.errno in (errno.ENOENT, errno.EINVAL):
4665.5.18 by Vincent Ladeuil
Better redirection handling.
389
                return 1, None, '%s: No such file or directory\n' % (out_name,)
4789.18.1 by John Arbash Meinel
Rework test_script a little bit.
390
            raise
4665.5.15 by Vincent Ladeuil
Catch the retcode for all commands.
391
        return 0, output, None
4665.5.5 by Vincent Ladeuil
Implement 'cd' and 'mkdir'.
392
4665.5.24 by Vincent Ladeuil
Scripts can be used without imposing a test base class.
393
    def _get_jail_root(self, test_case):
394
        return test_case.test_dir
395
4665.5.23 by Vincent Ladeuil
Revert the jail_root parameter addition.
396
    def _ensure_in_jail(self, test_case, path):
4665.5.24 by Vincent Ladeuil
Scripts can be used without imposing a test base class.
397
        jail_root = self._get_jail_root(test_case)
4665.5.23 by Vincent Ladeuil
Revert the jail_root parameter addition.
398
        if not osutils.is_inside(jail_root, osutils.normalizepath(path)):
399
            raise ValueError('%s is not inside %s' % (path, jail_root))
4665.5.5 by Vincent Ladeuil
Implement 'cd' and 'mkdir'.
400
4665.5.22 by Vincent Ladeuil
Try to relax the test_case/script runner coupling.
401
    def do_cd(self, test_case, input, args):
4665.5.5 by Vincent Ladeuil
Implement 'cd' and 'mkdir'.
402
        if len(args) > 1:
403
            raise SyntaxError('Usage: cd [dir]')
404
        if len(args) == 1:
405
            d = args[0]
4665.5.23 by Vincent Ladeuil
Revert the jail_root parameter addition.
406
            self._ensure_in_jail(test_case, d)
4665.5.5 by Vincent Ladeuil
Implement 'cd' and 'mkdir'.
407
        else:
4665.5.23 by Vincent Ladeuil
Revert the jail_root parameter addition.
408
            # The test "home" directory is the root of its jail
4665.5.24 by Vincent Ladeuil
Scripts can be used without imposing a test base class.
409
            d = self._get_jail_root(test_case)
4665.5.5 by Vincent Ladeuil
Implement 'cd' and 'mkdir'.
410
        os.chdir(d)
4665.5.15 by Vincent Ladeuil
Catch the retcode for all commands.
411
        return 0, None, None
4665.5.5 by Vincent Ladeuil
Implement 'cd' and 'mkdir'.
412
4665.5.22 by Vincent Ladeuil
Try to relax the test_case/script runner coupling.
413
    def do_mkdir(self, test_case, input, args):
4665.5.5 by Vincent Ladeuil
Implement 'cd' and 'mkdir'.
414
        if not args or len(args) != 1:
415
            raise SyntaxError('Usage: mkdir dir')
416
        d = args[0]
4665.5.23 by Vincent Ladeuil
Revert the jail_root parameter addition.
417
        self._ensure_in_jail(test_case, d)
4665.5.5 by Vincent Ladeuil
Implement 'cd' and 'mkdir'.
418
        os.mkdir(d)
4665.5.15 by Vincent Ladeuil
Catch the retcode for all commands.
419
        return 0, None, None
4665.5.6 by Vincent Ladeuil
Implement 'bzr' command.
420
4665.5.22 by Vincent Ladeuil
Try to relax the test_case/script runner coupling.
421
    def do_rm(self, test_case, input, args):
4665.5.17 by Vincent Ladeuil
Implement 'rm' command.
422
        err = None
423
424
        def error(msg, path):
7143.15.2 by Jelmer Vernooij
Run autopep8.
425
            return "rm: cannot remove '%s': %s\n" % (path, msg)
4665.5.17 by Vincent Ladeuil
Implement 'rm' command.
426
427
        force, recursive = False, False
428
        opts = None
429
        if args and args[0][0] == '-':
430
            opts = args.pop(0)[1:]
431
            if 'f' in opts:
432
                force = True
433
                opts = opts.replace('f', '', 1)
434
            if 'r' in opts:
435
                recursive = True
436
                opts = opts.replace('r', '', 1)
437
        if not args or opts:
438
            raise SyntaxError('Usage: rm [-fr] path+')
439
        for p in args:
4665.5.23 by Vincent Ladeuil
Revert the jail_root parameter addition.
440
            self._ensure_in_jail(test_case, p)
4665.5.17 by Vincent Ladeuil
Implement 'rm' command.
441
            # FIXME: Should we put that in osutils ?
442
            try:
443
                os.remove(p)
6619.3.2 by Jelmer Vernooij
Apply 2to3 except fix.
444
            except OSError as e:
4707.1.1 by Vincent Ladeuil
Fix OSX and FreeBSD failures.
445
                # Various OSes raises different exceptions (linux: EISDIR,
446
                #   win32: EACCES, OSX: EPERM) when invoked on a directory
447
                if e.errno in (errno.EISDIR, errno.EPERM, errno.EACCES):
4665.5.17 by Vincent Ladeuil
Implement 'rm' command.
448
                    if recursive:
449
                        osutils.rmtree(p)
450
                    else:
451
                        err = error('Is a directory', p)
452
                        break
453
                elif e.errno == errno.ENOENT:
454
                    if not force:
7143.15.2 by Jelmer Vernooij
Run autopep8.
455
                        err = error('No such file or directory', p)
4665.5.17 by Vincent Ladeuil
Implement 'rm' command.
456
                        break
457
                else:
458
                    raise
459
        if err:
460
            retcode = 1
461
        else:
462
            retcode = 0
463
        return retcode, None, err
464
4953.2.1 by Neil Martinsen-Burrell
add an mv command to shell-like tests
465
    def do_mv(self, test_case, input, args):
466
        err = None
7143.15.2 by Jelmer Vernooij
Run autopep8.
467
4953.2.3 by Vincent Ladeuil
Use os.rename() and fix some typos.
468
        def error(msg, src, dst):
469
            return "mv: cannot move %s to %s: %s\n" % (src, dst, msg)
4953.2.1 by Neil Martinsen-Burrell
add an mv command to shell-like tests
470
471
        if not args or len(args) != 2:
472
            raise SyntaxError("Usage: mv path1 path2")
4953.2.3 by Vincent Ladeuil
Use os.rename() and fix some typos.
473
        src, dst = args
4953.2.1 by Neil Martinsen-Burrell
add an mv command to shell-like tests
474
        try:
4953.2.3 by Vincent Ladeuil
Use os.rename() and fix some typos.
475
            real_dst = dst
476
            if os.path.isdir(dst):
477
                real_dst = os.path.join(dst, os.path.basename(src))
478
            os.rename(src, real_dst)
6619.3.2 by Jelmer Vernooij
Apply 2to3 except fix.
479
        except OSError as e:
4953.2.1 by Neil Martinsen-Burrell
add an mv command to shell-like tests
480
            if e.errno == errno.ENOENT:
4953.2.3 by Vincent Ladeuil
Use os.rename() and fix some typos.
481
                err = error('No such file or directory', src, dst)
4953.2.1 by Neil Martinsen-Burrell
add an mv command to shell-like tests
482
            else:
483
                raise
484
        if err:
485
            retcode = 1
486
        else:
487
            retcode = 0
488
        return retcode, None, err
489
490
4665.5.11 by Vincent Ladeuil
Create a new test case based on TestCaseWithMemoryTransport.
491
class TestCaseWithMemoryTransportAndScript(tests.TestCaseWithMemoryTransport):
4665.5.22 by Vincent Ladeuil
Try to relax the test_case/script runner coupling.
492
    """Helper class to experiment shell-like test and memory fs.
493
494
    This not intended to be used outside of experiments in implementing memoy
495
    based file systems and evolving bzr so that test can use only memory based
496
    resources.
497
    """
4665.5.11 by Vincent Ladeuil
Create a new test case based on TestCaseWithMemoryTransport.
498
499
    def setUp(self):
500
        super(TestCaseWithMemoryTransportAndScript, self).setUp()
4665.5.22 by Vincent Ladeuil
Try to relax the test_case/script runner coupling.
501
        self.script_runner = ScriptRunner()
6155.5.5 by Vincent Ladeuil
Allows bzr shelve to be used in test scripts and under emacs shells
502
        # FIXME: See shelf_ui.Shelver._char_based. This allow using shelve in
503
        # scripts while providing a line-based input (better solution in
504
        # progress). -- vila 2011-09-28
505
        self.overrideEnv('INSIDE_EMACS', '1')
4665.5.11 by Vincent Ladeuil
Create a new test case based on TestCaseWithMemoryTransport.
506
5531.1.2 by Vincent Ladeuil
s/blank_output/null_output/
507
    def run_script(self, script, null_output_matches_anything=False):
7143.15.2 by Jelmer Vernooij
Run autopep8.
508
        return self.script_runner.run_script(self, script,
509
                                             null_output_matches_anything=null_output_matches_anything)
4665.5.11 by Vincent Ladeuil
Create a new test case based on TestCaseWithMemoryTransport.
510
511
    def run_command(self, cmd, input, output, error):
4665.5.24 by Vincent Ladeuil
Scripts can be used without imposing a test base class.
512
        return self.script_runner.run_command(self, cmd, input, output, error)
4665.5.11 by Vincent Ladeuil
Create a new test case based on TestCaseWithMemoryTransport.
513
514
4665.5.10 by Vincent Ladeuil
Start separating the script runner from the test case.
515
class TestCaseWithTransportAndScript(tests.TestCaseWithTransport):
4665.5.22 by Vincent Ladeuil
Try to relax the test_case/script runner coupling.
516
    """Helper class to quickly define shell-like tests.
517
518
    Can be used as:
519
6622.1.34 by Jelmer Vernooij
Rename brzlib => breezy.
520
    from breezy.tests import script
4665.5.22 by Vincent Ladeuil
Try to relax the test_case/script runner coupling.
521
522
523
    class TestBug(script.TestCaseWithTransportAndScript):
524
525
        def test_bug_nnnnn(self):
526
            self.run_script('''
6622.1.29 by Jelmer Vernooij
Fix some more tests.
527
            $ brz init
528
            $ brz do-this
4665.5.22 by Vincent Ladeuil
Try to relax the test_case/script runner coupling.
529
            # Boom, error
530
            ''')
531
    """
4665.5.10 by Vincent Ladeuil
Start separating the script runner from the test case.
532
533
    def setUp(self):
534
        super(TestCaseWithTransportAndScript, self).setUp()
4665.5.23 by Vincent Ladeuil
Revert the jail_root parameter addition.
535
        self.script_runner = ScriptRunner()
6155.5.5 by Vincent Ladeuil
Allows bzr shelve to be used in test scripts and under emacs shells
536
        # FIXME: See shelf_ui.Shelver._char_based. This allow using shelve in
537
        # scripts while providing a line-based input (better solution in
538
        # progress). -- vila 2011-09-28
539
        self.overrideEnv('INSIDE_EMACS', '1')
4665.5.23 by Vincent Ladeuil
Revert the jail_root parameter addition.
540
5531.1.2 by Vincent Ladeuil
s/blank_output/null_output/
541
    def run_script(self, script, null_output_matches_anything=False):
5509.1.2 by Neil Martinsen-Burrell
address vilas review comments
542
        return self.script_runner.run_script(self, script,
7143.15.2 by Jelmer Vernooij
Run autopep8.
543
                                             null_output_matches_anything=null_output_matches_anything)
4665.5.10 by Vincent Ladeuil
Start separating the script runner from the test case.
544
545
    def run_command(self, cmd, input, output, error):
4665.5.24 by Vincent Ladeuil
Scripts can be used without imposing a test base class.
546
        return self.script_runner.run_command(self, cmd, input, output, error)
4665.5.22 by Vincent Ladeuil
Try to relax the test_case/script runner coupling.
547
5283.1.1 by Martin Pool
Add helper function script.run_script and suggest using it
548
5531.1.2 by Vincent Ladeuil
s/blank_output/null_output/
549
def run_script(test_case, script_string, null_output_matches_anything=False):
5283.1.1 by Martin Pool
Add helper function script.run_script and suggest using it
550
    """Run the given script within a testcase"""
5509.1.2 by Neil Martinsen-Burrell
address vilas review comments
551
    return ScriptRunner().run_script(test_case, script_string,
7143.15.2 by Jelmer Vernooij
Run autopep8.
552
                                     null_output_matches_anything=null_output_matches_anything)