~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_script.py

  • Committer: Martin Pool
  • Date: 2010-09-14 06:46:18 UTC
  • mto: This revision was merged to the branch mainline in revision 5426.
  • Revision ID: mbp@sourcefrog.net-20100914064618-1b05bktzv3513mx0
Add ConfirmationUserInterfacePolicy that lets specific confirmations be configured off.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2009, 2010 Canonical Ltd
 
2
#
 
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.
 
7
#
 
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.
 
12
#
 
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
 
16
 
 
17
 
 
18
from bzrlib import (
 
19
    commands,
 
20
    osutils,
 
21
    tests,
 
22
    ui,
 
23
    )
 
24
from bzrlib.tests import script
 
25
 
 
26
 
 
27
class TestSyntax(tests.TestCase):
 
28
 
 
29
    def test_comment_is_ignored(self):
 
30
        self.assertEquals([], script._script_to_commands('#comment\n'))
 
31
 
 
32
    def test_trim_blank_lines(self):
 
33
        """Blank lines are respected, but trimmed at the start and end.
 
34
 
 
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.
 
38
 
 
39
        However we do want to be able to match commands that emit blank lines.
 
40
        """
 
41
        self.assertEquals([
 
42
            (['bar'], None, '\n', None),
 
43
            ],
 
44
            script._script_to_commands("""
 
45
            $bar
 
46
 
 
47
            """))
 
48
 
 
49
    def test_simple_command(self):
 
50
        self.assertEquals([(['cd', 'trunk'], None, None, None)],
 
51
                           script._script_to_commands('$ cd trunk'))
 
52
 
 
53
    def test_command_with_single_quoted_param(self):
 
54
        story = """$ bzr commit -m 'two words'"""
 
55
        self.assertEquals([(['bzr', 'commit', '-m', "'two words'"],
 
56
                            None, None, None)],
 
57
                           script._script_to_commands(story))
 
58
 
 
59
    def test_command_with_double_quoted_param(self):
 
60
        story = """$ bzr commit -m "two words" """
 
61
        self.assertEquals([(['bzr', 'commit', '-m', '"two words"'],
 
62
                            None, None, None)],
 
63
                           script._script_to_commands(story))
 
64
 
 
65
    def test_command_with_input(self):
 
66
        self.assertEquals(
 
67
            [(['cat', '>file'], 'content\n', None, None)],
 
68
            script._script_to_commands('$ cat >file\n<content\n'))
 
69
 
 
70
    def test_indented(self):
 
71
        # scripts are commonly given indented within the test source code, and
 
72
        # common indentation is stripped off
 
73
        story = """
 
74
            $ bzr add
 
75
            adding file
 
76
            adding file2
 
77
            """
 
78
        self.assertEquals([(['bzr', 'add'], None,
 
79
                            'adding file\nadding file2\n', None)],
 
80
                          script._script_to_commands(story))
 
81
 
 
82
    def test_command_with_output(self):
 
83
        story = """
 
84
$ bzr add
 
85
adding file
 
86
adding file2
 
87
"""
 
88
        self.assertEquals([(['bzr', 'add'], None,
 
89
                            'adding file\nadding file2\n', None)],
 
90
                          script._script_to_commands(story))
 
91
 
 
92
    def test_command_with_error(self):
 
93
        story = """
 
94
$ bzr branch foo
 
95
2>bzr: ERROR: Not a branch: "foo"
 
96
"""
 
97
        self.assertEquals([(['bzr', 'branch', 'foo'],
 
98
                            None, None, 'bzr: ERROR: Not a branch: "foo"\n')],
 
99
                          script._script_to_commands(story))
 
100
 
 
101
    def test_input_without_command(self):
 
102
        self.assertRaises(SyntaxError, script._script_to_commands, '<input')
 
103
 
 
104
    def test_output_without_command(self):
 
105
        self.assertRaises(SyntaxError, script._script_to_commands, '>input')
 
