1
# Copyright (C) 2009, 2010 Canonical Ltd
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.
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.
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
25
from bzrlib.tests import script
28
class TestSyntax(tests.TestCase):
30
def test_comment_is_ignored(self):
31
self.assertEquals([], script._script_to_commands('#comment\n'))
33
def test_comment_multiple_lines(self):
35
(['bar'], None, None, None),
37
script._script_to_commands("""
38
# this comment is ignored
44
def test_trim_blank_lines(self):
45
"""Blank lines are respected, but trimmed at the start and end.
47
Python triple-quoted syntax is going to give stubby/empty blank lines
48
right at the start and the end. These are cut off so that callers don't
49
need special syntax to avoid them.
51
However we do want to be able to match commands that emit blank lines.
54
(['bar'], None, '\n', None),
56
script._script_to_commands("""
61
def test_simple_command(self):
62
self.assertEquals([(['cd', 'trunk'], None, None, None)],
63
script._script_to_commands('$ cd trunk'))
65
def test_command_with_single_quoted_param(self):
66
story = """$ bzr commit -m 'two words'"""
67
self.assertEquals([(['bzr', 'commit', '-m', "'two words'"],
69
script._script_to_commands(story))
71
def test_command_with_double_quoted_param(self):
72
story = """$ bzr commit -m "two words" """
73
self.assertEquals([(['bzr', 'commit', '-m', '"two words"'],
75
script._script_to_commands(story))
77
def test_command_with_input(self):
79
[(['cat', '>file'], 'content\n', None, None)],
80
script._script_to_commands('$ cat >file\n<content\n'))
82
def test_indented(self):
83
# scripts are commonly given indented within the test source code, and
84
# common indentation is stripped off
90
self.assertEquals([(['bzr', 'add'], None,
91
'adding file\nadding file2\n', None)],
92
script._script_to_commands(story))
94
def test_command_with_output(self):
100
self.assertEquals([(['bzr', 'add'], None,
101
'adding file\nadding file2\n', None)],
102
script._script_to_commands(story))
104
def test_command_with_error(self):
107
2>bzr: ERROR: Not a branch: "foo"
109
self.assertEquals([(['bzr', 'branch', 'foo'],
110
None, None, 'bzr: ERROR: Not a branch: "foo"\n')],
111
script._script_to_commands(story))
113
def test_input_without_command(self):
114
self.assertRaises(SyntaxError, script._script_to_commands, '<input')
116
def test_output_without_command(self):
117
self.assertRaises(SyntaxError, script._script_to_commands, '>input')
119
def test_command_with_backquotes(self):
121
$ foo = `bzr file-id toto`
123
self.assertEquals([(['foo', '=', '`bzr file-id toto`'],
125
script._script_to_commands(story))
128
class TestRedirections(tests.TestCase):
130
def _check(self, in_name, out_name, out_mode, remaining, args):
131
self.assertEqual(script._scan_redirection_options(args),
132
(in_name, out_name, out_mode, remaining))
134
def test_no_redirection(self):
135
self._check(None, None, None, [], [])
136
self._check(None, None, None, ['foo', 'bar'], ['foo', 'bar'])
138
def test_input_redirection(self):
139
self._check('foo', None, None, [], ['<foo'])
140
self._check('foo', None, None, ['bar'], ['bar', '<foo'])
141
self._check('foo', None, None, ['bar'], ['bar', '<', 'foo'])
142
self._check('foo', None, None, ['bar'], ['<foo', 'bar'])
143
self._check('foo', None, None, ['bar', 'baz'], ['bar', '<foo', 'baz'])
145
def test_output_redirection(self):
146
self._check(None, 'foo', 'wb+', [], ['>foo'])
147
self._check(None, 'foo', 'wb+', ['bar'], ['bar', '>foo'])
148
self._check(None, 'foo', 'wb+', ['bar'], ['bar', '>', 'foo'])
149
self._check(None, 'foo', 'ab+', [], ['>>foo'])
150
self._check(None, 'foo', 'ab+', ['bar'], ['bar', '>>foo'])
151
self._check(None, 'foo', 'ab+', ['bar'], ['bar', '>>', 'foo'])
153
def test_redirection_syntax_errors(self):
154
self._check('', None, None, [], ['<'])
155
self._check(None, '', 'wb+', [], ['>'])
156
self._check(None, '', 'ab+', [], ['>>'])
157
self._check('>', '', 'ab+', [], ['<', '>', '>>'])
161
class TestExecution(script.TestCaseWithTransportAndScript):
163
def test_unknown_command(self):
164
"""A clear error is reported for commands that aren't recognised
166
Testing the attributes of the SyntaxError instance is equivalent to
167
using traceback.format_exception_only and comparing with:
168
File "<string>", line 1
171
SyntaxError: Command not found "foo"
173
e = self.assertRaises(SyntaxError, self.run_script, "$ foo --frob")
174
self.assertContainsRe(e.msg, "not found.*foo")
175
self.assertEquals(e.text, "foo --frob")
177
def test_blank_output_mismatches_output(self):
178
"""If you give output, the output must actually be blank.
180
See <https://bugs.launchpad.net/bzr/+bug/637830>: previously blank
181
output was a wildcard. Now you must say ... if you want that.
183
self.assertRaises(AssertionError,
189
def test_ellipsis_everything(self):
190
"""A simple ellipsis matches everything."""
196
def test_ellipsis_matches_empty(self):
202
def test_stops_on_unexpected_output(self):
206
The cd command ouputs nothing
208
self.assertRaises(AssertionError, self.run_script, story)
210
def test_stops_on_unexpected_error(self):
216
self.assertRaises(AssertionError, self.run_script, story)
218
def test_continue_on_expected_error(self):
223
self.run_script(story)
225
def test_continue_on_error_output(self):
226
# The status matters, not the output
234
$ bzr commit -m 'adding file'
237
self.run_script(story)
239
def test_ellipsis_output(self):
249
self.run_script(story)
254
self.run_script(story)
257
$ bzr branch not-a-branch
258
2>bzr: ERROR: Not a branch...not-a-branch/".
260
self.run_script(story)
263
class TestArgumentProcessing(script.TestCaseWithTransportAndScript):
265
def test_globing(self):
274
def test_quoted_globbing(self):
278
2>*: No such file or directory
281
def test_quotes_removal(self):
283
$ echo 'cat' "dog" '"chicken"' "'dragon'"
284
cat dog "chicken" 'dragon'
287
def test_verbosity_isolated(self):
288
"""Global verbosity is isolated from commands run in scripts.
290
# see also 656694; we should get rid of global verbosity
294
self.assertEquals(trace.is_quiet(), False)
297
class TestCat(script.TestCaseWithTransportAndScript):
299
def test_cat_usage(self):
300
self.assertRaises(SyntaxError, self.run_script, 'cat foo <bar')
302
def test_cat_input_to_output(self):
303
retcode, out, err = self.run_command(['cat'],
304
'content\n', 'content\n', None)
305
self.assertEquals('content\n', out)
306
self.assertEquals(None, err)
308
def test_cat_file_to_output(self):
309
self.build_tree_contents([('file', 'content\n')])
310
retcode, out, err = self.run_command(['cat', 'file'],
311
None, 'content\n', None)
312
self.assertEquals('content\n', out)
313
self.assertEquals(None, err)
315
def test_cat_input_to_file(self):
316
retcode, out, err = self.run_command(['cat', '>file'],
317
'content\n', None, None)
318
self.assertFileEqual('content\n', 'file')
319
self.assertEquals(None, out)
320
self.assertEquals(None, err)
321
retcode, out, err = self.run_command(['cat', '>>file'],
322
'more\n', None, None)
323
self.assertFileEqual('content\nmore\n', 'file')
324
self.assertEquals(None, out)
325
self.assertEquals(None, err)
327
def test_cat_file_to_file(self):
328
self.build_tree_contents([('file', 'content\n')])
329
retcode, out, err = self.run_command(['cat', 'file', '>file2'],
331
self.assertFileEqual('content\n', 'file2')
333
def test_cat_files_to_file(self):
334
self.build_tree_contents([('cat', 'cat\n')])
335
self.build_tree_contents([('dog', 'dog\n')])
336
retcode, out, err = self.run_command(['cat', 'cat', 'dog', '>file'],
338
self.assertFileEqual('cat\ndog\n', 'file')
340
def test_cat_bogus_input_file(self):
343
2>file: No such file or directory
346
def test_cat_bogus_output_file(self):
349
2>: No such file or directory
352
def test_echo_bogus_output_file(self):
353
# We need a backing file sysytem for that test so it can't be in
357
2>: No such file or directory
361
class TestMkdir(script.TestCaseWithTransportAndScript):
363
def test_mkdir_usage(self):
364
self.assertRaises(SyntaxError, self.run_script, '$ mkdir')
365
self.assertRaises(SyntaxError, self.run_script, '$ mkdir foo bar')
367
def test_mkdir_jailed(self):
368
self.assertRaises(ValueError, self.run_script, '$ mkdir /out-of-jail')
369
self.assertRaises(ValueError, self.run_script, '$ mkdir ../out-of-jail')
371
def test_mkdir_in_jail(self):
378
self.failUnlessExists('dir')
379
self.failUnlessExists('dir2')
382
class TestCd(script.TestCaseWithTransportAndScript):
384
def test_cd_usage(self):
385
self.assertRaises(SyntaxError, self.run_script, '$ cd foo bar')
387
def test_cd_out_of_jail(self):
388
self.assertRaises(ValueError, self.run_script, '$ cd /out-of-jail')
389
self.assertRaises(ValueError, self.run_script, '$ cd ..')
391
def test_cd_dir_and_back_home(self):
392
self.assertEquals(self.test_dir, osutils.getcwd())
397
self.assertEquals(osutils.pathjoin(self.test_dir, 'dir'),
400
self.run_script('$ cd')
401
self.assertEquals(self.test_dir, osutils.getcwd())
404
class TestBzr(script.TestCaseWithTransportAndScript):
406
def test_bzr_smoke(self):
409
Created a standalone tree (format: ...)
411
self.failUnlessExists('branch')
414
class TestEcho(script.TestCaseWithMemoryTransportAndScript):
416
def test_echo_usage(self):
421
self.assertRaises(SyntaxError, self.run_script, story)
423
def test_echo_input(self):
424
self.assertRaises(SyntaxError, self.run_script, """
428
def test_echo_to_output(self):
429
retcode, out, err = self.run_command(['echo'], None, '\n', None)
430
self.assertEquals('\n', out)
431
self.assertEquals(None, err)
433
def test_echo_some_to_output(self):
434
retcode, out, err = self.run_command(['echo', 'hello'],
435
None, 'hello\n', None)
436
self.assertEquals('hello\n', out)
437
self.assertEquals(None, err)
439
def test_echo_more_output(self):
440
retcode, out, err = self.run_command(
441
['echo', 'hello', 'happy', 'world'],
442
None, 'hello happy world\n', None)
443
self.assertEquals('hello happy world\n', out)
444
self.assertEquals(None, err)
446
def test_echo_appended(self):
447
retcode, out, err = self.run_command(['echo', 'hello', '>file'],
449
self.assertEquals(None, out)
450
self.assertEquals(None, err)
451
self.assertFileEqual('hello\n', 'file')
452
retcode, out, err = self.run_command(['echo', 'happy', '>>file'],
454
self.assertEquals(None, out)
455
self.assertEquals(None, err)
456
self.assertFileEqual('hello\nhappy\n', 'file')
458
def test_empty_line_in_output_is_respected(self):
467
class TestRm(script.TestCaseWithTransportAndScript):
469
def test_rm_usage(self):
470
self.assertRaises(SyntaxError, self.run_script, '$ rm')
471
self.assertRaises(SyntaxError, self.run_script, '$ rm -ff foo')
473
def test_rm_file(self):
474
self.run_script('$ echo content >file')
475
self.failUnlessExists('file')
476
self.run_script('$ rm file')
477
self.failIfExists('file')
479
def test_rm_file_force(self):
480
self.failIfExists('file')
481
self.run_script('$ rm -f file')
482
self.failIfExists('file')
484
def test_rm_files(self):
487
$ echo content >file2
489
self.failUnlessExists('file2')
490
self.run_script('$ rm file file2')
491
self.failIfExists('file2')
493
def test_rm_dir(self):
494
self.run_script('$ mkdir dir')
495
self.failUnlessExists('dir')
498
2>rm: cannot remove 'dir': Is a directory
500
self.failUnlessExists('dir')
502
def test_rm_dir_recursive(self):
507
self.failIfExists('dir')
510
class TestMv(script.TestCaseWithTransportAndScript):
512
def test_usage(self):
513
self.assertRaises(SyntaxError, self.run_script, '$ mv')
514
self.assertRaises(SyntaxError, self.run_script, '$ mv f')
515
self.assertRaises(SyntaxError, self.run_script, '$ mv f1 f2 f3')
517
def test_move_file(self):
518
self.run_script('$ echo content >file')
519
self.failUnlessExists('file')
520
self.run_script('$ mv file new_name')
521
self.failIfExists('file')
522
self.failUnlessExists('new_name')
524
def test_move_unknown_file(self):
525
self.assertRaises(AssertionError,
526
self.run_script, '$ mv unknown does-not-exist')
528
def test_move_dir(self):
531
$ echo content >dir/file
533
self.run_script('$ mv dir new_name')
534
self.failIfExists('dir')
535
self.failUnlessExists('new_name')
536
self.failUnlessExists('new_name/file')
538
def test_move_file_into_dir(self):
541
$ echo content > file
543
self.run_script('$ mv file dir')
544
self.failUnlessExists('dir')
545
self.failIfExists('file')
546
self.failUnlessExists('dir/file')
549
class cmd_test_confirm(commands.Command):
552
if ui.ui_factory.get_boolean(
554
# 'bzrlib.tests.test_script.confirm',
557
self.outf.write('Do it!\n')
562
class TestUserInteraction(script.TestCaseWithMemoryTransportAndScript):
564
def test_confirm_action(self):
565
"""You can write tests that demonstrate user confirmation.
567
Specifically, ScriptRunner does't care if the output line for the prompt
568
isn't terminated by a newline from the program; it's implicitly terminated
571
commands.builtin_command_registry.register(cmd_test_confirm)
572
self.addCleanup(commands.builtin_command_registry.remove, 'test-confirm')
575
2>Really do it? [y/n]:
579
2>Really do it? [y/n]: