13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
from cStringIO import StringIO
16
"""Shell-like test scripts.
18
This allows users to write tests in a syntax very close to a shell session,
19
using a restricted and limited set of commands that should be enough to mimic
20
most of the behaviours.
22
A script is a set of commands, each command is composed of:
23
- one mandatory command line,
24
- one optional set of input lines to feed the command,
25
- one optional set of output expected lines,
26
- one optional set of error expected lines.
28
The optional lines starts with a special string (mnemonic: shell redirection):
33
The execution stops as soon as an expected output or an expected error is not
36
When no output is specified, any ouput from the command is accepted
37
and let the execution continue.
39
If an error occurs and no expected error is specified, the execution stops.
41
The matching is done on a full string comparison basis unless '...' is used, in
42
which case expected output/errors can be lees precise.
46
The following will succeeds only if 'bzr add' outputs 'adding file'.
51
If you want the command to succeed for any output, just use:
55
The following will stop with an error:
59
If you want it to succeed, use:
62
2> bzr: ERROR: unknown command "not-a-command"
64
You can use ellipsis (...) to replace any piece of text you don't want to be
67
bzr branch not-a-branch
68
2>bzr: ERROR: Not a branch...not-a-branch/".
71
This can be used to ignore entire lines too:
83
You can check the content of a file with cat:
88
You can also check the existence of a file with cat, the following will fail if
89
the file doesn't exist:
98
from cStringIO import StringIO
21
100
from bzrlib import (
144
223
return in_name, out_name, out_mode, remaining
147
class TestCaseWithScript(tests.TestCaseWithTransport):
226
class ScriptRunner(object):
150
super(TestCaseWithScript, self).setUp()
228
def __init__(self, test_case):
229
self.test_case = test_case
230
self.output_checker = doctest.OutputChecker()
231
self.check_options = doctest.ELLIPSIS
153
233
def run_script(self, text):
154
234
for cmd, input, output, error in _script_to_commands(text):
155
self.run_command(cmd, input, output, error)
235
out, err = self.run_command(cmd, input, output, error)
157
237
def _check_output(self, expected, actual):
158
238
if expected is None:
159
239
# Specifying None means: any output is accepted
161
self.assertEquals(expected, actual)
242
self.test_case.fail('Unexpected: %s' % actual)
243
matching = self.output_checker.check_output(
244
expected, actual, self.check_options)
246
# Note that we can't use output_checker.output_difference() here
247
# because... the API is boken (expected must be a doctest specific
248
# object of whicha 'want' attribute will be our 'expected'
249
# parameter. So we just fallbacl to our good old assertEqualDiff
250
# since we know there are differences and the output should be
252
self.test_case.assertEqualDiff(expected, actual)
163
254
def run_command(self, cmd, input, output, error):
164
255
mname = 'do_' + cmd[0]
175
266
self._check_output(output, actual_output)
176
267
self._check_output(error, actual_error)
268
if not error and actual_error:
269
self.test_case.fail('Unexpected error: %s' % actual_error)
177
270
return actual_output, actual_error
179
272
def _read_input(self, input, in_name):
199
292
def do_bzr(self, input, args):
200
out, err = self._run_bzr_core(args, retcode=None, encoding=None,
201
stdin=input, working_dir=None)
293
out, err = self.test_case._run_bzr_core(
294
args, retcode=None, encoding=None, stdin=input, working_dir=None)
204
297
def do_cat(self, input, args):
232
325
return output, None
234
327
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))
328
jail_root = self.test_case.get_jail_root()
329
if not osutils.is_inside(jail_root, osutils.normalizepath(path)):
330
raise ValueError('%s is not inside %s' % (path, jail_root))
238
332
def do_cd(self, input, args):
239
333
if len(args) > 1:
255
349
return None, None
352
class TestCaseWithMemoryTransportAndScript(tests.TestCaseWithMemoryTransport):
355
super(TestCaseWithMemoryTransportAndScript, self).setUp()
356
self.script_runner = ScriptRunner(self)
357
# Break the circular dependency
358
def break_dependency():
359
self.script_runner = None
360
self.addCleanup(break_dependency)
362
def get_jail_root(self):
363
raise NotImplementedError(self.get_jail_root)
365
def run_script(self, script):
366
return self.script_runner.run_script(script)
368
def run_command(self, cmd, input, output, error):
369
return self.script_runner.run_command(cmd, input, output, error)
372
class TestCaseWithTransportAndScript(tests.TestCaseWithTransport):
375
super(TestCaseWithTransportAndScript, self).setUp()
376
self.script_runner = ScriptRunner(self)
377
# Break the circular dependency
378
def break_dependency():
379
self.script_runner = None
380
self.addCleanup(break_dependency)
382
def get_jail_root(self):
385
def run_script(self, script):
386
return self.script_runner.run_script(script)
388
def run_command(self, cmd, input, output, error):
389
return self.script_runner.run_command(cmd, input, output, error)