~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_script.py

(parthm) 'bzr status' now displays shelve summary (#403687). (Parth
 Malwankar)

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_comment_multiple_lines(self):
 
33
        self.assertEquals([
 
34
            (['bar'], None, None, None),
 
35
            ],
 
36
            script._script_to_commands("""
 
37
            # this comment is ignored
 
38
            # so is this
 
39
            # no we run bar
 
40
            $ bar
 
41
            """))
 
42
 
 
43
    def test_trim_blank_lines(self):
 
44
        """Blank lines are respected, but trimmed at the start and end.
 
45
 
 
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.
 
49
 
 
50
        However we do want to be able to match commands that emit blank lines.
 
51
        """
 
52
        self.assertEquals([
 
53
            (['bar'], None, '\n', None),
 
54
            ],
 
55
            script._script_to_commands("""
 
56
            $bar
 
57
 
 
58
            """))
 
59
 
 
60
    def test_simple_command(self):
 
61
        self.assertEquals([(['cd', 'trunk'], None, None, None)],
 
62
                           script._script_to_commands('$ cd trunk'))
 
63
 
 
64
    def test_command_with_single_quoted_param(self):
 
65
        story = """$ bzr commit -m 'two words'"""
 
66
        self.assertEquals([(['bzr', 'commit', '-m', "'two words'"],
 
67
                            None, None, None)],
 
68
                           script._script_to_commands(story))
 
69
 
 
70
    def test_command_with_double_quoted_param(self):
 
71
        story = """$ bzr commit -m "two words" """
 
72
        self.assertEquals([(['bzr', 'commit', '-m', '"two words"'],
 
73
                            None, None, None)],
 
74
                           script._script_to_commands(story))
 
75
 
 
76
    def test_command_with_input(self):
 
77
        self.assertEquals(
 
78
            [(['cat', '>file'], 'content\n', None, None)],
 
79
            script._script_to_commands('$ cat >file\n<content\n'))
 
80
 
 
81
    def test_indented(self):
 
82
        # scripts are commonly given indented within the test source code, and
 
83
        # common indentation is stripped off
 
84
        story = """
 
85
            $ bzr add
 
86
            adding file
 
87
            adding file2
 
88
            """
 
89
        self.assertEquals([(['bzr', 'add'], None,
 
90
                            'adding file\nadding file2\n', None)],
 
91
                          script._script_to_commands(story))
 
92
 
 
93
    def test_command_with_output(self):
 
94
        story = """
 
95
$ bzr add
 
96
adding file
 
97
adding file2
 
98
"""
 
99
        self.assertEquals([(['bzr', 'add'], None,
 
100
                            'adding file\nadding file2\n', None)],
 
101
                          script._script_to_commands(story))
 
102
 
 
103
    def test_command_with_error(self):
 
104
        story = """
 
105
$ bzr branch foo
 
106
2>bzr: ERROR: Not a branch: "foo"
 
107
"""
 
108
        self.assertEquals([(['bzr', 'branch', 'foo'],
 
109
                            None, None, 'bzr: ERROR: Not a branch: "foo"\n')],
 
110
                          script._script_to_commands(story))
 
111
 
 
112
    def test_input_without_command(self):
 
113
        self.assertRaises(SyntaxError, script._script_to_commands, '<input')
 
114
 
 
115
    def test_output_without_command(self):
 
116
        self.assertRaises(SyntaxError, script._script_to_commands, '>input')
 
117
 
 
118
    def test_command_with_backquotes(self):
 
119
        story = """
 
120
$ foo = `bzr file-id toto`
 
121
"""
 
122
        self.assertEquals([(['foo', '=', '`bzr file-id toto`'],
 
123
                            None, None, None)],
 
124
                          script._script_to_commands(story))
 
125
 
 
126
 
 
127
class TestRedirections(tests.TestCase):
 
128
 
 
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))
 
132
 
 
133
    def test_no_redirection(self):
 
134
        self._check(None, None, None, [], [])
 
135
        self._check(None, None, None, ['foo', 'bar'], ['foo', 'bar'])
 
136
 
 
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'])
 
143
 
 
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'])
 
151
 
 
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+', [], ['<', '>', '>>'])
 
157
 
 
158
 
 
159
 
 
160
class TestExecution(script.TestCaseWithTransportAndScript):
 
161
 
 
162
    def test_unknown_command(self):
 
163
        self.assertRaises(SyntaxError, self.run_script, 'foo')
 
164
 
 
165
    def test_stops_on_unexpected_output(self):
 
166
        story = """
 
167
$ mkdir dir
 
168
$ cd dir
 
169
The cd command ouputs nothing
 
170
"""
 
171
        self.assertRaises(AssertionError, self.run_script, story)
 
172
 
 
173
 
 
174
    def test_stops_on_unexpected_error(self):
 
175
        story = """
 
176
$ cat
 
177
<Hello
 
178
$ bzr not-a-command
 
179
"""
 
180
        self.assertRaises(AssertionError, self.run_script, story)
 
