/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
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
16
4665.5.4 by Vincent Ladeuil
Implement a 'cat' command.
17
from cStringIO import StringIO
4665.5.5 by Vincent Ladeuil
Implement 'cd' and 'mkdir'.
18
import os
4665.5.1 by Vincent Ladeuil
Start some shell-like capability to write tests.
19
import shlex
20
4665.5.5 by Vincent Ladeuil
Implement 'cd' and 'mkdir'.
21
from bzrlib import (
22
    osutils,
23
    tests,
24
    )
4665.5.4 by Vincent Ladeuil
Implement a 'cat' command.
25
4665.5.1 by Vincent Ladeuil
Start some shell-like capability to write tests.
26
4665.5.2 by Vincent Ladeuil
Handle simple, double and back quotes.
27
def split(s):
28
    """Split a command line respecting quotes."""
29
    scanner = shlex.shlex(s)
30
    scanner.quotes = '\'"`'
31
    scanner.whitespace_split = True
32
    for t in list(scanner):
33
        # Strip the simple and double quotes since we don't care about them.
34
        # We leave the backquotes in place though since they have a different
35
        # semantic.
36
        if t[0] in  ('"', "'") and t[0] == t[-1]:
37
            yield t[1:-1]
38
        else:
39
            yield t
40
41
42
def _script_to_commands(text, file_name=None):
4665.5.1 by Vincent Ladeuil
Start some shell-like capability to write tests.
43
    """Turn a script into a list of commands with their associated IOs.
44
45
    Each command appears on a line by itself. It can be associated with an
46
    input that will feed it and an expected output.
47
    Comments starts with '#' until the end of line.
48
    Empty lines are ignored.
49
    Input and output are full lines terminated by a '\n'.
50
    Input lines start with '<'.
4665.5.3 by Vincent Ladeuil
Separate error from normal output.
51
    Output lines start with '>'.
52
    Error lines start with '2>'.
4665.5.1 by Vincent Ladeuil
Start some shell-like capability to write tests.
53
    """
4665.5.7 by Vincent Ladeuil
Simplify output/errors handling.
54
4665.5.1 by Vincent Ladeuil
Start some shell-like capability to write tests.
55
    commands = []
4665.5.7 by Vincent Ladeuil
Simplify output/errors handling.
56
57
    def add_command(cmd, input, output, error):
58
        if cmd is not None:
59
            if input is not None:
60
                input = ''.join(input)
61
            if output is not None:
62
                output = ''.join(output)
63
            if error is not None:
64
                error = ''.join(error)
65
            commands.append((cmd, input, output, error))
66
4665.5.1 by Vincent Ladeuil
Start some shell-like capability to write tests.
67
    cmd_cur = None
68
    cmd_line = 1
69
    lineno = 0
4665.5.3 by Vincent Ladeuil
Separate error from normal output.
70
    input, output, error = None, None, None
4665.5.2 by Vincent Ladeuil
Handle simple, double and back quotes.
71
    for line in text.split('\n'):
4665.5.1 by Vincent Ladeuil
Start some shell-like capability to write tests.
72
        lineno += 1
73
        # Keep a copy for error reporting
74
        orig = line
75
        comment =  line.find('#')
76
        if comment >= 0:
77
            # Delete comments
78
            line = line[0:comment]
79
            line = line.rstrip()
80
        if line == '':
81
            # Ignore empty lines
82
            continue
83
        if line.startswith('<'):
84
            if input is None:
85
                if cmd_cur is None:
86
                    raise SyntaxError('No command for that input',
87
                                      (file_name, lineno, 1, orig))
88
                input = []
89
            input.append(line[1:] + '\n')
90
            continue
91
        elif line.startswith('>'):
92
            if output is None:
93
                if cmd_cur is None:
94
                    raise SyntaxError('No command for that output',
95
                                      (file_name, lineno, 1, orig))
96
                output = []
97
            output.append(line[1:] + '\n')
98
            continue
4665.5.3 by Vincent Ladeuil
Separate error from normal output.
99
        elif line.startswith('2>'):
100
            if error is None:
101
                if cmd_cur is None:
102
                    raise SyntaxError('No command for that error',
103
                                      (file_name, lineno, 1, orig))
104
                error = []
105
            error.append(line[2:] + '\n')
106
            continue
4665.5.1 by Vincent Ladeuil
Start some shell-like capability to write tests.
107
        else:
108
            # Time to output the current command
4665.5.7 by Vincent Ladeuil
Simplify output/errors handling.
109
            add_command(cmd_cur, input, output, error)
4665.5.1 by Vincent Ladeuil
Start some shell-like capability to write tests.
110
            # And start a new one
4665.5.2 by Vincent Ladeuil
Handle simple, double and back quotes.
111
            cmd_cur = list(split(line))
4665.5.1 by Vincent Ladeuil
Start some shell-like capability to write tests.
112
            cmd_line = lineno
4665.5.3 by Vincent Ladeuil
Separate error from normal output.
113
            input, output, error = None, None, None
4665.5.1 by Vincent Ladeuil
Start some shell-like capability to write tests.
114
    # Add the last seen command
4665.5.7 by Vincent Ladeuil
Simplify output/errors handling.
115
    add_command(cmd_cur, input, output, error)
4665.5.1 by Vincent Ladeuil
Start some shell-like capability to write tests.
116
    return commands
4665.5.4 by Vincent Ladeuil
Implement a 'cat' command.
117
118
4665.5.8 by Vincent Ladeuil
Implement 'echo' command.
119
def _scan_redirection_options(args):
120
    """Recognize and process input and output redirections.
121
122
    :param args: The command line arguments
123
124
    :return: A tuple containing: 
125
        - The file name redirected from or None
126
        - The file name redirected to or None
127
        - The mode to open the output file or None
128
        - The reamining arguments
129
    """
130
    remaining = []
131
    in_name = None
132
    out_name, out_mode = None, None
133
    for arg in  args:
134
        if arg.startswith('<'):
135
            in_name = arg[1:]
136
        elif arg.startswith('>>'):
137
            out_name = arg[2:]
138
            out_mode = 'ab+'
139
        elif arg.startswith('>'):
140
            out_name = arg[1:]
141
            out_mode = 'wb+'
142
        else:
143
            remaining.append(arg)
144
    return in_name, out_name, out_mode, remaining
145
146
4665.5.4 by Vincent Ladeuil
Implement a 'cat' command.
147
class TestCaseWithScript(tests.TestCaseWithTransport):
148
149
    def setUp(self):
150
        super(TestCaseWithScript, self).setUp()
151
        self._vars = {}
152
153
    def run_script(self, text):
154
        for cmd, input, output, error in _script_to_commands(text):
155
            self.run_command(cmd, input, output, error)
156
4665.5.5 by Vincent Ladeuil
Implement 'cd' and 'mkdir'.
157
    def _check_output(self, expected, actual):
158
        if expected is None:
4665.5.6 by Vincent Ladeuil
Implement 'bzr' command.
159
            # Specifying None means: any output is accepted
160
            return
4665.5.7 by Vincent Ladeuil
Simplify output/errors handling.
161
        self.assertEquals(expected, actual)
4665.5.5 by Vincent Ladeuil
Implement 'cd' and 'mkdir'.
162
4665.5.4 by Vincent Ladeuil
Implement a 'cat' command.
163
    def run_command(self, cmd, input, output, error):
164
        mname = 'do_' + cmd[0]
165
        method = getattr(self, mname, None)
166
        if method is None:
167
            raise SyntaxError('Command not found "%s"' % (cmd[0],),
168
                              None, 1, ' '.join(cmd))
169
        if input is None:
170
            str_input = ''
171
        else:
172
            str_input = ''.join(input)
173
        actual_output, actual_error = method(str_input, cmd[1:])
