~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_script.py

  • Committer: Vincent Ladeuil
  • Date: 2010-11-07 13:38:56 UTC
  • mfrom: (5050.45.8 2.2)
  • mto: This revision was merged to the branch mainline in revision 5531.
  • Revision ID: v.ladeuil+lp@free.fr-20101107133856-21rzvgfl40q4wxhd
Merge 2.2 into trunk including fix for bug #646961

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
    trace,
 
23
    ui,
 
24
    )
 
25
from bzrlib.tests import script
 
26
 
 
27
 
 
28
class TestSyntax(tests.TestCase):
 
29
 
 
30
    def test_comment_is_ignored(self):
 
31
        self.assertEquals([], script._script_to_commands('#comment\n'))
 
32
 
 
33
    def test_comment_multiple_lines(self):
 
34
        self.assertEquals([
 
35
            (['bar'], None, None, None),
 
36
            ],
 
37
            script._script_to_commands("""
 
38
            # this comment is ignored
 
39
            # so is this
 
40
            # no we run bar
 
41
            $ bar
 
42
            """))
 
43
 
 
44
    def test_trim_blank_lines(self):
 
45
        """Blank lines are respected, but trimmed at the start and end.
 
46
 
 
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.
 
50
 
 
51
        However we do want to be able to match commands that emit blank lines.
 
52
        """
 
53
        self.assertEquals([
 
54
            (['bar'], None, '\n', None),
 
55
            ],
 
56
            script._script_to_commands("""
 
57
            $bar
 
58
 
 
59
            """))
 
60
 
 
61
    def test_simple_command(self):
 
62
        self.assertEquals([(['cd', 'trunk'], None, None, None)],
 
63
                           script._script_to_commands('$ cd trunk'))
 
64
 
 
65
    def test_command_with_single_quoted_param(self):
 
66
        story = """$ bzr commit -m 'two words'"""
 
67
        self.assertEquals([(['bzr', 'commit', '-m', "'two words'"],
 
68
                            None, None, None)],
 
69
                           script._script_to_commands(story))
 
70
 
 
71
    def test_command_with_double_quoted_param(self):
 
72
        story = """$ bzr commit -m "two words" """
 
73
        self.assertEquals([(['bzr', 'commit', '-m', '"two words"'],
 
74
                            None, None, None)],
 
75
                           script._script_to_commands(story))
 
76
 
 
77
    def test_command_with_input(self):
 
78
        self.assertEquals(
 
79
            [(['cat', '>file'], 'content\n', None, None)],
 
80
            script._script_to_commands('$ cat >file\n<content\n'))
 
81
 
 
82
    def test_indented(self):
 
83
        # scripts are commonly given indented within the test source code, and
 
84
        # common indentation is stripped off
 
85
        story = """
 
86
            $ bzr add
 
87
            adding file
 
88
            adding file2
 
89
            """
 
90
        self.assertEquals([(['bzr', 'add'], None,
 
91
                            'adding file\nadding file2\n', None)],
 
92
                          script._script_to_commands(story))
 
93
 
 
94
    def test_command_with_output(self):
 
95
        story = """
 
96
$ bzr add
 
97
adding file
 
98
adding file2
 
99
"""
 
100
        self.assertEquals([(['bzr', 'add'], None,
 
101
                            'adding file\nadding file2\n', None)],
 
102
                          script._script_to_commands(story))
 
103
 
 
104
    def test_command_with_error(self):
 
105
        story = """
 
106
$ bzr branch foo
 
107
2>bzr: ERROR: Not a branch: "foo"
 
108
"""
 
109
        self.assertEquals([(['bzr', 'branch', 'foo'],
 
110
                            None, None, 'bzr: ERROR: Not a branch: "foo"\n')],
 
111
                          script._script_to_commands(story))
 
112
 
 
113
    def test_input_without_command(self):
 
114
        self.assertRaises(SyntaxError, script._script_to_commands, '<input')
 
115
 
 
116
    def test_output_without_command(self):
 
117
        self.assertRaises(SyntaxError, script._script_to_commands, '>input')
 
118
 
 
119
    def test_command_with_backquotes(self):
 
120
        story = """
 
121
$ foo = `bzr file-id toto`
 
122
"""
 
123
        self.assertEquals([(['foo', '=', '`bzr file-id toto`'],
 
124
                            None, None, None)],
 
125
                          script._script_to_commands(story))
 
126
 
 
127
 
 
128
class TestRedirections(tests.TestCase):
 
129
 
 
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))
 
133
 
 
134
    def test_no_redirection(self):
 
135
        self._check(None, None, None, [], [])
 
136
        self._check(None, None, None, ['foo', 'bar'], ['foo', 'bar'])
 
137
 
 
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'])
 
144
 
 
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'])
 
152
 
 
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+', [], ['<', '>', '>>'])
 
158
 
 
159
 
 
160
 
 
161
class TestExecution(script.TestCaseWithTransportAndScript):
 
162
 
 
163
    def test_unknown_command(self):
 
164
        """A clear error is reported for commands that aren't recognised
 
165
 
 
166
        Testing the attributes of the SyntaxError instance is equivalent to
 
167
        using traceback.format_exception_only and comparing with:
 
168
          File "<string>", line 1
 
169
            foo --frob
 
170
            ^
 
171
        SyntaxError: Command not found "foo"
 
172
        """
 
173
        e = self.assertRaises(SyntaxError, self.run_script, "$ foo --frob")
 
174
        self.assertContainsRe(e.msg, "not found.*foo")
 
175
        self.assertEquals(e.text, "foo --frob")
 
176
 
 
177
    def test_blank_output_mismatches_output(self):
 
178
        """If you give output, the output must actually be blank.
 
179
        
 
180
        See <https://bugs.launchpad.net/bzr/+bug/637830>: previously blank
 
181
        output was a wildcard.  Now you must say ... if you want that.
 
182
        """
 
183
        self.assertRaises(AssertionError,
 
184
            self.run_script,
 
185
            """
 
186
            $ echo foo
 
187
            """)
 
188
 
 
189
    def test_ellipsis_everything(self):
 
190
        """A simple ellipsis matches everything."""
 
191
        self.run_script("""
 
192
        $ echo foo
 
193
        ...
 
194
        """)
 
195
 
 
196
    def test_ellipsis_matches_empty(self):
 
197
        self.run_script("""
 
198
        $ cd .
 
199
        ...
 
200
        """)
 
201
 
 
202
    def test_stops_on_unexpected_output(self):
 
203
        story = """
 
204
$ mkdir dir
 
205
$ cd dir
 
206
The cd command ouputs nothing
 
207
"""
 
208
        self.assertRaises(AssertionError, self.run_script, story)
 
209
 
 
210
    def test_stops_on_unexpected_error(self):
 
211
        story = """
 
212
$ cat
 
213
<Hello
 
214
$ bzr not-a-command
 
215
"""
 
216
        self.assertRaises(AssertionError, self.run_script, story)
 
217
 
 
218
    def test_continue_on_expected_error(self):
 
219
        story = """
 
220
$ bzr not-a-command
 
221
2>..."not-a-command"
 
222
"""
 
223
        self.run_script(story)
 
224
 
 
225
    def test_continue_on_error_output(self):
 
226
        # The status matters, not the output
 
227
        story = """
 
228
$ bzr init
 
229
...
 
230
$ cat >file
 
231
<Hello
 
232
$ bzr add file
 
233
...
 
234
$ bzr commit -m 'adding file'
 
235
2>...
 
236
"""
 
237
        self.run_script(story)
 
238
 
 
239
    def test_ellipsis_output(self):
 
240
        story = """
 
241
$ cat
 
242
<first line
 
243
<second line
 
244
<last line
 
245
first line
 
246
...
 
247
last line
 
248
"""
 
249
        self.run_script(story)
 
250
        story = """
 
251
$ bzr not-a-command
 
252
2>..."not-a-command"
 
253
"""
 
254
        self.run_script(story)
 
255
 
 
256
        story = """
 
257
$ bzr branch not-a-branch
 
258
2>bzr: ERROR: Not a branch...not-a-branch/".
 
259
"""
 
260
        self.run_script(story)
 
261
 
 
262
 
 
263
class TestArgumentProcessing(script.TestCaseWithTransportAndScript):
 
264
 
 
265
    def test_globing(self):
 
266
        self.run_script("""
 
267
$ echo cat >cat
 
268
$ echo dog >dog
 
269
$ cat *
 
270
cat
 
271
dog
 
272
""")
 
273
 
 
274
    def test_quoted_globbing(self):
 
275
        self.run_script("""
 
276
$ echo cat >cat
 
277
$ cat '*'
 
278
2>*: No such file or directory
 
279
""")
 
280
 
 
281
    def test_quotes_removal(self):
 
282
        self.run_script("""
 
283
$ echo 'cat' "dog" '"chicken"' "'dragon'"
 
284
cat dog "chicken" 'dragon'
 
285
""")
 
286
 
 
287
    def test_verbosity_isolated(self):
 
288
        """Global verbosity is isolated from commands run in scripts.
 
289
        """
 
290
        # see also 656694; we should get rid of global verbosity
 
291
        self.run_script("""
 
292
        $ bzr init --quiet a
 
293
        """)
 
294
        self.assertEquals(trace.is_quiet(), False)
 
295
 
 
296
 
 
297
class TestCat(script.TestCaseWithTransportAndScript):
 
298
 
 
299
    def test_cat_usage(self):
 
300
        self.assertRaises(SyntaxError, self.run_script, 'cat foo <bar')
 
301
 
 
302
    def test_cat_input_to_output(self):
 
303
        retcode, out, err = self.run_command(['cat'],
 
304
                                             'content\n', 'content\n', None)
 
305
        self.assertEquals('content\n', out)
 
306
        self.assertEquals(None, err)
 
307
 
 
308
    def test_cat_file_to_output(self):
 
309
        self.build_tree_contents([('file', 'content\n')])
 
310
        retcode, out, err = self.run_command(['cat', 'file'],
 
311
                                             None, 'content\n', None)
 
312
        self.assertEquals('content\n', out)
 
313
        self.assertEquals(None, err)
 
314
 
 
315
    def test_cat_input_to_file(self):
 
316
        retcode, out, err = self.run_command(['cat', '>file'],
 
317
                                             'content\n', None, None)
 
318
        self.assertFileEqual('content\n', 'file')
 
319
        self.assertEquals(None, out)
 
320
        self.assertEquals(None, err)
 
321
        retcode, out, err = self.run_command(['cat', '>>file'],
 
322
                                             'more\n', None, None)
 
323
        self.assertFileEqual('content\nmore\n', 'file')
 
324
        self.assertEquals(None, out)
 
325
        self.assertEquals(None, err)
 
326
 
 
327
    def test_cat_file_to_file(self):
 
328
        self.build_tree_contents([('file', 'content\n')])
 
329
        retcode, out, err = self.run_command(['cat', 'file', '>file2'],
 
330
                                             None, None, None)
 
331
        self.assertFileEqual('content\n', 'file2')
 
332
 
 
333
    def test_cat_files_to_file(self):
 
334
        self.build_tree_contents([('cat', 'cat\n')])
 
335
        self.build_tree_contents([('dog', 'dog\n')])
 
336
        retcode, out, err = self.run_command(['cat', 'cat', 'dog', '>file'],
 
337
                                             None, None, None)
 
338
        self.assertFileEqual('cat\ndog\n', 'file')
 
339
 
 
340
    def test_cat_bogus_input_file(self):
 
341
        self.run_script("""
 
342
$ cat <file
 
343
2>file: No such file or directory
 
344
""")
 
345
 
 
346
    def test_cat_bogus_output_file(self):
 
347
        self.run_script("""
 
348
$ cat >
 
349
2>: No such file or directory
 
350
""")
 
351
 
 
352
    def test_echo_bogus_output_file(self):
 
353
        # We need a backing file sysytem for that test so it can't be in
 
354
        # TestEcho
 
355
        self.run_script("""
 
356
$ echo >
 
357
2>: No such file or directory
 
358
""")
 
359
 
 
360
 
 
361
class TestMkdir(script.TestCaseWithTransportAndScript):
 
362
 
 
363
    def test_mkdir_usage(self):
 
364
        self.assertRaises(SyntaxError, self.run_script, '$ mkdir')
 
365
        self.assertRaises(SyntaxError, self.run_script, '$ mkdir foo bar')
 
366
 
 
367
    def test_mkdir_jailed(self):
 
368
        self.assertRaises(ValueError, self.run_script, '$ mkdir /out-of-jail')
 
369
        self.assertRaises(ValueError, self.run_script, '$ mkdir ../out-of-jail')
 