181
 
 
182
    def test_continue_on_expected_error(self):
 
183
        story = """
 
184
$ bzr not-a-command
 
185
2>..."not-a-command"
 
186
"""
 
187
        self.run_script(story)
 
188
 
 
189
    def test_continue_on_error_output(self):
 
190
        # The status matters, not the output
 
191
        story = """
 
192
$ bzr init
 
193
$ cat >file
 
194
<Hello
 
195
$ bzr add file
 
196
$ bzr commit -m 'adding file'
 
197
"""
 
198
        self.run_script(story)
 
199
 
 
200
    def test_ellipsis_output(self):
 
201
        story = """
 
202
$ cat
 
203
<first line
 
204
<second line
 
205
<last line
 
206
first line
 
207
...
 
208
last line
 
209
"""
 
210
        self.run_script(story)
 
211
        story = """
 
212
$ bzr not-a-command
 
213
2>..."not-a-command"
 
214
"""
 
215
        self.run_script(story)
 
216
 
 
217
        story = """
 
218
$ bzr branch not-a-branch
 
219
2>bzr: ERROR: Not a branch...not-a-branch/".
 
220
"""
 
221
        self.run_script(story)
 
222
 
 
223
 
 
224
class TestArgumentProcessing(script.TestCaseWithTransportAndScript):
 
225
 
 
226
    def test_globing(self):
 
227
        self.run_script("""
 
228
$ echo cat >cat
 
229
$ echo dog >dog
 
230
$ cat *
 
231
cat
 
232
dog
 
233
""")
 
234
 
 
235
    def test_quoted_globbing(self):
 
236
        self.run_script("""
 
237
$ echo cat >cat
 
238
$ cat '*'
 
239
2>*: No such file or directory
 
240
""")
 
241
 
 
242
    def test_quotes_removal(self):
 
243
        self.run_script("""
 
244
$ echo 'cat' "dog" '"chicken"' "'dragon'"
 
245
cat dog "chicken" 'dragon'
 
246
""")
 
247
 
 
248
 
 
249
class TestCat(script.TestCaseWithTransportAndScript):
 
250
 
 
251
    def test_cat_usage(self):
 
252
        self.assertRaises(SyntaxError, self.run_script, 'cat foo <bar')
 
253
 
 
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)
 
259
 
 
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)
 
266
 
 
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)
 
278
 
 
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'],
 
282
                                             None, None, None)
 
283
        self.assertFileEqual('content\n', 'file2')
 
284
 
 
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'],
 
289
                                             None, None, None)
 
290
        self.assertFileEqual('cat\ndog\n', 'file')
 
291
 
 
292
    def test_cat_bogus_input_file(self):
 
293
        self.run_script("""
 
294
$ cat <file
 
295
2>file: No such file or directory
 
296
""")
 
297
 
 
298
    def test_cat_bogus_output_file(self):
 
299
        self.run_script("""
 
300
$ cat >
 
301
2>: No such file or directory
 
302
""")
 
303
 
 
304
    def test_echo_bogus_output_file(self):
 
305
        # We need a backing file sysytem for that test so it can't be in
 
306
        # TestEcho
 
307
        self.run_script("""
 
308
$ echo >
 
309
2>: No such file or directory
 
310
""")
 
311
 
 
312
 
 
313
class TestMkdir(script.TestCaseWithTransportAndScript):
 
314
 
 
315
    def test_mkdir_usage(self):
 
316
        self.assertRaises(SyntaxError, self.run_script, '$ mkdir')
 
317
        self.assertRaises(SyntaxError, self.run_script, '$ mkdir foo bar')
 
318
 
 
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')
 
322
 
 
323
    def test_mkdir_in_jail(self):
 
324
        self.run_script("""
 
325
$ mkdir dir
 
326
$ cd dir
 
327
$ mkdir ../dir2
 
328
$ cd ..
 
329
""")
 
330
        self.failUnlessExists('dir')
 
331
        self.failUnlessExists('dir2')
 
332
 
 
333
 
 
334
class TestCd(script.TestCaseWithTransportAndScript):
 
335
 
 
336
    def test_cd_usage(self):
 
337
        self.assertRaises(SyntaxError, self.run_script, '$ cd foo bar')
 
338
 
 
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 ..')
 
342
 
 
343
    def test_cd_dir_and_back_home(self):
 
344
        self.assertEquals(self.test_dir, osutils.getcwd())
 
345
        self.run_script("""
 
346
$ mkdir dir
 
347
$ cd dir
 
348
""")
 
349
        self.assertEquals(osutils.pathjoin(self.test_dir, 'dir'),
 
350
                          osutils.getcwd())
 
351
 
 
352
        self.run_script('$ cd')
 
353
        self.assertEquals(self.test_dir, osutils.getcwd())
 
354
 
 
355
 
 
356
class TestBzr(script.TestCaseWithTransportAndScript):
 
357
 
 
358
    def test_bzr_smoke(self):
 
359
        self.run_script('$ bzr init branch')
 
360
        self.failUnlessExists('branch')
 
361
 
 
362
 
 
363
class TestEcho(script.TestCaseWithMemoryTransportAndScript):
 
364
 
 
365
    def test_echo_usage(self):
 
366
        story = """
 
367
$ echo foo
 
368
<bar
 
369
"""
 
370
        self.assertRaises(SyntaxError, self.run_script, story)
 
371
 
 
372
    def test_echo_input(self):
 
373
        self.assertRaises(SyntaxError, self.run_script, """
 
374
            $ echo <foo
 
375
            """)
 
376
 
 
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)
 
381
 
 
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)
 
387
 
 
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)
 
394
 
 
395
    def test_echo_appended(self):
 
396
        retcode, out, err = self.run_command(['echo', 'hello', '>file'],
 
397
                                             None, None, None)
 
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'],
 
402
                                             None, None, None)
 
403
        self.assertEquals(None, out)
 
404
        self.assertEquals(None, err)
 
405
        self.assertFileEqual('hello\nhappy\n', 'file')
 
406
 
 
407
    def test_empty_line_in_output_is_respected(self):
 
408
        self.run_script("""
 
409
            $ echo
 
410
 
 
411
            $ echo bar
 
412
            bar
 
413
            """)
 
414
 
 
415
 
 
416
class TestRm(script.TestCaseWithTransportAndScript):
 
417
 
 
418
    def test_rm_usage(self):
 
419
        self.assertRaises(SyntaxError, self.run_script, '$ rm')
 
420
        self.assertRaises(SyntaxError, self.run_script, '$ rm -ff foo')
 
421
 
 
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')
 
427
 
 
428
    def test_rm_file_force(self):
 
429
        self.failIfExists('file')
 
430
        self.run_script('$ rm -f file')
 
431
        self.failIfExists('file')
 
432
 
 
433
    def test_rm_files(self):
 
434
        self.run_script("""
 
435
$ echo content >file
 
436
$ echo content >file2
 
437
""")
 
438
        self.failUnlessExists('file2')
 
439
        self.run_script('$ rm file file2')
 
440
        self.failIfExists('file2')
 
441
 
 
442
    def test_rm_dir(self):
 
443
        self.run_script('$ mkdir dir')
 
444
        self.failUnlessExists('dir')
 
445
        self.run_script("""
 
446
$ rm dir
 
447
2>rm: cannot remove 'dir': Is a directory
 
448
""")
 
449
        self.failUnlessExists('dir')
 
450
 
 
451
    def test_rm_dir_recursive(self):
 
452
        self.run_script("""
 
453
$ mkdir dir
 
454
$ rm -r dir
 
455
""")
 
456
        self.failIfExists('dir')
 
457
 
 
458
 
 
459
class TestMv(script.TestCaseWithTransportAndScript):
 
460
 
 
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')
 
465
 
 
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')
 
472
 
 
473
    def test_move_unknown_file(self):
 
474
        self.assertRaises(AssertionError,
 
475
                          self.run_script, '$ mv unknown does-not-exist')
 
476
 
 
477
    def test_move_dir(self):
 
478
        self.run_script("""
 
479
$ mkdir dir
 
480
$ echo content >dir/file
 
481
""")
 
482
        self.run_script('$ mv dir new_name')
 
483
        self.failIfExists('dir')
 
484
        self.failUnlessExists('new_name')
 
485
        self.failUnlessExists('new_name/file')
 
486
 
 
487
    def test_move_file_into_dir(self):
 
488
        self.run_script("""
 
489
$ mkdir dir
 
490
$ echo content > file
 
491
""")
 
492
        self.run_script('$ mv file dir')
 
493
        self.failUnlessExists('dir')
 
494
        self.failIfExists('file')
 
495
        self.failUnlessExists('dir/file')
 
496
 
 
497
 
 
498
class cmd_test_confirm(commands.Command):
 
499
 
 
500
    def run(self):
 
501
        if ui.ui_factory.get_boolean(
 
502
            'Really do it',
 
503
            # 'bzrlib.tests.test_script.confirm',
 
504
            # {}
 
505
            ):
 
506
            self.outf.write('Do it!\n')
 
507
        else:
 
508
            print 'ok, no'
 
509
 
 
510
 
 
511
class TestUserInteraction(script.TestCaseWithMemoryTransportAndScript):
 
512
 
 
513
    def test_confirm_action(self):
 
514
        """You can write tests that demonstrate user confirmation.
 
515
        
 
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 
 
518
        by the input.
 
519
        """
 
520
        commands.builtin_command_registry.register(cmd_test_confirm)
 
521
        self.addCleanup(commands.builtin_command_registry.remove, 'test-confirm')
 
522
        self.run_script("""
 
523
            $ bzr test-confirm
 
524
            2>Really do it? [y/n]: 
 
525
            <yes
 
526
            Do it!
 
527
            $ bzr test-confirm
 
528
            2>Really do it? [y/n]: 
 
529
            <no
 
530
            ok, no
 
531
            """)
 
532