108
108
error.append(line[2:] + '\n')
110
# can happen if the first line is not recognized as a command, eg
111
# if the prompt has leading whitespace
112
110
if output is None:
113
111
if cmd_cur is None:
114
raise SyntaxError('No command for line %r' % (line,),
112
raise SyntaxError('No command for that output',
115
113
(file_name, lineno, 1, orig))
117
115
output.append(line + '\n')
162
160
class ScriptRunner(object):
163
"""Run a shell-like script from a test.
167
from bzrlib.tests import script
171
def test_bug_nnnnn(self):
172
sr = script.ScriptRunner()
173
sr.run_script(self, '''
162
def __init__(self, test_case):
163
self.test_case = test_case
181
164
self.output_checker = doctest.OutputChecker()
182
165
self.check_options = doctest.ELLIPSIS
184
def run_script(self, test_case, text):
185
"""Run a shell-like script as a test.
187
:param test_case: A TestCase instance that should provide the fail(),
188
assertEqualDiff and _run_bzr_core() methods as well as a 'test_dir'
189
attribute used as a jail root.
191
:param text: A shell-like script (see _script_to_commands for syntax).
167
def run_script(self, text):
193
168
for cmd, input, output, error in _script_to_commands(text):
194
self.run_command(test_case, cmd, input, output, error)
196
def run_command(self, test_case, cmd, input, output, error):
197
mname = 'do_' + cmd[0]
198
method = getattr(self, mname, None)
200
raise SyntaxError('Command not found "%s"' % (cmd[0],),
201
None, 1, ' '.join(cmd))
205
str_input = ''.join(input)
206
args = list(self._pre_process_args(cmd[1:]))
207
retcode, actual_output, actual_error = method(test_case,
210
self._check_output(output, actual_output, test_case)
211
self._check_output(error, actual_error, test_case)
212
if retcode and not error and actual_error:
213
test_case.fail('In \n\t%s\nUnexpected error: %s'
214
% (' '.join(cmd), actual_error))
215
return retcode, actual_output, actual_error
217
def _check_output(self, expected, actual, test_case):
169
self.run_command(cmd, input, output, error)
171
def _check_output(self, expected, actual):
218
172
if expected is None:
219
173
# Specifying None means: any output is accepted
221
175
if actual is None:
222
test_case.fail('We expected output: %r, but found None'
176
self.test_case.fail('Unexpected: %s' % actual)
224
177
matching = self.output_checker.check_output(
225
178
expected, actual, self.check_options)
208
def run_command(self, cmd, input, output, error):
209
mname = 'do_' + cmd[0]
210
method = getattr(self, mname, None)
212
raise SyntaxError('Command not found "%s"' % (cmd[0],),
213
None, 1, ' '.join(cmd))
217
str_input = ''.join(input)
218
args = list(self._pre_process_args(cmd[1:]))
219
retcode, actual_output, actual_error = method(str_input, args)
221
self._check_output(output, actual_output)
222
self._check_output(error, actual_error)
223
if retcode and not error and actual_error:
224
self.test_case.fail('In \n\t%s\nUnexpected error: %s'
225
% (' '.join(cmd), actual_error))
226
return retcode, actual_output, actual_error
255
228
def _read_input(self, input, in_name):
256
229
if in_name is not None:
257
230
infile = open(in_name, 'rb')
275
def do_bzr(self, test_case, input, args):
276
retcode, out, err = test_case._run_bzr_core(
248
def do_bzr(self, input, args):
249
retcode, out, err = self.test_case._run_bzr_core(
277
250
args, retcode=None, encoding=None, stdin=input, working_dir=None)
278
251
return retcode, out, err
280
def do_cat(self, test_case, input, args):
253
def do_cat(self, input, args):
281
254
(in_name, out_name, out_mode, args) = _scan_redirection_options(args)
282
255
if args and in_name is not None:
283
256
raise SyntaxError('Specify a file OR use redirection')
293
266
inputs.append(self._read_input(None, in_name))
294
267
except IOError, e:
295
# Some filenames are illegal on Windows and generate EINVAL
296
# rather than just saying the filename doesn't exist
297
if e.errno in (errno.ENOENT, errno.EINVAL):
268
if e.errno == errno.ENOENT:
299
270
'%s: No such file or directory\n' % (in_name,))
301
271
# Basically cat copy input to output
302
272
output = ''.join(inputs)
303
273
# Handle output redirections
305
275
output = self._write_output(output, out_name, out_mode)
306
276
except IOError, e:
307
# If out_name cannot be created, we may get 'ENOENT', however if
308
# out_name is something like '', we can get EINVAL
309
if e.errno in (errno.ENOENT, errno.EINVAL):
277
if e.errno == errno.ENOENT:
310
278
return 1, None, '%s: No such file or directory\n' % (out_name,)
312
279
return 0, output, None
314
def do_echo(self, test_case, input, args):
281
def do_echo(self, input, args):
315
282
(in_name, out_name, out_mode, args) = _scan_redirection_options(args)
317
raise SyntaxError('echo doesn\'t read from stdin')
284
raise SyntaxError('Specify parameters OR use redirection')
319
286
input = ' '.join(args)
288
input = self._read_input(input, in_name)
290
if e.errno == errno.ENOENT:
291
return 1, None, '%s: No such file or directory\n' % (in_name,)
320
292
# Always append a \n'
326
298
output = self._write_output(output, out_name, out_mode)
327
299
except IOError, e:
328
if e.errno in (errno.ENOENT, errno.EINVAL):
300
if e.errno == errno.ENOENT:
329
301
return 1, None, '%s: No such file or directory\n' % (out_name,)
331
302
return 0, output, None
333
def _get_jail_root(self, test_case):
334
return test_case.test_dir
336
def _ensure_in_jail(self, test_case, path):
337
jail_root = self._get_jail_root(test_case)
304
def _ensure_in_jail(self, path):
305
jail_root = self.test_case.get_jail_root()
338
306
if not osutils.is_inside(jail_root, osutils.normalizepath(path)):
339
307
raise ValueError('%s is not inside %s' % (path, jail_root))
341
def do_cd(self, test_case, input, args):
309
def do_cd(self, input, args):
342
310
if len(args) > 1:
343
311
raise SyntaxError('Usage: cd [dir]')
344
312
if len(args) == 1:
346
self._ensure_in_jail(test_case, d)
314
self._ensure_in_jail(d)
348
# The test "home" directory is the root of its jail
349
d = self._get_jail_root(test_case)
316
d = self.test_case.get_jail_root()
351
318
return 0, None, None
353
def do_mkdir(self, test_case, input, args):
320
def do_mkdir(self, input, args):
354
321
if not args or len(args) != 1:
355
322
raise SyntaxError('Usage: mkdir dir')
357
self._ensure_in_jail(test_case, d)
324
self._ensure_in_jail(d)
359
326
return 0, None, None
361
def do_rm(self, test_case, input, args):
328
def do_rm(self, input, args):
364
331
def error(msg, path):
377
344
if not args or opts:
378
345
raise SyntaxError('Usage: rm [-fr] path+')
380
self._ensure_in_jail(test_case, p)
347
self._ensure_in_jail(p)
381
348
# FIXME: Should we put that in osutils ?
384
351
except OSError, e:
385
# Various OSes raises different exceptions (linux: EISDIR,
386
# win32: EACCES, OSX: EPERM) when invoked on a directory
387
if e.errno in (errno.EISDIR, errno.EPERM, errno.EACCES):
352
if e.errno == errno.EISDIR:
389
354
osutils.rmtree(p)
403
368
return retcode, None, err
405
def do_mv(self, test_case, input, args):
407
def error(msg, src, dst):
408
return "mv: cannot move %s to %s: %s\n" % (src, dst, msg)
410
if not args or len(args) != 2:
411
raise SyntaxError("Usage: mv path1 path2")
415
if os.path.isdir(dst):
416
real_dst = os.path.join(dst, os.path.basename(src))
417
os.rename(src, real_dst)
419
if e.errno == errno.ENOENT:
420
err = error('No such file or directory', src, dst)
427
return retcode, None, err
431
371
class TestCaseWithMemoryTransportAndScript(tests.TestCaseWithMemoryTransport):
432
"""Helper class to experiment shell-like test and memory fs.
434
This not intended to be used outside of experiments in implementing memoy
435
based file systems and evolving bzr so that test can use only memory based
440
374
super(TestCaseWithMemoryTransportAndScript, self).setUp()
441
self.script_runner = ScriptRunner()
375
self.script_runner = ScriptRunner(self)
376
# Break the circular dependency
377
def break_dependency():
378
self.script_runner = None
379
self.addCleanup(break_dependency)
381
def get_jail_root(self):
382
raise NotImplementedError(self.get_jail_root)
443
384
def run_script(self, script):
444
return self.script_runner.run_script(self, script)
385
return self.script_runner.run_script(script)
446
387
def run_command(self, cmd, input, output, error):
447
return self.script_runner.run_command(self, cmd, input, output, error)
388
return self.script_runner.run_command(cmd, input, output, error)
450
391
class TestCaseWithTransportAndScript(tests.TestCaseWithTransport):
451
"""Helper class to quickly define shell-like tests.
455
from bzrlib.tests import script
458
class TestBug(script.TestCaseWithTransportAndScript):
460
def test_bug_nnnnn(self):
469
394
super(TestCaseWithTransportAndScript, self).setUp()
470
self.script_runner = ScriptRunner()
395
self.script_runner = ScriptRunner(self)
396
# Break the circular dependency
397
def break_dependency():
398
self.script_runner = None
399
self.addCleanup(break_dependency)
401
def get_jail_root(self):
472
404
def run_script(self, script):
473
return self.script_runner.run_script(self, script)
405
return self.script_runner.run_script(script)
475
407
def run_command(self, cmd, input, output, error):
476
return self.script_runner.run_command(self, cmd, input, output, error)
408
return self.script_runner.run_command(cmd, input, output, error)