370
 
 
371
    def test_mkdir_in_jail(self):
 
372
        self.run_script("""
 
373
$ mkdir dir
 
374
$ cd dir
 
375
$ mkdir ../dir2
 
376
$ cd ..
 
377
""")
 
378
        self.failUnlessExists('dir')
 
379
        self.failUnlessExists('dir2')
 
380
 
 
381
 
 
382
class TestCd(script.TestCaseWithTransportAndScript):
 
383
 
 
384
    def test_cd_usage(self):
 
385
        self.assertRaises(SyntaxError, self.run_script, '$ cd foo bar')
 
386
 
 
387
    def test_cd_out_of_jail(self):
 
388
        self.assertRaises(ValueError, self.run_script, '$ cd /out-of-jail')
 
389
        self.assertRaises(ValueError, self.run_script, '$ cd ..')
 
390
 
 
391
    def test_cd_dir_and_back_home(self):
 
392
        self.assertEquals(self.test_dir, osutils.getcwd())
 
393
        self.run_script("""
 
394
$ mkdir dir
 
395
$ cd dir
 
396
""")
 
397
        self.assertEquals(osutils.pathjoin(self.test_dir, 'dir'),
 
398
                          osutils.getcwd())
 
399
 
 
400
        self.run_script('$ cd')
 
401
        self.assertEquals(self.test_dir, osutils.getcwd())
 
402
 
 
403
 
 
404
class TestBzr(script.TestCaseWithTransportAndScript):
 
405
 
 
406
    def test_bzr_smoke(self):
 
407
        self.run_script("""
 
408
            $ bzr init branch
 
409
            Created a standalone tree (format: ...)
 
410
            """)
 
411
        self.failUnlessExists('branch')
 
412
 
 
413
 
 
414
class TestEcho(script.TestCaseWithMemoryTransportAndScript):
 
415
 
 
416
    def test_echo_usage(self):
 
417
        story = """
 
418
$ echo foo
 
419
<bar
 
420
"""
 
421
        self.assertRaises(SyntaxError, self.run_script, story)
 
422
 
 
423
    def test_echo_input(self):
 
424
        self.assertRaises(SyntaxError, self.run_script, """
 
425
            $ echo <foo
 
426
            """)
 
427
 
 
428
    def test_echo_to_output(self):
 
429
        retcode, out, err = self.run_command(['echo'], None, '\n', None)
 
430
        self.assertEquals('\n', out)
 
431
        self.assertEquals(None, err)
 
432
 
 
433
    def test_echo_some_to_output(self):
 
434
        retcode, out, err = self.run_command(['echo', 'hello'],
 
435
                                             None, 'hello\n', None)
 
436
        self.assertEquals('hello\n', out)
 
437
        self.assertEquals(None, err)
 
438
 
 
439
    def test_echo_more_output(self):
 
440
        retcode, out, err = self.run_command(
 
441
            ['echo', 'hello', 'happy', 'world'],
 
442
            None, 'hello happy world\n', None)
 
443
        self.assertEquals('hello happy world\n', out)
 
444
        self.assertEquals(None, err)
 
445
 
 
446
    def test_echo_appended(self):
 
447
        retcode, out, err = self.run_command(['echo', 'hello', '>file'],
 
448
                                             None, None, None)
 
449
        self.assertEquals(None, out)
 
450
        self.assertEquals(None, err)
 
451
        self.assertFileEqual('hello\n', 'file')
 
452
        retcode, out, err = self.run_command(['echo', 'happy', '>>file'],
 
453
                                             None, None, None)
 
454
        self.assertEquals(None, out)
 
455
        self.assertEquals(None, err)
 
456
        self.assertFileEqual('hello\nhappy\n', 'file')
 
457
 
 
458
    def test_empty_line_in_output_is_respected(self):
 
459
        self.run_script("""
 
460
            $ echo
 
461
 
 
462
            $ echo bar
 
463
            bar
 
464
            """)
 
465
 
 
466
 
 
467
class TestRm(script.TestCaseWithTransportAndScript):
 
468
 
 
469
    def test_rm_usage(self):
 
470
        self.assertRaises(SyntaxError, self.run_script, '$ rm')
 
471
        self.assertRaises(SyntaxError, self.run_script, '$ rm -ff foo')
 
472
 
 
473
    def test_rm_file(self):
 
474
        self.run_script('$ echo content >file')
 
475
        self.failUnlessExists('file')
 
476
        self.run_script('$ rm file')
 
477
        self.failIfExists('file')
 
478
 
 
479
    def test_rm_file_force(self):
 
480
        self.failIfExists('file')
 
481
        self.run_script('$ rm -f file')
 
482
        self.failIfExists('file')
 
483
 
 
484
    def test_rm_files(self):
 
485
        self.run_script("""
 
486
$ echo content >file
 
487
$ echo content >file2
 
488
""")
 
489
        self.failUnlessExists('file2')
 
490
        self.run_script('$ rm file file2')
 
491
        self.failIfExists('file2')
 
492
 
 
493
    def test_rm_dir(self):
 
494
        self.run_script('$ mkdir dir')
 
495
        self.failUnlessExists('dir')
 
496
        self.run_script("""
 
497
$ rm dir
 
498
2>rm: cannot remove 'dir': Is a directory
 
499
""")
 
500
        self.failUnlessExists('dir')
 
501
 
 
502
    def test_rm_dir_recursive(self):
 
503
        self.run_script("""
 
504
$ mkdir dir
 
505
$ rm -r dir
 
506
""")
 
507
        self.failIfExists('dir')
 
508
 
 
509
 
 
510
class TestMv(script.TestCaseWithTransportAndScript):
 
511
 
 
512
    def test_usage(self):
 
513
        self.assertRaises(SyntaxError, self.run_script, '$ mv')
 
514
        self.assertRaises(SyntaxError, self.run_script, '$ mv f')
 
515
        self.assertRaises(SyntaxError, self.run_script, '$ mv f1 f2 f3')
 
516
 
 
517
    def test_move_file(self):
 
518
        self.run_script('$ echo content >file')
 
519
        self.failUnlessExists('file')
 
520
        self.run_script('$ mv file new_name')
 
521
        self.failIfExists('file')
 
522
        self.failUnlessExists('new_name')
 
523
 
 
524
    def test_move_unknown_file(self):
 
525
        self.assertRaises(AssertionError,
 
526
                          self.run_script, '$ mv unknown does-not-exist')
 
527
 
 
528
    def test_move_dir(self):
 
529
        self.run_script("""
 
530
$ mkdir dir
 
531
$ echo content >dir/file
 
532
""")
 
533
        self.run_script('$ mv dir new_name')
 
534
        self.failIfExists('dir')
 
535
        self.failUnlessExists('new_name')
 
536
        self.failUnlessExists('new_name/file')
 
537
 
 
538
    def test_move_file_into_dir(self):
 
539
        self.run_script("""
 
540
$ mkdir dir
 
541
$ echo content > file
 
542
""")
 
543
        self.run_script('$ mv file dir')
 
544
        self.failUnlessExists('dir')
 
545
        self.failIfExists('file')
 
546
        self.failUnlessExists('dir/file')
 
547
 
 
548
 
 
549
class cmd_test_confirm(commands.Command):
 
550
 
 
551
    def run(self):
 
552
        if ui.ui_factory.get_boolean(
 
553
            'Really do it',
 
554
            # 'bzrlib.tests.test_script.confirm',
 
555
            # {}
 
556
            ):
 
557
            self.outf.write('Do it!\n')
 
558
        else:
 
559
            print 'ok, no'
 
560
 
 
561
 
 
562
class TestUserInteraction(script.TestCaseWithMemoryTransportAndScript):
 
563
 
 
564
    def test_confirm_action(self):
 
565
        """You can write tests that demonstrate user confirmation.
 
566
        
 
567
        Specifically, ScriptRunner does't care if the output line for the prompt
 
568
        isn't terminated by a newline from the program; it's implicitly terminated 
 
569
        by the input.
 
570
        """
 
571
        commands.builtin_command_registry.register(cmd_test_confirm)
 
572
        self.addCleanup(commands.builtin_command_registry.remove, 'test-confirm')
 
573
        self.run_script("""
 
574
            $ bzr test-confirm
 
575
            2>Really do it? [y/n]: 
 
576
            <yes
 
577
            Do it!
 
578
            $ bzr test-confirm
 
579
            2>Really do it? [y/n]: 
 
580
            <no
 
581
            ok, no
 
582
            """)
 
583