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
self.assertRaises(SyntaxError, self.run_script, 'foo')
166
def test_blank_output_mismatches_output(self):
167
"""If you give output, the output must actually be blank.
169
See <https://bugs.launchpad.net/bzr/+bug/637830>: previously blank
170
output was a wildcard. Now you must say ... if you want that.
172
self.assertRaises(AssertionError,
178
def test_ellipsis_everything(self):
179
"""A simple ellipsis matches everything."""
185
def test_ellipsis_matches_empty(self):
191
def test_stops_on_unexpected_output(self):
195
The cd command ouputs nothing
197
self.assertRaises(AssertionError, self.run_script, story)
199
def test_stops_on_unexpected_error(self):
205
self.assertRaises(AssertionError, self.run_script, story)
207
def test_continue_on_expected_error(self):
212
self.run_script(story)
214
def test_continue_on_error_output(self):
215
# The status matters, not the output
223
$ bzr commit -m 'adding file'
226
self.run_script(story)
228
def test_ellipsis_output(self):
238
self.run_script(story)
243
self.run_script(story)
246
$ bzr branch not-a-branch
247
2>bzr: ERROR: Not a branch...not-a-branch/".
249
self.run_script(story)
252
class TestArgumentProcessing(script.TestCaseWithTransportAndScript):
254
def test_globing(self):
263
def test_quoted_globbing(self):
267
2>*: No such file or directory
270
def test_quotes_removal(self):
272
$ echo 'cat' "dog" '"chicken"' "'dragon'"
273
cat dog "chicken" 'dragon'
276
def test_verbosity_isolated(self):
277
"""Global verbosity is isolated from commands run in scripts.
279
# see also 656694; we should get rid of global verbosity
283
self.assertEquals(trace.is_quiet(), False)
286
class TestCat(script.TestCaseWithTransportAndScript):
288
def test_cat_usage(self):
289
self.assertRaises(SyntaxError, self.run_script, 'cat foo <bar')
291
def test_cat_input_to_output(self):
292
retcode, out, err = self.run_command(['cat'],
293
'content\n', 'content\n', None)
294
self.assertEquals('content\n', out)
295
self.assertEquals(None, err)
297
def test_cat_file_to_output(self):
298
self.build_tree_contents([('file', 'content\n')])
299
retcode, out, err = self.run_command(['cat', 'file'],
300
None, 'content\n', None)
301
self.assertEquals('content\n', out)
302
self.assertEquals(None, err)
304
def test_cat_input_to_file(self):
305
retcode, out, err = self.run_command(['cat', '>file'],
306
'content\n', None, None)
307
self.assertFileEqual('content\n', 'file')
308
self.assertEquals(None, out)
309
self.assertEquals(None, err)
310
retcode, out, err = self.run_command(['cat', '>>file'],
311
'more\n', None, None)
312
self.assertFileEqual('content\nmore\n', 'file')
313
self.assertEquals(None, out)
314
self.assertEquals(None, err)
316
def test_cat_file_to_file(self):
317
self.build_tree_contents([('file', 'content\n')])
318
retcode, out, err = self.run_command(['cat', 'file', '>file2'],
320
self.assertFileEqual('content\n', 'file2')
322
def test_cat_files_to_file(self):
323
self.build_tree_contents([('cat', 'cat\n')])
324
self.build_tree_contents([('dog', 'dog\n')])
325
retcode, out, err = self.run_command(['cat', 'cat', 'dog', '>file'],
327
self.assertFileEqual('cat\ndog\n', 'file')
329
def test_cat_bogus_input_file(self):
332
2>file: No such file or directory
335
def test_cat_bogus_output_file(self):
338
2>: No such file or directory
341
def test_echo_bogus_output_file(self):
342
# We need a backing file sysytem for that test so it can't be in
346
2>: No such file or directory
350
class TestMkdir(script.TestCaseWithTransportAndScript):
352
def test_mkdir_usage(self):
353
self.assertRaises(SyntaxError, self.run_script, '$ mkdir')
354
self.assertRaises(SyntaxError, self.run_script, '$ mkdir foo bar')
356
def test_mkdir_jailed(self):
357
self.assertRaises(ValueError, self.run_script, '$ mkdir /out-of-jail')
358
self.assertRaises(ValueError, self.run_script, '$ mkdir ../out-of-jail')
360
def test_mkdir_in_jail(self):
367
self.failUnlessExists('dir')
368
self.failUnlessExists('dir2')
371
class TestCd(script.TestCaseWithTransportAndScript):
373
def test_cd_usage(self):
374
self.assertRaises(SyntaxError, self.run_script, '$ cd foo bar')
376
def test_cd_out_of_jail(self):
377
self.assertRaises(ValueError, self.run_script, '$ cd /out-of-jail')
378
self.assertRaises(ValueError, self.run_script, '$ cd ..')
380
def test_cd_dir_and_back_home(self):
381
self.assertEquals(self.test_dir, osutils.getcwd())
386
self.assertEquals(osutils.pathjoin(self.test_dir, 'dir'),
389
self.run_script('$ cd')
390
self.assertEquals(self.test_dir, osutils.getcwd())
393
class TestBzr(script.TestCaseWithTransportAndScript):
395
def test_bzr_smoke(self):
398
Created a standalone tree (format: ...)
400
self.failUnlessExists('branch')
403
class TestEcho(script.TestCaseWithMemoryTransportAndScript):
405
def test_echo_usage(self):
410
self.assertRaises(SyntaxError, self.run_script, story)
412
def test_echo_input(self):
413
self.assertRaises(SyntaxError, self.run_script, """
417
def test_echo_to_output(self):
418
retcode, out, err = self.run_command(['echo'], None, '\n', None)
419
self.assertEquals('\n', out)
420
self.assertEquals(None, err)
422
def test_echo_some_to_output(self):
423
retcode, out, err = self.run_command(['echo', 'hello'],
424
None, 'hello\n', None)
425
self.assertEquals('hello\n', out)
426
self.assertEquals(None, err)
428
def test_echo_more_output(self):
429
retcode, out, err = self.run_command(
430
['echo', 'hello', 'happy', 'world'],
431
None, 'hello happy world\n', None)
432
self.assertEquals('hello happy world\n', out)
433
self.assertEquals(None, err)
435
def test_echo_appended(self):
436
retcode, out, err = self.run_command(['echo', 'hello', '>file'],
438
self.assertEquals(None, out)
439
self.assertEquals(None, err)
440
self.assertFileEqual('hello\n', 'file')
441
retcode, out, err = self.run_command(['echo', 'happy', '>>file'],
443
self.assertEquals(None, out)
444
self.assertEquals(None, err)
445
self.assertFileEqual('hello\nhappy\n', 'file')
447
def test_empty_line_in_output_is_respected(self):
456
class TestRm(script.TestCaseWithTransportAndScript):
458
def test_rm_usage(self):
459
self.assertRaises(SyntaxError, self.run_script, '$ rm')
460
self.assertRaises(SyntaxError, self.run_script, '$ rm -ff foo')
462
def test_rm_file(self):
463
self.run_script('$ echo content >file')
464
self.failUnlessExists('file')
465
self.run_script('$ rm file')
466
self.failIfExists('file')
468
def test_rm_file_force(self):
469
self.failIfExists('file')
470
self.run_script('$ rm -f file')
471
self.failIfExists('file')
473
def test_rm_files(self):
476
$ echo content >file2
478
self.failUnlessExists('file2')
479
self.run_script('$ rm file file2')
480
self.failIfExists('file2')
482
def test_rm_dir(self):
483
self.run_script('$ mkdir dir')
484
self.failUnlessExists('dir')
487
2>rm: cannot remove 'dir': Is a directory
489
self.failUnlessExists('dir')
491
def test_rm_dir_recursive(self):
496
self.failIfExists('dir')
499
class TestMv(script.TestCaseWithTransportAndScript):
501
def test_usage(self):
502
self.assertRaises(SyntaxError, self.run_script, '$ mv')
503
self.assertRaises(SyntaxError, self.run_script, '$ mv f')
504
self.assertRaises(SyntaxError, self.run_script, '$ mv f1 f2 f3')
506
def test_move_file(self):
507
self.run_script('$ echo content >file')
508
self.failUnlessExists('file')
509
self.run_script('$ mv file new_name')
510
self.failIfExists('file')
511
self.failUnlessExists('new_name')
513
def test_move_unknown_file(self):
514
self.assertRaises(AssertionError,
515
self.run_script, '$ mv unknown does-not-exist')
517
def test_move_dir(self):
520
$ echo content >dir/file
522
self.run_script('$ mv dir new_name')
523
self.failIfExists('dir')
524
self.failUnlessExists('new_name')
525
self.failUnlessExists('new_name/file')
527
def test_move_file_into_dir(self):
530
$ echo content > file
532
self.run_script('$ mv file dir')
533
self.failUnlessExists('dir')
534
self.failIfExists('file')
535
self.failUnlessExists('dir/file')
538
class cmd_test_confirm(commands.Command):
541
if ui.ui_factory.get_boolean(
543
# 'bzrlib.tests.test_script.confirm',
546
self.outf.write('Do it!\n')
551
class TestUserInteraction(script.TestCaseWithMemoryTransportAndScript):
553
def test_confirm_action(self):
554
"""You can write tests that demonstrate user confirmation.
556
Specifically, ScriptRunner does't care if the output line for the prompt
557
isn't terminated by a newline from the program; it's implicitly terminated
560
commands.builtin_command_registry.register(cmd_test_confirm)
561
self.addCleanup(commands.builtin_command_registry.remove, 'test-confirm')
564
2>Really do it? [y/n]:
568
2>Really do it? [y/n]: