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
24
from bzrlib.tests import script
27
class TestSyntax(tests.TestCase):
29
def test_comment_is_ignored(self):
30
self.assertEquals([], script._script_to_commands('#comment\n'))
32
def test_comment_multiple_lines(self):
34
(['bar'], None, None, None),
36
script._script_to_commands("""
37
# this comment is ignored
43
def test_trim_blank_lines(self):
44
"""Blank lines are respected, but trimmed at the start and end.
46
Python triple-quoted syntax is going to give stubby/empty blank lines
47
right at the start and the end. These are cut off so that callers don't
48
need special syntax to avoid them.
50
However we do want to be able to match commands that emit blank lines.
53
(['bar'], None, '\n', None),
55
script._script_to_commands("""
60
def test_simple_command(self):
61
self.assertEquals([(['cd', 'trunk'], None, None, None)],
62
script._script_to_commands('$ cd trunk'))
64
def test_command_with_single_quoted_param(self):
65
story = """$ bzr commit -m 'two words'"""
66
self.assertEquals([(['bzr', 'commit', '-m', "'two words'"],
68
script._script_to_commands(story))
70
def test_command_with_double_quoted_param(self):
71
story = """$ bzr commit -m "two words" """
72
self.assertEquals([(['bzr', 'commit', '-m', '"two words"'],
74
script._script_to_commands(story))
76
def test_command_with_input(self):
78
[(['cat', '>file'], 'content\n', None, None)],
79
script._script_to_commands('$ cat >file\n<content\n'))
81
def test_indented(self):
82
# scripts are commonly given indented within the test source code, and
83
# common indentation is stripped off
89
self.assertEquals([(['bzr', 'add'], None,
90
'adding file\nadding file2\n', None)],
91
script._script_to_commands(story))
93
def test_command_with_output(self):
99
self.assertEquals([(['bzr', 'add'], None,
100
'adding file\nadding file2\n', None)],
101
script._script_to_commands(story))
103
def test_command_with_error(self):
106
2>bzr: ERROR: Not a branch: "foo"
108
self.assertEquals([(['bzr', 'branch', 'foo'],
109
None, None, 'bzr: ERROR: Not a branch: "foo"\n')],
110
script._script_to_commands(story))
112
def test_input_without_command(self):
113
self.assertRaises(SyntaxError, script._script_to_commands, '<input')
115
def test_output_without_command(self):
116
self.assertRaises(SyntaxError, script._script_to_commands, '>input')
118
def test_command_with_backquotes(self):
120
$ foo = `bzr file-id toto`
122
self.assertEquals([(['foo', '=', '`bzr file-id toto`'],
124
script._script_to_commands(story))
127
class TestRedirections(tests.TestCase):
129
def _check(self, in_name, out_name, out_mode, remaining, args):
130
self.assertEqual(script._scan_redirection_options(args),
131
(in_name, out_name, out_mode, remaining))
133
def test_no_redirection(self):
134
self._check(None, None, None, [], [])
135
self._check(None, None, None, ['foo', 'bar'], ['foo', 'bar'])
137
def test_input_redirection(self):
138
self._check('foo', None, None, [], ['<foo'])
139
self._check('foo', None, None, ['bar'], ['bar', '<foo'])
140
self._check('foo', None, None, ['bar'], ['bar', '<', 'foo'])
141
self._check('foo', None, None, ['bar'], ['<foo', 'bar'])
142
self._check('foo', None, None, ['bar', 'baz'], ['bar', '<foo', 'baz'])
144
def test_output_redirection(self):
145
self._check(None, 'foo', 'wb+', [], ['>foo'])
146
self._check(None, 'foo', 'wb+', ['bar'], ['bar', '>foo'])
147
self._check(None, 'foo', 'wb+', ['bar'], ['bar', '>', 'foo'])
148
self._check(None, 'foo', 'ab+', [], ['>>foo'])
149
self._check(None, 'foo', 'ab+', ['bar'], ['bar', '>>foo'])
150
self._check(None, 'foo', 'ab+', ['bar'], ['bar', '>>', 'foo'])
152
def test_redirection_syntax_errors(self):
153
self._check('', None, None, [], ['<'])
154
self._check(None, '', 'wb+', [], ['>'])
155
self._check(None, '', 'ab+', [], ['>>'])
156
self._check('>', '', 'ab+', [], ['<', '>', '>>'])
160
class TestExecution(script.TestCaseWithTransportAndScript):
162
def test_unknown_command(self):
163
self.assertRaises(SyntaxError, self.run_script, 'foo')
165
def test_stops_on_unexpected_output(self):
169
The cd command ouputs nothing
171
self.assertRaises(AssertionError, self.run_script, story)
174
def test_stops_on_unexpected_error(self):
180
self.assertRaises(AssertionError, self.run_script, story)
182
def test_continue_on_expected_error(self):
187
self.run_script(story)
189
def test_continue_on_error_output(self):
190
# The status matters, not the output
196
$ bzr commit -m 'adding file'
198
self.run_script(story)
200
def test_ellipsis_output(self):
210
self.run_script(story)
215
self.run_script(story)
218
$ bzr branch not-a-branch
219
2>bzr: ERROR: Not a branch...not-a-branch/".
221
self.run_script(story)
224
class TestArgumentProcessing(script.TestCaseWithTransportAndScript):
226
def test_globing(self):
235
def test_quoted_globbing(self):
239
2>*: No such file or directory
242
def test_quotes_removal(self):
244
$ echo 'cat' "dog" '"chicken"' "'dragon'"
245
cat dog "chicken" 'dragon'
249
class TestCat(script.TestCaseWithTransportAndScript):
251
def test_cat_usage(self):
252
self.assertRaises(SyntaxError, self.run_script, 'cat foo <bar')
254
def test_cat_input_to_output(self):
255
retcode, out, err = self.run_command(['cat'],
256
'content\n', 'content\n', None)
257
self.assertEquals('content\n', out)
258
self.assertEquals(None, err)
260
def test_cat_file_to_output(self):
261
self.build_tree_contents([('file', 'content\n')])
262
retcode, out, err = self.run_command(['cat', 'file'],
263
None, 'content\n', None)
264
self.assertEquals('content\n', out)
265
self.assertEquals(None, err)
267
def test_cat_input_to_file(self):
268
retcode, out, err = self.run_command(['cat', '>file'],
269
'content\n', None, None)
270
self.assertFileEqual('content\n', 'file')
271
self.assertEquals(None, out)
272
self.assertEquals(None, err)
273
retcode, out, err = self.run_command(['cat', '>>file'],
274
'more\n', None, None)
275
self.assertFileEqual('content\nmore\n', 'file')
276
self.assertEquals(None, out)
277
self.assertEquals(None, err)
279
def test_cat_file_to_file(self):
280
self.build_tree_contents([('file', 'content\n')])
281
retcode, out, err = self.run_command(['cat', 'file', '>file2'],
283
self.assertFileEqual('content\n', 'file2')
285
def test_cat_files_to_file(self):
286
self.build_tree_contents([('cat', 'cat\n')])
287
self.build_tree_contents([('dog', 'dog\n')])
288
retcode, out, err = self.run_command(['cat', 'cat', 'dog', '>file'],
290
self.assertFileEqual('cat\ndog\n', 'file')
292
def test_cat_bogus_input_file(self):
295
2>file: No such file or directory
298
def test_cat_bogus_output_file(self):
301
2>: No such file or directory
304
def test_echo_bogus_output_file(self):
305
# We need a backing file sysytem for that test so it can't be in
309
2>: No such file or directory
313
class TestMkdir(script.TestCaseWithTransportAndScript):
315
def test_mkdir_usage(self):
316
self.assertRaises(SyntaxError, self.run_script, '$ mkdir')
317
self.assertRaises(SyntaxError, self.run_script, '$ mkdir foo bar')
319
def test_mkdir_jailed(self):
320
self.assertRaises(ValueError, self.run_script, '$ mkdir /out-of-jail')
321
self.assertRaises(ValueError, self.run_script, '$ mkdir ../out-of-jail')
323
def test_mkdir_in_jail(self):
330
self.failUnlessExists('dir')
331
self.failUnlessExists('dir2')
334
class TestCd(script.TestCaseWithTransportAndScript):
336
def test_cd_usage(self):
337
self.assertRaises(SyntaxError, self.run_script, '$ cd foo bar')
339
def test_cd_out_of_jail(self):
340
self.assertRaises(ValueError, self.run_script, '$ cd /out-of-jail')
341
self.assertRaises(ValueError, self.run_script, '$ cd ..')
343
def test_cd_dir_and_back_home(self):
344
self.assertEquals(self.test_dir, osutils.getcwd())
349
self.assertEquals(osutils.pathjoin(self.test_dir, 'dir'),
352
self.run_script('$ cd')
353
self.assertEquals(self.test_dir, osutils.getcwd())
356
class TestBzr(script.TestCaseWithTransportAndScript):
358
def test_bzr_smoke(self):
359
self.run_script('$ bzr init branch')
360
self.failUnlessExists('branch')
363
class TestEcho(script.TestCaseWithMemoryTransportAndScript):
365
def test_echo_usage(self):
370
self.assertRaises(SyntaxError, self.run_script, story)
372
def test_echo_input(self):
373
self.assertRaises(SyntaxError, self.run_script, """
377
def test_echo_to_output(self):
378
retcode, out, err = self.run_command(['echo'], None, '\n', None)
379
self.assertEquals('\n', out)
380
self.assertEquals(None, err)
382
def test_echo_some_to_output(self):
383
retcode, out, err = self.run_command(['echo', 'hello'],
384
None, 'hello\n', None)
385
self.assertEquals('hello\n', out)
386
self.assertEquals(None, err)
388
def test_echo_more_output(self):
389
retcode, out, err = self.run_command(
390
['echo', 'hello', 'happy', 'world'],
391
None, 'hello happy world\n', None)
392
self.assertEquals('hello happy world\n', out)
393
self.assertEquals(None, err)
395
def test_echo_appended(self):
396
retcode, out, err = self.run_command(['echo', 'hello', '>file'],
398
self.assertEquals(None, out)
399
self.assertEquals(None, err)
400
self.assertFileEqual('hello\n', 'file')
401
retcode, out, err = self.run_command(['echo', 'happy', '>>file'],
403
self.assertEquals(None, out)
404
self.assertEquals(None, err)
405
self.assertFileEqual('hello\nhappy\n', 'file')
407
def test_empty_line_in_output_is_respected(self):
416
class TestRm(script.TestCaseWithTransportAndScript):
418
def test_rm_usage(self):
419
self.assertRaises(SyntaxError, self.run_script, '$ rm')
420
self.assertRaises(SyntaxError, self.run_script, '$ rm -ff foo')
422
def test_rm_file(self):
423
self.run_script('$ echo content >file')
424
self.failUnlessExists('file')
425
self.run_script('$ rm file')
426
self.failIfExists('file')
428
def test_rm_file_force(self):
429
self.failIfExists('file')
430
self.run_script('$ rm -f file')
431
self.failIfExists('file')
433
def test_rm_files(self):
436
$ echo content >file2
438
self.failUnlessExists('file2')
439
self.run_script('$ rm file file2')
440
self.failIfExists('file2')
442
def test_rm_dir(self):
443
self.run_script('$ mkdir dir')
444
self.failUnlessExists('dir')
447
2>rm: cannot remove 'dir': Is a directory
449
self.failUnlessExists('dir')
451
def test_rm_dir_recursive(self):
456
self.failIfExists('dir')
459
class TestMv(script.TestCaseWithTransportAndScript):
461
def test_usage(self):
462
self.assertRaises(SyntaxError, self.run_script, '$ mv')
463
self.assertRaises(SyntaxError, self.run_script, '$ mv f')
464
self.assertRaises(SyntaxError, self.run_script, '$ mv f1 f2 f3')
466
def test_move_file(self):
467
self.run_script('$ echo content >file')
468
self.failUnlessExists('file')
469
self.run_script('$ mv file new_name')
470
self.failIfExists('file')
471
self.failUnlessExists('new_name')
473
def test_move_unknown_file(self):
474
self.assertRaises(AssertionError,
475
self.run_script, '$ mv unknown does-not-exist')
477
def test_move_dir(self):
480
$ echo content >dir/file
482
self.run_script('$ mv dir new_name')
483
self.failIfExists('dir')
484
self.failUnlessExists('new_name')
485
self.failUnlessExists('new_name/file')
487
def test_move_file_into_dir(self):
490
$ echo content > file
492
self.run_script('$ mv file dir')
493
self.failUnlessExists('dir')
494
self.failIfExists('file')
495
self.failUnlessExists('dir/file')
498
class cmd_test_confirm(commands.Command):
501
if ui.ui_factory.get_boolean(
503
# 'bzrlib.tests.test_script.confirm',
506
self.outf.write('Do it!\n')
511
class TestUserInteraction(script.TestCaseWithMemoryTransportAndScript):
513
def test_confirm_action(self):
514
"""You can write tests that demonstrate user confirmation.
516
Specifically, ScriptRunner does't care if the output line for the prompt
517
isn't terminated by a newline from the program; it's implicitly terminated
520
commands.builtin_command_registry.register(cmd_test_confirm)
521
self.addCleanup(commands.builtin_command_registry.remove, 'test-confirm')
524
2>Really do it? [y/n]:
528
2>Really do it? [y/n]: