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_trim_blank_lines(self):
33
"""Blank lines are respected, but trimmed at the start and end.
35
Python triple-quoted syntax is going to give stubby/empty blank lines
36
right at the start and the end. These are cut off so that callers don't
37
need special syntax to avoid them.
39
However we do want to be able to match commands that emit blank lines.
42
(['bar'], None, '\n', None),
44
script._script_to_commands("""
49
def test_simple_command(self):
50
self.assertEquals([(['cd', 'trunk'], None, None, None)],
51
script._script_to_commands('$ cd trunk'))
53
def test_command_with_single_quoted_param(self):
54
story = """$ bzr commit -m 'two words'"""
55
self.assertEquals([(['bzr', 'commit', '-m', "'two words'"],
57
script._script_to_commands(story))
59
def test_command_with_double_quoted_param(self):
60
story = """$ bzr commit -m "two words" """
61
self.assertEquals([(['bzr', 'commit', '-m', '"two words"'],
63
script._script_to_commands(story))
65
def test_command_with_input(self):
67
[(['cat', '>file'], 'content\n', None, None)],
68
script._script_to_commands('$ cat >file\n<content\n'))
70
def test_indented(self):
71
# scripts are commonly given indented within the test source code, and
72
# common indentation is stripped off
78
self.assertEquals([(['bzr', 'add'], None,
79
'adding file\nadding file2\n', None)],
80
script._script_to_commands(story))
82
def test_command_with_output(self):
88
self.assertEquals([(['bzr', 'add'], None,
89
'adding file\nadding file2\n', None)],
90
script._script_to_commands(story))
92
def test_command_with_error(self):
95
2>bzr: ERROR: Not a branch: "foo"
97
self.assertEquals([(['bzr', 'branch', 'foo'],
98
None, None, 'bzr: ERROR: Not a branch: "foo"\n')],
99
script._script_to_commands(story))
101
def test_input_without_command(self):
102
self.assertRaises(SyntaxError, script._script_to_commands, '<input')
104
def test_output_without_command(self):
105
self.assertRaises(SyntaxError, script._script_to_commands, '>input')
107
def test_command_with_backquotes(self):
109
$ foo = `bzr file-id toto`
111
self.assertEquals([(['foo', '=', '`bzr file-id toto`'],
113
script._script_to_commands(story))
116
class TestRedirections(tests.TestCase):
118
def _check(self, in_name, out_name, out_mode, remaining, args):
119
self.assertEqual(script._scan_redirection_options(args),
120
(in_name, out_name, out_mode, remaining))
122
def test_no_redirection(self):
123
self._check(None, None, None, [], [])
124
self._check(None, None, None, ['foo', 'bar'], ['foo', 'bar'])
126
def test_input_redirection(self):
127
self._check('foo', None, None, [], ['<foo'])
128
self._check('foo', None, None, ['bar'], ['bar', '<foo'])
129
self._check('foo', None, None, ['bar'], ['bar', '<', 'foo'])
130
self._check('foo', None, None, ['bar'], ['<foo', 'bar'])
131
self._check('foo', None, None, ['bar', 'baz'], ['bar', '<foo', 'baz'])
133
def test_output_redirection(self):
134
self._check(None, 'foo', 'wb+', [], ['>foo'])
135
self._check(None, 'foo', 'wb+', ['bar'], ['bar', '>foo'])
136
self._check(None, 'foo', 'wb+', ['bar'], ['bar', '>', 'foo'])
137
self._check(None, 'foo', 'ab+', [], ['>>foo'])
138
self._check(None, 'foo', 'ab+', ['bar'], ['bar', '>>foo'])
139
self._check(None, 'foo', 'ab+', ['bar'], ['bar', '>>', 'foo'])
141
def test_redirection_syntax_errors(self):
142
self._check('', None, None, [], ['<'])
143
self._check(None, '', 'wb+', [], ['>'])
144
self._check(None, '', 'ab+', [], ['>>'])
145
self._check('>', '', 'ab+', [], ['<', '>', '>>'])
149
class TestExecution(script.TestCaseWithTransportAndScript):
151
def test_unknown_command(self):
152
self.assertRaises(SyntaxError, self.run_script, 'foo')
154
def test_stops_on_unexpected_output(self):
158
The cd command ouputs nothing
160
self.assertRaises(AssertionError, self.run_script, story)
163
def test_stops_on_unexpected_error(self):
169
self.assertRaises(AssertionError, self.run_script, story)
171
def test_continue_on_expected_error(self):
176
self.run_script(story)
178
def test_continue_on_error_output(self):
179
# The status matters, not the output
185
$ bzr commit -m 'adding file'
187
self.run_script(story)
189
def test_ellipsis_output(self):
199
self.run_script(story)
204
self.run_script(story)
207
$ bzr branch not-a-branch
208
2>bzr: ERROR: Not a branch...not-a-branch/".
210
self.run_script(story)
213
class TestArgumentProcessing(script.TestCaseWithTransportAndScript):
215
def test_globing(self):
224
def test_quoted_globbing(self):
228
2>*: No such file or directory
231
def test_quotes_removal(self):
233
$ echo 'cat' "dog" '"chicken"' "'dragon'"
234
cat dog "chicken" 'dragon'
238
class TestCat(script.TestCaseWithTransportAndScript):
240
def test_cat_usage(self):
241
self.assertRaises(SyntaxError, self.run_script, 'cat foo <bar')
243
def test_cat_input_to_output(self):
244
retcode, out, err = self.run_command(['cat'],
245
'content\n', 'content\n', None)
246
self.assertEquals('content\n', out)
247
self.assertEquals(None, err)
249
def test_cat_file_to_output(self):
250
self.build_tree_contents([('file', 'content\n')])
251
retcode, out, err = self.run_command(['cat', 'file'],
252
None, 'content\n', None)
253
self.assertEquals('content\n', out)
254
self.assertEquals(None, err)
256
def test_cat_input_to_file(self):
257
retcode, out, err = self.run_command(['cat', '>file'],
258
'content\n', None, None)
259
self.assertFileEqual('content\n', 'file')
260
self.assertEquals(None, out)
261
self.assertEquals(None, err)
262
retcode, out, err = self.run_command(['cat', '>>file'],
263
'more\n', None, None)
264
self.assertFileEqual('content\nmore\n', 'file')
265
self.assertEquals(None, out)
266
self.assertEquals(None, err)
268
def test_cat_file_to_file(self):
269
self.build_tree_contents([('file', 'content\n')])
270
retcode, out, err = self.run_command(['cat', 'file', '>file2'],
272
self.assertFileEqual('content\n', 'file2')
274
def test_cat_files_to_file(self):
275
self.build_tree_contents([('cat', 'cat\n')])
276
self.build_tree_contents([('dog', 'dog\n')])
277
retcode, out, err = self.run_command(['cat', 'cat', 'dog', '>file'],
279
self.assertFileEqual('cat\ndog\n', 'file')
281
def test_cat_bogus_input_file(self):
284
2>file: No such file or directory
287
def test_cat_bogus_output_file(self):
290
2>: No such file or directory
293
def test_echo_bogus_output_file(self):
294
# We need a backing file sysytem for that test so it can't be in
298
2>: No such file or directory
302
class TestMkdir(script.TestCaseWithTransportAndScript):
304
def test_mkdir_usage(self):
305
self.assertRaises(SyntaxError, self.run_script, '$ mkdir')
306
self.assertRaises(SyntaxError, self.run_script, '$ mkdir foo bar')
308
def test_mkdir_jailed(self):
309
self.assertRaises(ValueError, self.run_script, '$ mkdir /out-of-jail')
310
self.assertRaises(ValueError, self.run_script, '$ mkdir ../out-of-jail')
312
def test_mkdir_in_jail(self):
319
self.failUnlessExists('dir')
320
self.failUnlessExists('dir2')
323
class TestCd(script.TestCaseWithTransportAndScript):
325
def test_cd_usage(self):
326
self.assertRaises(SyntaxError, self.run_script, '$ cd foo bar')
328
def test_cd_out_of_jail(self):
329
self.assertRaises(ValueError, self.run_script, '$ cd /out-of-jail')
330
self.assertRaises(ValueError, self.run_script, '$ cd ..')
332
def test_cd_dir_and_back_home(self):
333
self.assertEquals(self.test_dir, osutils.getcwd())
338
self.assertEquals(osutils.pathjoin(self.test_dir, 'dir'),
341
self.run_script('$ cd')
342
self.assertEquals(self.test_dir, osutils.getcwd())
345
class TestBzr(script.TestCaseWithTransportAndScript):
347
def test_bzr_smoke(self):
348
self.run_script('$ bzr init branch')
349
self.failUnlessExists('branch')
352
class TestEcho(script.TestCaseWithMemoryTransportAndScript):
354
def test_echo_usage(self):
359
self.assertRaises(SyntaxError, self.run_script, story)
361
def test_echo_input(self):
362
self.assertRaises(SyntaxError, self.run_script, """
366
def test_echo_to_output(self):
367
retcode, out, err = self.run_command(['echo'], None, '\n', None)
368
self.assertEquals('\n', out)
369
self.assertEquals(None, err)
371
def test_echo_some_to_output(self):
372
retcode, out, err = self.run_command(['echo', 'hello'],
373
None, 'hello\n', None)
374
self.assertEquals('hello\n', out)
375
self.assertEquals(None, err)
377
def test_echo_more_output(self):
378
retcode, out, err = self.run_command(
379
['echo', 'hello', 'happy', 'world'],
380
None, 'hello happy world\n', None)
381
self.assertEquals('hello happy world\n', out)
382
self.assertEquals(None, err)
384
def test_echo_appended(self):
385
retcode, out, err = self.run_command(['echo', 'hello', '>file'],
387
self.assertEquals(None, out)
388
self.assertEquals(None, err)
389
self.assertFileEqual('hello\n', 'file')
390
retcode, out, err = self.run_command(['echo', 'happy', '>>file'],
392
self.assertEquals(None, out)
393
self.assertEquals(None, err)
394
self.assertFileEqual('hello\nhappy\n', 'file')
396
def test_empty_line_in_output_is_respected(self):
405
class TestRm(script.TestCaseWithTransportAndScript):
407
def test_rm_usage(self):
408
self.assertRaises(SyntaxError, self.run_script, '$ rm')
409
self.assertRaises(SyntaxError, self.run_script, '$ rm -ff foo')
411
def test_rm_file(self):
412
self.run_script('$ echo content >file')
413
self.failUnlessExists('file')
414
self.run_script('$ rm file')
415
self.failIfExists('file')
417
def test_rm_file_force(self):
418
self.failIfExists('file')
419
self.run_script('$ rm -f file')
420
self.failIfExists('file')
422
def test_rm_files(self):
425
$ echo content >file2
427
self.failUnlessExists('file2')
428
self.run_script('$ rm file file2')
429
self.failIfExists('file2')
431
def test_rm_dir(self):
432
self.run_script('$ mkdir dir')
433
self.failUnlessExists('dir')
436
2>rm: cannot remove 'dir': Is a directory
438
self.failUnlessExists('dir')
440
def test_rm_dir_recursive(self):
445
self.failIfExists('dir')
448
class TestMv(script.TestCaseWithTransportAndScript):
450
def test_usage(self):
451
self.assertRaises(SyntaxError, self.run_script, '$ mv')
452
self.assertRaises(SyntaxError, self.run_script, '$ mv f')
453
self.assertRaises(SyntaxError, self.run_script, '$ mv f1 f2 f3')
455
def test_move_file(self):
456
self.run_script('$ echo content >file')
457
self.failUnlessExists('file')
458
self.run_script('$ mv file new_name')
459
self.failIfExists('file')
460
self.failUnlessExists('new_name')
462
def test_move_unknown_file(self):
463
self.assertRaises(AssertionError,
464
self.run_script, '$ mv unknown does-not-exist')
466
def test_move_dir(self):
469
$ echo content >dir/file
471
self.run_script('$ mv dir new_name')
472
self.failIfExists('dir')
473
self.failUnlessExists('new_name')
474
self.failUnlessExists('new_name/file')
476
def test_move_file_into_dir(self):
479
$ echo content > file
481
self.run_script('$ mv file dir')
482
self.failUnlessExists('dir')
483
self.failIfExists('file')
484
self.failUnlessExists('dir/file')
487
class cmd_test_confirm(commands.Command):
490
if ui.ui_factory.get_boolean(
492
# 'bzrlib.tests.test_script.confirm',
495
self.outf.write('Do it!\n')
500
class TestUserInteraction(script.TestCaseWithMemoryTransportAndScript):
502
def test_confirm_action(self):
503
"""You can write tests that demonstrate user confirmation.
505
Specifically, ScriptRunner does't care if the output line for the prompt
506
isn't terminated by a newline from the program; it's implicitly terminated
509
commands.builtin_command_registry.register(cmd_test_confirm)
510
self.addCleanup(commands.builtin_command_registry.remove, 'test-confirm')
513
2>Really do it? [y/n]:
517
2>Really do it? [y/n]: