~bzr-pqm/bzr/bzr.dev

4665.5.1 by Vincent Ladeuil
Start some shell-like capability to write tests.
1
# Copyright (C) 2009 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., 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
4665.5.5 by Vincent Ladeuil
Implement 'cd' and 'mkdir'.
25
import os
4665.5.1 by Vincent Ladeuil
Start some shell-like capability to write tests.
26
import shlex
4665.5.12 by Vincent Ladeuil
Support '...' in expected strings.
27
from cStringIO import StringIO
4665.5.1 by Vincent Ladeuil
Start some shell-like capability to write tests.
28
4665.5.5 by Vincent Ladeuil
Implement 'cd' and 'mkdir'.
29
from bzrlib import (
30
    osutils,
31
    tests,
32
    )
4665.5.4 by Vincent Ladeuil
Implement a 'cat' command.
33
4665.5.1 by Vincent Ladeuil
Start some shell-like capability to write tests.
34
4665.5.2 by Vincent Ladeuil
Handle simple, double and back quotes.
35
def split(s):
36
    """Split a command line respecting quotes."""
37
    scanner = shlex.shlex(s)
38
    scanner.quotes = '\'"`'
39
    scanner.whitespace_split = True
40
    for t in list(scanner):
4665.5.19 by Vincent Ladeuil
Implement globbing and enhance cat to accept multiple files.
41
        yield t
4665.5.2 by Vincent Ladeuil
Handle simple, double and back quotes.
42
43
44
def _script_to_commands(text, file_name=None):
4665.5.1 by Vincent Ladeuil
Start some shell-like capability to write tests.
45
    """Turn a script into a list of commands with their associated IOs.
46
4665.5.21 by Vincent Ladeuil
Fix some typos mentioned by Martin.
47
    Each command appears on a line by itself starting with '$ '. It can be
48
    associated with an input that will feed it and an expected output.
49
4665.5.1 by Vincent Ladeuil
Start some shell-like capability to write tests.
50
    Comments starts with '#' until the end of line.
51
    Empty lines are ignored.
4665.5.21 by Vincent Ladeuil
Fix some typos mentioned by Martin.
52
4665.5.1 by Vincent Ladeuil
Start some shell-like capability to write tests.
53
    Input and output are full lines terminated by a '\n'.
4665.5.21 by Vincent Ladeuil
Fix some typos mentioned by Martin.
54
4665.5.1 by Vincent Ladeuil
Start some shell-like capability to write tests.
55
    Input lines start with '<'.
4665.5.21 by Vincent Ladeuil
Fix some typos mentioned by Martin.
56
    Output lines start with nothing.
4665.5.3 by Vincent Ladeuil
Separate error from normal output.
57
    Error lines start with '2>'.
4665.5.1 by Vincent Ladeuil
Start some shell-like capability to write tests.
58
    """
4665.5.7 by Vincent Ladeuil
Simplify output/errors handling.
59
4665.5.1 by Vincent Ladeuil
Start some shell-like capability to write tests.
60
    commands = []
4665.5.7 by Vincent Ladeuil
Simplify output/errors handling.
61
62
    def add_command(cmd, input, output, error):
63
        if cmd is not None:
64
            if input is not None:
65
                input = ''.join(input)
66
            if output is not None:
67
                output = ''.join(output)
68
            if error is not None:
69
                error = ''.join(error)
70
            commands.append((cmd, input, output, error))
71
4665.5.1 by Vincent Ladeuil
Start some shell-like capability to write tests.
72
    cmd_cur = None
73
    cmd_line = 1
74
    lineno = 0
4665.5.3 by Vincent Ladeuil
Separate error from normal output.
75
    input, output, error = None, None, None
4665.5.2 by Vincent Ladeuil
Handle simple, double and back quotes.
76
    for line in text.split('\n'):
4665.5.1 by Vincent Ladeuil
Start some shell-like capability to write tests.
77
        lineno += 1
78
        # Keep a copy for error reporting
79
        orig = line
80
        comment =  line.find('#')
81
        if comment >= 0:
82
            # Delete comments
83
            line = line[0:comment]
84
            line = line.rstrip()
85
        if line == '':
86
            # Ignore empty lines
87
            continue
4665.5.20 by Vincent Ladeuil
Fixed as per Martin's review.
88
        if line.startswith('$'):
89
            # Time to output the current command
90
            add_command(cmd_cur, input, output, error)
91
            # And start a new one
92
            cmd_cur = list(split(line[1:]))
93
            cmd_line = lineno
94
            input, output, error = None, None, None
95
        elif line.startswith('<'):
4665.5.1 by Vincent Ladeuil
Start some shell-like capability to write tests.
96
            if input is None:
97
                if cmd_cur is None:
98
                    raise SyntaxError('No command for that input',
99
                                      (file_name, lineno, 1, orig))
100
                input = []
101
            input.append(line[1:] + '\n')
4665.5.3 by Vincent Ladeuil
Separate error from normal output.
102
        elif line.startswith('2>'):
103
            if error is None:
104
                if cmd_cur is None:
105
                    raise SyntaxError('No command for that error',
106
                                      (file_name, lineno, 1, orig))
107
                error = []
108
            error.append(line[2:] + '\n')
4665.5.1 by Vincent Ladeuil
Start some shell-like capability to write tests.
109
        else:
4665.5.20 by Vincent Ladeuil
Fixed as per Martin's review.
110
            if output is None:
111
                if cmd_cur is None:
112
                    raise SyntaxError('No command for that output',
113
                                      (file_name, lineno, 1, orig))
114
                output = []
115
            output.append(line + '\n')
4665.5.1 by Vincent Ladeuil
Start some shell-like capability to write tests.
116
    # Add the last seen command
4665.5.7 by Vincent Ladeuil
Simplify output/errors handling.
117
    add_command(cmd_cur, input, output, error)
4665.5.1 by Vincent Ladeuil
Start some shell-like capability to write tests.
118
    return commands
4665.5.4 by Vincent Ladeuil
Implement a 'cat' command.
119
120
4665.5.8 by Vincent Ladeuil
Implement 'echo' command.
121
def _scan_redirection_options(args):
122
    """Recognize and process input and output redirections.
123
124
    :param args: The command line arguments
125
126
    :return: A tuple containing: 
127
        - The file name redirected from or None
128
        - The file name redirected to or None
129
        - The mode to open the output file or None
130
        - The reamining arguments
131
    """
4665.5.18 by Vincent Ladeuil
Better redirection handling.
132
    def redirected_file_name(direction, name, args):
133
        if name == '':
134
            try:
135
                name = args.pop(0)
136
            except IndexError:
137
                # We leave the error handling to higher levels, an empty name
138
                # can't be legal.
139
                name = ''
140
        return name
141
4665.5.8 by Vincent Ladeuil
Implement 'echo' command.
142
    remaining = []
143
    in_name = None
144
    out_name, out_mode = None, None
4665.5.18 by Vincent Ladeuil
Better redirection handling.
145
    while args:
146
        arg = args.pop(0)
4665.5.8 by Vincent Ladeuil
Implement 'echo' command.
147
        if arg.startswith('<'):
4665.5.18 by Vincent Ladeuil
Better redirection handling.
148
            in_name = redirected_file_name('<', arg[1:], args)
4665.5.8 by Vincent Ladeuil
Implement 'echo' command.
149
        elif arg.startswith('>>'):
4665.5.18 by Vincent Ladeuil
Better redirection handling.
150
            out_name = redirected_file_name('>>', arg[2:], args)
4665.5.8 by Vincent Ladeuil
Implement 'echo' command.
151
            out_mode = 'ab+'
4665.5.18 by Vincent Ladeuil
Better redirection handling.
152
        elif arg.startswith('>',):
153
            out_name = redirected_file_name('>', arg[1:], args)
4665.5.8 by Vincent Ladeuil
Implement 'echo' command.
154
            out_mode = 'wb+'
155
        else:
156
            remaining.append(arg)
157
    return in_name, out_name, out_mode, remaining
158
159
4665.5.10 by Vincent Ladeuil
Start separating the script runner from the test case.
160
class ScriptRunner(object):
4665.5.24 by Vincent Ladeuil
Scripts can be used without imposing a test base class.
161
    """Run a shell-like script from a test.
162
    
163
    Can be used as:
164
165
    from bzrlib.tests import script
166
167
    ...
168
169
        def test_bug_nnnnn(self):
170
            sr = script.ScriptRunner()
171
            sr.run_script(self, '''
172
            $ bzr init
173
            $ bzr do-this
174
            # Boom, error
175
            ''')
176
    """
4665.5.4 by Vincent Ladeuil
Implement a 'cat' command.
177
4665.5.23 by Vincent Ladeuil
Revert the jail_root parameter addition.
178
    def __init__(self):
4665.5.12 by Vincent Ladeuil
Support '...' in expected strings.
179
        self.output_checker = doctest.OutputChecker()
180
        self.check_options = doctest.ELLIPSIS
4665.5.4 by Vincent Ladeuil
Implement a 'cat' command.
181
4665.5.24 by Vincent Ladeuil
Scripts can be used without imposing a test base class.
182
    def run_script(self, test_case, text):
183
        """Run a shell-like script as a test.
184
185
        :param test_case: A TestCase instance that should provide the fail(),
186
            assertEqualDiff and _run_bzr_core() methods as well as a 'test_dir'
187
            attribute used as a jail root.
188
189
        :param text: A shell-like script (see _script_to_commands for syntax).
190
        """
4665.5.4 by Vincent Ladeuil
Implement a 'cat' command.
191
        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.
192
            self.run_command(test_case, cmd, input, output, error)
4665.5.22 by Vincent Ladeuil
Try to relax the test_case/script runner coupling.
193
4665.5.24 by Vincent Ladeuil
Scripts can be used without imposing a test base class.
194
    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.
195
        mname = 'do_' + cmd[0]
196
        method = getattr(self, mname, None)
197
        if method is None:
198
            raise SyntaxError('Command not found "%s"' % (cmd[0],),
199
                              None, 1, ' '.join(cmd))
200
        if input is None:
201
            str_input = ''
202
        else:
203
            str_input = ''.join(input)
204
        args = list(self._pre_process_args(cmd[1:]))
205
        retcode, actual_output, actual_error = method(test_case,
206
                                                      str_input, args)
207
208
        self._check_output(output, actual_output, test_case)
209
        self._check_output(error, actual_error, test_case)
210
        if retcode and not error and actual_error:
211
            test_case.fail('In \n\t%s\nUnexpected error: %s'
212
                           % (' '.join(cmd), actual_error))
213
        return retcode, actual_output, actual_error
214
215
    def _check_output(self, expected, actual, test_case):
4665.5.5 by Vincent Ladeuil
Implement 'cd' and 'mkdir'.
216
        if expected is None:
4665.5.6 by Vincent Ladeuil
Implement 'bzr' command.
217
            # Specifying None means: any output is accepted
218
            return
4665.5.12 by Vincent Ladeuil
Support '...' in expected strings.
219
        if actual is None:
4789.18.1 by John Arbash Meinel
Rework test_script a little bit.
220
            test_case.fail('We expected output: %r, but found None'
221
                           % (expected,))
4665.5.12 by Vincent Ladeuil
Support '...' in expected strings.
222
        matching = self.output_checker.check_output(
223
            expected, actual, self.check_options)
224
        if not matching:
225
            # Note that we can't use output_checker.output_difference() here
4665.5.15 by Vincent Ladeuil
Catch the retcode for all commands.
226
            # because... the API is broken ('expected' must be a doctest
227
            # specific object of which a 'want' attribute will be our
228
            # 'expected' parameter. So we just fallback to our good old
229
            # assertEqualDiff since we know there *are* differences and the
230
            # output should be decently readable.
4665.5.22 by Vincent Ladeuil
Try to relax the test_case/script runner coupling.
231
            test_case.assertEqualDiff(expected, actual)
4665.5.5 by Vincent Ladeuil
Implement 'cd' and 'mkdir'.
232
4665.5.19 by Vincent Ladeuil
Implement globbing and enhance cat to accept multiple files.
233
    def _pre_process_args(self, args):
234
        new_args = []
235
        for arg in args:
236
            # Strip the simple and double quotes since we don't care about
237
            # them.  We leave the backquotes in place though since they have a
238
            # different semantic.
239
            if arg[0] in  ('"', "'") and arg[0] == arg[-1]:
240
                yield arg[1:-1]
241
            else:
242
                if glob.has_magic(arg):
243
                    matches = glob.glob(arg)
244
                    if matches:
245
                        # We care more about order stability than performance
246
                        # here
247
                        matches.sort()
248
                        for m in matches:
249
                            yield m
250
                else:
251
                    yield arg
252
4665.5.8 by Vincent Ladeuil
Implement 'echo' command.
253
    def _read_input(self, input, in_name):
4665.5.4 by Vincent Ladeuil
Implement a 'cat' command.
254
        if in_name is not None:
255
            infile = open(in_name, 'rb')
256
            try:
4665.5.8 by Vincent Ladeuil
Implement 'echo' command.
257
                # Command redirection takes precedence over provided input
4665.5.4 by Vincent Ladeuil
Implement a 'cat' command.
258
                input = infile.read()
259
            finally:
260
                infile.close()
4665.5.8 by Vincent Ladeuil
Implement 'echo' command.
261
        return input
262
263
    def _write_output(self, output, out_name, out_mode):
4665.5.4 by Vincent Ladeuil
Implement a 'cat' command.
264
        if out_name is not None:
4665.5.8 by Vincent Ladeuil
Implement 'echo' command.
265
            outfile = open(out_name, out_mode)
4665.5.4 by Vincent Ladeuil
Implement a 'cat' command.
266
            try:
267
                outfile.write(output)
268
            finally:
269
                outfile.close()
4665.5.5 by Vincent Ladeuil
Implement 'cd' and 'mkdir'.
270
            output = None
4665.5.8 by Vincent Ladeuil
Implement 'echo' command.
271
        return output
272
4665.5.22 by Vincent Ladeuil
Try to relax the test_case/script runner coupling.
273
    def do_bzr(self, test_case, input, args):
274
        retcode, out, err = test_case._run_bzr_core(
4665.5.10 by Vincent Ladeuil
Start separating the script runner from the test case.
275
            args, retcode=None, encoding=None, stdin=input, working_dir=None)
4665.5.15 by Vincent Ladeuil
Catch the retcode for all commands.
276
        return retcode, out, err
4665.5.8 by Vincent Ladeuil
Implement 'echo' command.
277
4665.5.22 by Vincent Ladeuil
Try to relax the test_case/script runner coupling.
278
    def do_cat(self, test_case, input, args):
4665.5.8 by Vincent Ladeuil
Implement 'echo' command.
279
        (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.
280
        if args and in_name is not None:
281
            raise SyntaxError('Specify a file OR use redirection')
282
283
        inputs = []
284
        if input:
285
            inputs.append(input)
286
        input_names = args
287
        if in_name:
288
            args.append(in_name)
289
        for in_name in input_names:
290
            try:
291
                inputs.append(self._read_input(None, in_name))
292
            except IOError, e:
4789.18.1 by John Arbash Meinel
Rework test_script a little bit.
293
                # Some filenames are illegal on Windows and generate EINVAL
294
                # rather than just saying the filename doesn't exist
295
                if e.errno in (errno.ENOENT, errno.EINVAL):
4665.5.19 by Vincent Ladeuil
Implement globbing and enhance cat to accept multiple files.
296
                    return (1, None,
297
                            '%s: No such file or directory\n' % (in_name,))
4789.18.1 by John Arbash Meinel
Rework test_script a little bit.
298
                raise
4665.5.8 by Vincent Ladeuil
Implement 'echo' command.
299
        # Basically cat copy input to output
4665.5.19 by Vincent Ladeuil
Implement globbing and enhance cat to accept multiple files.
300
        output = ''.join(inputs)
4665.5.8 by Vincent Ladeuil
Implement 'echo' command.
301
        # Handle output redirections
4665.5.18 by Vincent Ladeuil
Better redirection handling.
302
        try:
303
            output = self._write_output(output, out_name, out_mode)
304
        except IOError, e:
4789.18.1 by John Arbash Meinel
Rework test_script a little bit.
305
            # If out_name cannot be created, we may get 'ENOENT', however if
306
            # out_name is something like '', we can get EINVAL
307
            if e.errno in (errno.ENOENT, errno.EINVAL):
4665.5.18 by Vincent Ladeuil
Better redirection handling.
308
                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.
309
            raise
4665.5.15 by Vincent Ladeuil
Catch the retcode for all commands.
310
        return 0, output, None
4665.5.8 by Vincent Ladeuil
Implement 'echo' command.
311
4665.5.22 by Vincent Ladeuil
Try to relax the test_case/script runner coupling.
312
    def do_echo(self, test_case, input, args):
4665.5.8 by Vincent Ladeuil
Implement 'echo' command.
313
        (in_name, out_name, out_mode, args) = _scan_redirection_options(args)
4789.18.1 by John Arbash Meinel
Rework test_script a little bit.
314
        if input or in_name:
315
            raise SyntaxError('echo doesn\'t read from stdin')
4665.5.8 by Vincent Ladeuil
Implement 'echo' command.
316
        if args:
4665.5.20 by Vincent Ladeuil
Fixed as per Martin's review.
317
            input = ' '.join(args)
4665.5.8 by Vincent Ladeuil
Implement 'echo' command.
318
        # Always append a \n'
319
        input += '\n'
320
        # Process output
321
        output = input
322
        # Handle output redirections
4665.5.18 by Vincent Ladeuil
Better redirection handling.
323
        try:
324
            output = self._write_output(output, out_name, out_mode)
325
        except IOError, e:
4789.18.1 by John Arbash Meinel
Rework test_script a little bit.
326
            if e.errno in (errno.ENOENT, errno.EINVAL):
4665.5.18 by Vincent Ladeuil
Better redirection handling.
327
                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.
328
            raise
4665.5.15 by Vincent Ladeuil
Catch the retcode for all commands.
329
        return 0, output, None
4665.5.5 by Vincent Ladeuil
Implement 'cd' and 'mkdir'.
330
4665.5.24 by Vincent Ladeuil
Scripts can be used without imposing a test base class.
331
    def _get_jail_root(self, test_case):
332
        return test_case.test_dir
333
4665.5.23 by Vincent Ladeuil
Revert the jail_root parameter addition.
334
    def _ensure_in_jail(self, test_case, path):
4665.5.24 by Vincent Ladeuil
Scripts can be used without imposing a test base class.
335
        jail_root = self._get_jail_root(test_case)
4665.5.23 by Vincent Ladeuil
Revert the jail_root parameter addition.
336
        if not osutils.is_inside(jail_root, osutils.normalizepath(path)):
337
            raise ValueError('%s is not inside %s' % (path, jail_root))
4665.5.5 by Vincent Ladeuil
Implement 'cd' and 'mkdir'.
338
4665.5.22 by Vincent Ladeuil
Try to relax the test_case/script runner coupling.
339
    def do_cd(self, test_case, input, args):
4665.5.5 by Vincent Ladeuil
Implement 'cd' and 'mkdir'.
340
        if len(args) > 1:
341
            raise SyntaxError('Usage: cd [dir]')
342
        if len(args) == 1:
343
            d = args[0]
4665.5.23 by Vincent Ladeuil
Revert the jail_root parameter addition.
344
            self._ensure_in_jail(test_case, d)
4665.5.5 by Vincent Ladeuil
Implement 'cd' and 'mkdir'.
345
        else:
4665.5.23 by Vincent Ladeuil
Revert the jail_root parameter addition.
346
            # 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.
347
            d = self._get_jail_root(test_case)
4665.5.5 by Vincent Ladeuil
Implement 'cd' and 'mkdir'.
348
        os.chdir(d)
4665.5.15 by Vincent Ladeuil
Catch the retcode for all commands.
349
        return 0, None, None
4665.5.5 by Vincent Ladeuil
Implement 'cd' and 'mkdir'.
350
4665.5.22 by Vincent Ladeuil
Try to relax the test_case/script runner coupling.
351
    def do_mkdir(self, test_case, input, args):
4665.5.5 by Vincent Ladeuil
Implement 'cd' and 'mkdir'.
352
        if not args or len(args) != 1:
353
            raise SyntaxError('Usage: mkdir dir')
354
        d = args[0]
4665.5.23 by Vincent Ladeuil
Revert the jail_root parameter addition.
355
        self._ensure_in_jail(test_case, d)
4665.5.5 by Vincent Ladeuil
Implement 'cd' and 'mkdir'.
356
        os.mkdir(d)
4665.5.15 by Vincent Ladeuil
Catch the retcode for all commands.
357
        return 0, None, None
4665.5.6 by Vincent Ladeuil
Implement 'bzr' command.
358
4665.5.22 by Vincent Ladeuil
Try to relax the test_case/script runner coupling.
359
    def do_rm(self, test_case, input, args):
4665.5.17 by Vincent Ladeuil
Implement 'rm' command.
360
        err = None
361
362
        def error(msg, path):
363
            return  "rm: cannot remove '%s': %s\n" % (path, msg)
364
365
        force, recursive = False, False
366
        opts = None
367
        if args and args[0][0] == '-':
368
            opts = args.pop(0)[1:]
369
            if 'f' in opts:
370
                force = True
371
                opts = opts.replace('f', '', 1)
372
            if 'r' in opts:
373
                recursive = True
374
                opts = opts.replace('r', '', 1)
375
        if not args or opts:
376
            raise SyntaxError('Usage: rm [-fr] path+')
377
        for p in args:
4665.5.23 by Vincent Ladeuil
Revert the jail_root parameter addition.
378
            self._ensure_in_jail(test_case, p)
4665.5.17 by Vincent Ladeuil
Implement 'rm' command.
379
            # FIXME: Should we put that in osutils ?
380
            try:
381
                os.remove(p)
382
            except OSError, e:
4707.1.1 by Vincent Ladeuil
Fix OSX and FreeBSD failures.
383
                # Various OSes raises different exceptions (linux: EISDIR,
384
                #   win32: EACCES, OSX: EPERM) when invoked on a directory
385
                if e.errno in (errno.EISDIR, errno.EPERM, errno.EACCES):
4665.5.17 by Vincent Ladeuil
Implement 'rm' command.
386
                    if recursive:
387
                        osutils.rmtree(p)
388
                    else:
389
                        err = error('Is a directory', p)
390
                        break
391
                elif e.errno == errno.ENOENT:
392
                    if not force:
393
                        err =  error('No such file or directory', p)
394
                        break
395
                else:
396
                    raise
397
        if err:
398
            retcode = 1
399
        else:
400
            retcode = 0
401
        return retcode, None, err
402
4665.5.10 by Vincent Ladeuil
Start separating the script runner from the test case.
403
4665.5.11 by Vincent Ladeuil
Create a new test case based on TestCaseWithMemoryTransport.
404
class TestCaseWithMemoryTransportAndScript(tests.TestCaseWithMemoryTransport):
4665.5.22 by Vincent Ladeuil
Try to relax the test_case/script runner coupling.
405
    """Helper class to experiment shell-like test and memory fs.
406
407
    This not intended to be used outside of experiments in implementing memoy
408
    based file systems and evolving bzr so that test can use only memory based
409
    resources.
410
    """
4665.5.11 by Vincent Ladeuil
Create a new test case based on TestCaseWithMemoryTransport.
411
412
    def setUp(self):
413
        super(TestCaseWithMemoryTransportAndScript, self).setUp()
4665.5.22 by Vincent Ladeuil
Try to relax the test_case/script runner coupling.
414
        self.script_runner = ScriptRunner()
4665.5.11 by Vincent Ladeuil
Create a new test case based on TestCaseWithMemoryTransport.
415
416
    def run_script(self, script):
4665.5.24 by Vincent Ladeuil
Scripts can be used without imposing a test base class.
417
        return self.script_runner.run_script(self, script)
4665.5.11 by Vincent Ladeuil
Create a new test case based on TestCaseWithMemoryTransport.
418
419
    def run_command(self, cmd, input, output, error):
4665.5.24 by Vincent Ladeuil
Scripts can be used without imposing a test base class.
420
        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.
421
422
4665.5.10 by Vincent Ladeuil
Start separating the script runner from the test case.
423
class TestCaseWithTransportAndScript(tests.TestCaseWithTransport):
4665.5.22 by Vincent Ladeuil
Try to relax the test_case/script runner coupling.
424
    """Helper class to quickly define shell-like tests.
425
426
    Can be used as:
427
428
    from bzrlib.tests import script
429
430
431
    class TestBug(script.TestCaseWithTransportAndScript):
432
433
        def test_bug_nnnnn(self):
434
            self.run_script('''
435
            $ bzr init
436
            $ bzr do-this
437
            # Boom, error
438
            ''')
439
    """
4665.5.10 by Vincent Ladeuil
Start separating the script runner from the test case.
440
441
    def setUp(self):
442
        super(TestCaseWithTransportAndScript, self).setUp()
4665.5.23 by Vincent Ladeuil
Revert the jail_root parameter addition.
443
        self.script_runner = ScriptRunner()
444
4665.5.10 by Vincent Ladeuil
Start separating the script runner from the test case.
445
    def run_script(self, script):
4665.5.24 by Vincent Ladeuil
Scripts can be used without imposing a test base class.
446
        return self.script_runner.run_script(self, script)
4665.5.10 by Vincent Ladeuil
Start separating the script runner from the test case.
447
448
    def run_command(self, cmd, input, output, error):
4665.5.24 by Vincent Ladeuil
Scripts can be used without imposing a test base class.
449
        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.
450