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
110
112
if output is None:
111
113
if cmd_cur is None:
112
raise SyntaxError('No command for that output',
114
raise SyntaxError('No command for line %r' % (line,),
113
115
(file_name, lineno, 1, orig))
115
117
output.append(line + '\n')
160
162
class ScriptRunner(object):
162
def __init__(self, test_case):
163
self.test_case = test_case
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, '''
164
181
self.output_checker = doctest.OutputChecker()
165
182
self.check_options = doctest.ELLIPSIS
167
def run_script(self, text):
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).
168
193
for cmd, input, output, error in _script_to_commands(text):
169
self.run_command(cmd, input, output, error)
171
def _check_output(self, expected, actual):
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):
172
218
if expected is None:
173
219
# Specifying None means: any output is accepted
175
221
if actual is None:
176
self.test_case.fail('Unexpected: %s' % actual)
222
test_case.fail('We expected output: %r, but found None'
177
224
matching = self.output_checker.check_output(
178
225
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
228
255
def _read_input(self, input, in_name):
229
256
if in_name is not None:
230
257
infile = open(in_name, 'rb')
248
def do_bzr(self, input, args):
249
retcode, out, err = self.test_case._run_bzr_core(
275
def do_bzr(self, test_case, input, args):
276
retcode, out, err = test_case._run_bzr_core(
250
277
args, retcode=None, encoding=None, stdin=input, working_dir=None)
251
278
return retcode, out, err
253
def do_cat(self, input, args):
280
def do_cat(self, test_case, input, args):
254
281
(in_name, out_name, out_mode, args) = _scan_redirection_options(args)
255
282
if args and in_name is not None:
256
283
raise SyntaxError('Specify a file OR use redirection')
266
293
inputs.append(self._read_input(None, in_name))
267
294
except IOError, e:
268
if e.errno == errno.ENOENT:
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):
270
299
'%s: No such file or directory\n' % (in_name,))
271
301
# Basically cat copy input to output
272
302
output = ''.join(inputs)
273
303
# Handle output redirections
275
305
output = self._write_output(output, out_name, out_mode)
276
306
except IOError, e:
277
if e.errno == errno.ENOENT:
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):
278
310
return 1, None, '%s: No such file or directory\n' % (out_name,)
279
312
return 0, output, None
281
def do_echo(self, input, args):
314
def do_echo(self, test_case, input, args):
282
315
(in_name, out_name, out_mode, args) = _scan_redirection_options(args)
284
raise SyntaxError('Specify parameters OR use redirection')
317
raise SyntaxError('echo doesn\'t read from stdin')
286
319
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,)
292
320
# Always append a \n'
298
326
output = self._write_output(output, out_name, out_mode)
299
327
except IOError, e:
300
if e.errno == errno.ENOENT:
328
if e.errno in (errno.ENOENT, errno.EINVAL):
301
329
return 1, None, '%s: No such file or directory\n' % (out_name,)
302
331
return 0, output, None
304
def _ensure_in_jail(self, path):
305
jail_root = self.test_case.get_jail_root()
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)
306
338
if not osutils.is_inside(jail_root, osutils.normalizepath(path)):
307
339
raise ValueError('%s is not inside %s' % (path, jail_root))
309
def do_cd(self, input, args):
341
def do_cd(self, test_case, input, args):
310
342
if len(args) > 1:
311
343
raise SyntaxError('Usage: cd [dir]')
312
344
if len(args) == 1:
314
self._ensure_in_jail(d)
346
self._ensure_in_jail(test_case, d)
316
d = self.test_case.get_jail_root()
348
# The test "home" directory is the root of its jail
349
d = self._get_jail_root(test_case)
318
351
return 0, None, None
320
def do_mkdir(self, input, args):
353
def do_mkdir(self, test_case, input, args):
321
354
if not args or len(args) != 1:
322
355
raise SyntaxError('Usage: mkdir dir')
324
self._ensure_in_jail(d)
357
self._ensure_in_jail(test_case, d)
326
359
return 0, None, None
328
def do_rm(self, input, args):
361
def do_rm(self, test_case, input, args):
331
364
def error(msg, path):
344
377
if not args or opts:
345
378
raise SyntaxError('Usage: rm [-fr] path+')
347
self._ensure_in_jail(p)
380
self._ensure_in_jail(test_case, p)
348
381
# FIXME: Should we put that in osutils ?
351
384
except OSError, e:
352
if e.errno == errno.EISDIR:
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):
354
389
osutils.rmtree(p)
368
403
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
371
431
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
374
440
super(TestCaseWithMemoryTransportAndScript, self).setUp()
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)
441
self.script_runner = ScriptRunner()
384
443
def run_script(self, script):
385
return self.script_runner.run_script(script)
444
return self.script_runner.run_script(self, script)
387
446
def run_command(self, cmd, input, output, error):
388
return self.script_runner.run_command(cmd, input, output, error)
447
return self.script_runner.run_command(self, cmd, input, output, error)
391
450
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):
394
469
super(TestCaseWithTransportAndScript, self).setUp()
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):
470
self.script_runner = ScriptRunner()
404
472
def run_script(self, script):
405
return self.script_runner.run_script(script)
473
return self.script_runner.run_script(self, script)
407
475
def run_command(self, cmd, input, output, error):
408
return self.script_runner.run_command(cmd, input, output, error)
476
return self.script_runner.run_command(self, cmd, input, output, error)