106
 
 
107
    def test_command_with_backquotes(self):
 
108
        story = """
 
109
$ foo = `bzr file-id toto`
 
110
"""
 
111
        self.assertEquals([(['foo', '=', '`bzr file-id toto`'],
 
112
                            None, None, None)],
 
113
                          script._script_to_commands(story))
 
114
 
 
115
 
 
116
class TestRedirections(tests.TestCase):
 
117
 
 
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))
 
121
 
 
122
    def test_no_redirection(self):
 
123
        self._check(None, None, None, [], [])
 
124
        self._check(None, None, None, ['foo', 'bar'], ['foo', 'bar'])
 
125
 
 
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'])
 
132
 
 
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'])
 
140
 
 
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+', [], ['<', '>', '>>'])
 
146
 
 
147
 
 
148
 
 
149
class TestExecution(script.TestCaseWithTransportAndScript):
 
150
 
 
151
    def test_unknown_command(self):
 
152
        self.assertRaises(SyntaxError, self.run_script, 'foo')
 
153
 
 
154
    def test_stops_on_unexpected_output(self):
 
155
        story = """
 
156
$ mkdir dir
 
157
$ cd dir
 
158
The cd command ouputs nothing
 
159
"""
 
160
        self.assertRaises(AssertionError, self.run_script, story)
 
161
 
 
162
 
 
163
    def test_stops_on_unexpected_error(self):
 
164
        story = """
 
165
$ cat
 
166
<Hello
 
167
$ bzr not-a-command
 
168
"""
 
169
        self.assertRaises(AssertionError, self.run_script, story)
 
170
 
 
171
    def test_continue_on_expected_error(self):
 
172
        story = """
 
173
$ bzr not-a-command
 
174
2>..."not-a-command"
 
175
"""
 
176
        self.run_script(story)
 
177
 
 
178
    def test_continue_on_error_output(self):
 
179
        # The status matters, not the output
 
180
        story = """
 
181
$ bzr init
 
182
$ cat >file
 
183
<Hello
 
184
$ bzr add file
 
185
$ bzr commit -m 'adding file'
 
186
"""
 
187
        self.run_script(story)
 
188
 
 
189
    def test_ellipsis_output(self):
 
190
        story = """
 
191
$ cat
 
192
<first line
 
193
<second line
 
194
<last line
 
195
first line
 
196
...
 
197
last line
 
198
"""
 
199
        self.run_script(story)
 
200
        story = """
 
201
$ bzr not-a-command
 
202
2>..."not-a-command"
 
203
"""
 
204
        self.run_script(story)
 
205
 
 
206
        story = """
 
207
$ bzr branch not-a-branch
 
208
2>bzr: ERROR: Not a branch...not-a-branch/".
 
209
"""
 
210
        self.run_script(story)
 
211
 
 
212
 
 
213
class TestArgumentProcessing(script.TestCaseWithTransportAndScript):
 
214
 
 
215
    def test_globing(self):
 
216
        self.run_script("""
 
217
$ echo cat >cat
 
218
$ echo dog >dog
 
219
$ cat *
 
220
cat
 
221
dog
 
222
""")
 
223
 
 
224
    def test_quoted_globbing(self):
 
225
        self.run_script("""
 
226
$ echo cat >cat
 
227
$ cat '*'
 
228
2>*: No such file or directory
 
229
""")
 
230
 
 
231
    def test_quotes_removal(self):
 
232
        self.run_script("""
 
233
$ echo 'cat' "dog" '"chicken"' "'dragon'"
 
234
cat dog "chicken" 'dragon'
 
235
""")
 
236
 
 
237
 
 
238
class TestCat(script.TestCaseWithTransportAndScript):
 
239
 
 
240
    def test_cat_usage(self):
 
241
        self.assertRaises(SyntaxError, self.run_script, 'cat foo <bar')
 
242
 
 
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)
 
248
 
 
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)
 
255
 
 
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)
 
267
 
 
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'],
 
271
                                             None, None, None)
 
272
        self.assertFileEqual('content\n', 'file2')
 
273
 
 
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'],
 
278
                                             None, None, None)
 
279
        self.assertFileEqual('cat\ndog\n', 'file')
 
280
 
 
281
    def test_cat_bogus_input_file(self):
 
282
        self.run_script("""
 
283
$ cat <file
 
284
2>file: No such file or directory
 
285
""")
 
286
 
 
287
    def test_cat_bogus_output_file(self):
 
288
        self.run_script("""
 
289
$ cat >
 
290
2>: No such file or directory
 
291
""")
 
292
 
 
293
    def test_echo_bogus_output_file(self):
 
294
        # We need a backing file sysytem for that test so it can't be in
 
295
        # TestEcho
 
296
        self.run_script("""
 
297
$ echo >
 
298
2>: No such file or directory
 
299
""")
 
300
 
 
301
 
 
302
class TestMkdir(script.TestCaseWithTransportAndScript):
 
303
 
 
304
    def test_mkdir_usage(self):
 
305
        self.assertRaises(SyntaxError, self.run_script, '$ mkdir')
 
306
        self.assertRaises(SyntaxError, self.run_script, '$ mkdir foo bar')
 
307
 
 
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')
 
311
 
 
312
    def test_mkdir_in_jail(self):
 
313
        self.run_script("""
 
314
$ mkdir dir
 
315
$ cd dir
 
316
$ mkdir ../dir2
 
317
$ cd ..
 
318
""")
 
319
        self.failUnlessExists('dir')
 
320
        self.failUnlessExists('dir2')
 
321
 
 
322
 
 
323
class TestCd(script.TestCaseWithTransportAndScript):
 
324
 
 
325
    def test_cd_usage(self):
 
326
        self.assertRaises(SyntaxError, self.run_script, '$ cd foo bar')
 
327
 
 
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 ..')
 
331
 
 
332
    def test_cd_dir_and_back_home(self):
 
333
        self.assertEquals(self.test_dir, osutils.getcwd())
 
334
        self.run_script("""
 
335
$ mkdir dir
 
336
$ cd dir
 
337
""")
 
338
        self.assertEquals(osutils.pathjoin(self.test_dir, 'dir'),
 
339
                          osutils.getcwd())
 
340
 
 
341
        self.run_script('$ cd')
 
342
        self.assertEquals(self.test_dir, osutils.getcwd())
 
343
 
 
344
 
 
345
class TestBzr(script.TestCaseWithTransportAndScript):
 
346
 
 
347
    def test_bzr_smoke(self):
 
348
        self.run_script('$ bzr init branch')
 
349
        self.failUnlessExists('branch')
 
350
 
 
351
 
 
352
class TestEcho(script.TestCaseWithMemoryTransportAndScript):
 
353
 
 
354
    def test_echo_usage(self):
 
355
        story = """
 
356
$ echo foo
 
357
<bar
 
358
"""
 
359
        self.assertRaises(SyntaxError, self.run_script, story)
 
360
 
 
361
    def test_echo_input(self):
 
362
        self.assertRaises(SyntaxError, self.run_script, """
 
363
            $ echo <foo
 
364
            """)
 
365
 
 
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)
 
370
 
 
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)
 
376
 
 
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)
 
383
 
 
384
    def test_echo_appended(self):
 
385
        retcode, out, err = self.run_command(['echo', 'hello', '>file'],
 
386
                                             None, None, None)
 
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'],
 
391
                                             None, None, None)
 
392
        self.assertEquals(None, out)
 
393
        self.assertEquals(None, err)
 
394
        self.assertFileEqual('hello\nhappy\n', 'file')
 
395
 
 
396
    def test_empty_line_in_output_is_respected(self):
 
397
        self.run_script("""
 
398
            $ echo
 
399
 
 
400
            $ echo bar
 
401
            bar
 
402
            """)
 
403
 
 
404
 
 
405
class TestRm(script.TestCaseWithTransportAndScript):
 
406
 
 
407
    def test_rm_usage(self):
 
408
        self.assertRaises(SyntaxError, self.run_script, '$ rm')
 
409
        self.assertRaises(SyntaxError, self.run_script, '$ rm -ff foo')
 
410
 
 
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')
 
416
 
 
417
    def test_rm_file_force(self):
 
418
        self.failIfExists('file')
 
419
        self.run_script('$ rm -f file')
 
420
        self.failIfExists('file')
 
421
 
 
422
    def test_rm_files(self):
 
423
        self.run_script("""
 
424
$ echo content >file
 
425
$ echo content >file2
 
426
""")
 
427
        self.failUnlessExists('file2')
 
428
        self.run_script('$ rm file file2')
 
429
        self.failIfExists('file2')
 
430
 
 
431
    def test_rm_dir(self):
 
432
        self.run_script('$ mkdir dir')
 
433
        self.failUnlessExists('dir')
 
434
        self.run_script("""
 
435
$ rm dir
 
436
2>rm: cannot remove 'dir': Is a directory
 
437
""")
 
438
        self.failUnlessExists('dir')
 
439
 
 
440
    def test_rm_dir_recursive(self):
 
441
        self.run_script("""
 
442
$ mkdir dir
 
443
$ rm -r dir
 
444
""")
 
445
        self.failIfExists('dir')
 
446
 
 
447
 
 
448
class TestMv(script.TestCaseWithTransportAndScript):
 
449
 
 
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')
 
454
 
 
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')
 
461
 
 
462
    def test_move_unknown_file(self):
 
463
        self.assertRaises(AssertionError,
 
464
                          self.run_script, '$ mv unknown does-not-exist')
 
465
 
 
466
    def test_move_dir(self):
 
467
        self.run_script("""
 
468
$ mkdir dir
 
469
$ echo content >dir/file
 
470
""")
 
471
        self.run_script('$ mv dir new_name')
 
472
        self.failIfExists('dir')
 
473
        self.failUnlessExists('new_name')
 
474
        self.failUnlessExists('new_name/file')
 
475
 
 
476
    def test_move_file_into_dir(self):
 
477
        self.run_script("""
 
478
$ mkdir dir
 
479
$ echo content > file
 
480
""")
 
481
        self.run_script('$ mv file dir')
 
482
        self.failUnlessExists('dir')
 
483
        self.failIfExists('file')
 
484
        self.failUnlessExists('dir/file')
 
485
 
 
486
 
 
487
class cmd_test_confirm(commands.Command):
 
488
 
 
489
    def run(self):
 
490
        if ui.ui_factory.get_boolean(
 
491
            'Really do it',
 
492
            # 'bzrlib.tests.test_script.confirm',
 
493
            # {}
 
494
            ):
 
495
            self.outf.write('Do it!\n')
 
496
        else:
 
497
            print 'ok, no'
 
498
 
 
499
 
 
500
class TestUserInteraction(script.TestCaseWithMemoryTransportAndScript):
 
501
 
 
502
    def test_confirm_action(self):
 
503
        """You can write tests that demonstrate user confirmation.
 
504
        
 
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 
 
507
        by the input.
 
508
        """
 
509
        commands.builtin_command_registry.register(cmd_test_confirm)
 
510
        self.addCleanup(commands.builtin_command_registry.remove, 'test-confirm')
 
511
        self.run_script("""
 
512
            $ bzr test-confirm
 
513
            2>Really do it? [y/n]: 
 
514
            <yes
 
515
            Do it!
 
516
            $ bzr test-confirm
 
517
            2>Really do it? [y/n]: 
 
518
            <no
 
519
            ok, no
 
520
            """)
 
521