4665.5.5 by Vincent Ladeuil
Implement 'cd' and 'mkdir'.
174
175
        self._check_output(output, actual_output)
176
        self._check_output(error, actual_error)
4665.5.4 by Vincent Ladeuil
Implement a 'cat' command.
177
        return actual_output, actual_error
178
4665.5.8 by Vincent Ladeuil
Implement 'echo' command.
179
    def _read_input(self, input, in_name):
4665.5.4 by Vincent Ladeuil
Implement a 'cat' command.
180
        if in_name is not None:
181
            infile = open(in_name, 'rb')
182
            try:
4665.5.8 by Vincent Ladeuil
Implement 'echo' command.
183
                # Command redirection takes precedence over provided input
4665.5.4 by Vincent Ladeuil
Implement a 'cat' command.
184
                input = infile.read()
185
            finally:
186
                infile.close()
4665.5.8 by Vincent Ladeuil
Implement 'echo' command.
187
        return input
188
189
    def _write_output(self, output, out_name, out_mode):
4665.5.4 by Vincent Ladeuil
Implement a 'cat' command.
190
        if out_name is not None:
4665.5.8 by Vincent Ladeuil
Implement 'echo' command.
191
            outfile = open(out_name, out_mode)
4665.5.4 by Vincent Ladeuil
Implement a 'cat' command.
192
            try:
193
                outfile.write(output)
194
            finally:
195
                outfile.close()
4665.5.5 by Vincent Ladeuil
Implement 'cd' and 'mkdir'.
196
            output = None
4665.5.8 by Vincent Ladeuil
Implement 'echo' command.
197
        return output
198
199
    def do_bzr(self, input, args):
200
        out, err = self._run_bzr_core(args, retcode=None, encoding=None,
201
                                      stdin=input, working_dir=None)
202
        return out, err
203
204
    def do_cat(self, input, args):
205
        (in_name, out_name, out_mode, args) = _scan_redirection_options(args)
206
        if len(args) > 1:
207
            raise SyntaxError('Usage: cat [file1]')
208
        if args:
209
            if in_name is not None:
210
                raise SyntaxError('Specify a file OR use redirection')
211
            in_name = args[0]
212
        input = self._read_input(input, in_name)
213
        # Basically cat copy input to output
214
        output = input
215
        # Handle output redirections
216
        output = self._write_output(output, out_name, out_mode)
217
        return output, None
218
219
    def do_echo(self, input, args):
220
        (in_name, out_name, out_mode, args) = _scan_redirection_options(args)
221
        if input and args:
222
                raise SyntaxError('Specify parameters OR use redirection')
223
        if args:
224
            input = ''.join(args)
225
        input = self._read_input(input, in_name)
226
        # Always append a \n'
227
        input += '\n'
228
        # Process output
229
        output = input
230
        # Handle output redirections
231
        output = self._write_output(output, out_name, out_mode)
4665.5.5 by Vincent Ladeuil
Implement 'cd' and 'mkdir'.
232
        return output, None
233
234
    def _ensure_in_jail(self, path):
235
        if not osutils.is_inside(self.test_dir, osutils.normalizepath(path)):
236
                raise ValueError('%s is not inside %s' % (path, self.test_dir))
237
238
    def do_cd(self, input, args):
239
        if len(args) > 1:
240
            raise SyntaxError('Usage: cd [dir]')
241
        if len(args) == 1:
242
            d = args[0]
243
            self._ensure_in_jail(d)
244
        else:
245
            d = self.test_dir
246
        os.chdir(d)
247
        return None, None
248
249
    def do_mkdir(self, input, args):
250
        if not args or len(args) != 1:
251
            raise SyntaxError('Usage: mkdir dir')
252
        d = args[0]
253
        self._ensure_in_jail(d)
254
        os.mkdir(d)
255
        return None, None
4665.5.6 by Vincent Ladeuil
Implement 'bzr' command.
256