/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to breezy/tests/blackbox/test_commit.py

  • Committer: Breezy landing bot
  • Author(s): Jelmer Vernooij
  • Date: 2020-07-28 02:47:10 UTC
  • mfrom: (7519.1.1 merge-3.1)
  • Revision ID: breezy.the.bot@gmail.com-20200728024710-a2ylds219f1lsl62
Merge lp:brz/3.1.

Merged from https://code.launchpad.net/~jelmer/brz/merge-3.1/+merge/388173

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006-2010 Canonical Ltd
 
1
# Copyright (C) 2006-2012, 2016 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
17
17
 
18
18
"""Tests for the commit CLI of bzr."""
19
19
 
 
20
import doctest
20
21
import os
21
22
import re
22
23
import sys
23
24
 
24
 
from bzrlib import (
 
25
from testtools.matchers import DocTestMatches
 
26
 
 
27
from ... import (
 
28
    config,
25
29
    osutils,
26
30
    ignores,
27
31
    msgeditor,
28
 
    osutils,
29
 
    tests,
30
 
    )
31
 
from bzrlib.bzrdir import BzrDir
32
 
from bzrlib.tests import (
33
 
    probe_bad_non_ascii,
34
 
    TestSkipped,
35
 
    )
36
 
from bzrlib.tests.blackbox import ExternalBase
37
 
 
38
 
 
39
 
class TestCommit(ExternalBase):
 
32
    )
 
33
from ...controldir import ControlDir
 
34
from .. import (
 
35
    test_foreign,
 
36
    features,
 
37
    )
 
38
from .. import TestCaseWithTransport
 
39
from ..test_bedding import override_whoami
 
40
 
 
41
 
 
42
class TestCommit(TestCaseWithTransport):
40
43
 
41
44
    def test_05_empty_commit(self):
42
45
        """Commit of tree with no versioned files should fail"""
43
46
        # If forced, it should succeed, but this is not tested here.
44
47
        self.make_branch_and_tree('.')
45
48
        self.build_tree(['hello.txt'])
46
 
        out,err = self.run_bzr('commit -m empty', retcode=3)
 
49
        out, err = self.run_bzr('commit -m empty', retcode=3)
47
50
        self.assertEqual('', out)
48
 
        self.assertContainsRe(err, 'bzr: ERROR: No changes to commit\.'
49
 
                                  ' Use --unchanged to commit anyhow.\n')
 
51
        # Two ugly bits here.
 
52
        # 1) We really don't want 'aborting commit write group' anymore.
 
53
        # 2) brz: ERROR: is a really long line, so we wrap it with '\'
 
54
        self.assertThat(
 
55
            err,
 
56
            DocTestMatches("""\
 
57
Committing to: ...
 
58
brz: ERROR: No changes to commit.\
 
59
 Please 'brz add' the files you want to commit,\
 
60
 or use --unchanged to force an empty commit.
 
61
""", flags=doctest.ELLIPSIS | doctest.REPORT_UDIFF))
50
62
 
51
63
    def test_commit_success(self):
52
64
        """Successful commit should not leave behind a bzr-commit-* file"""
58
70
        self.run_bzr(["commit", "--unchanged", "-m", u'foo\xb5'])
59
71
        self.assertEqual('', self.run_bzr('unknowns')[0])
60
72
 
 
73
    def test_commit_lossy_native(self):
 
74
        """A --lossy option to commit is supported."""
 
75
        self.make_branch_and_tree('.')
 
76
        self.run_bzr('commit --lossy --unchanged -m message')
 
77
        self.assertEqual('', self.run_bzr('unknowns')[0])
 
78
 
 
79
    def test_commit_lossy_foreign(self):
 
80
        test_foreign.register_dummy_foreign_for_test(self)
 
81
        self.make_branch_and_tree('.',
 
82
                                  format=test_foreign.DummyForeignVcsDirFormat())
 
83
        self.run_bzr('commit --lossy --unchanged -m message')
 
84
        output = self.run_bzr('revision-info')[0]
 
85
        self.assertTrue(output.startswith('1 dummy-'))
 
86
 
61
87
    def test_commit_with_path(self):
62
88
        """Commit tree with path of root specified"""
63
89
        a_tree = self.make_branch_and_tree('a')
65
91
        a_tree.add('a_file')
66
92
        self.run_bzr(['commit', '-m', 'first commit', 'a'])
67
93
 
68
 
        b_tree = a_tree.bzrdir.sprout('b').open_workingtree()
69
 
        self.build_tree_contents([('b/a_file', 'changes in b')])
 
94
        b_tree = a_tree.controldir.sprout('b').open_workingtree()
 
95
        self.build_tree_contents([('b/a_file', b'changes in b')])
70
96
        self.run_bzr(['commit', '-m', 'first commit in b', 'b'])
71
97
 
72
 
        self.build_tree_contents([('a/a_file', 'new contents')])
 
98
        self.build_tree_contents([('a/a_file', b'new contents')])
73
99
        self.run_bzr(['commit', '-m', 'change in a', 'a'])
74
100
 
75
101
        b_tree.merge_from_branch(a_tree.branch)
77
103
        self.run_bzr('resolved b/a_file')
78
104
        self.run_bzr(['commit', '-m', 'merge into b', 'b'])
79
105
 
80
 
 
81
106
    def test_10_verbose_commit(self):
82
107
        """Add one file and examine verbose commit output"""
83
108
        tree = self.make_branch_and_tree('.')
84
109
        self.build_tree(['hello.txt'])
85
110
        tree.add("hello.txt")
86
 
        out,err = self.run_bzr('commit -m added')
 
111
        out, err = self.run_bzr('commit -m added')
87
112
        self.assertEqual('', out)
88
113
        self.assertContainsRe(err, '^Committing to: .*\n'
89
114
                              'added hello.txt\n'
92
117
    def prepare_simple_history(self):
93
118
        """Prepare and return a working tree with one commit of one file"""
94
119
        # Commit with modified file should say so
95
 
        wt = BzrDir.create_standalone_workingtree('.')
 
120
        wt = ControlDir.create_standalone_workingtree('.')
96
121
        self.build_tree(['hello.txt', 'extra.txt'])
97
122
        wt.add(['hello.txt'])
98
123
        wt.commit(message='added')
101
126
    def test_verbose_commit_modified(self):
102
127
        # Verbose commit of modified file should say so
103
128
        wt = self.prepare_simple_history()
104
 
        self.build_tree_contents([('hello.txt', 'new contents')])
 
129
        self.build_tree_contents([('hello.txt', b'new contents')])
105
130
        out, err = self.run_bzr('commit -m modified')
106
131
        self.assertEqual('', out)
107
132
        self.assertContainsRe(err, '^Committing to: .*\n'
108
 
                              'modified hello\.txt\n'
109
 
                              'Committed revision 2\.\n$')
 
133
                              'modified hello\\.txt\n'
 
134
                              'Committed revision 2\\.\n$')
110
135
 
111
136
    def test_unicode_commit_message_is_filename(self):
112
137
        """Unicode commit message same as a filename (Bug #563646).
113
138
        """
 
139
        self.requireFeature(features.UnicodeFilenameFeature)
114
140
        file_name = u'\N{euro sign}'
115
141
        self.run_bzr(['init'])
116
 
        open(file_name, 'w').write('hello world')
 
142
        with open(file_name, 'w') as f:
 
143
            f.write('hello world')
117
144
        self.run_bzr(['add'])
118
145
        out, err = self.run_bzr(['commit', '-m', file_name])
119
 
        reflags = re.MULTILINE|re.DOTALL|re.UNICODE
 
146
        reflags = re.MULTILINE | re.DOTALL | re.UNICODE
120
147
        te = osutils.get_terminal_encoding()
121
 
        self.assertContainsRe(err.decode(te),
122
 
            u'The commit message is a file name:',
123
 
            flags=reflags)
 
148
        self.assertContainsRe(err,
 
149
                              u'The commit message is a file name:',
 
150
                              flags=reflags)
124
151
 
125
152
        # Run same test with a filename that causes encode
126
153
        # error for the terminal encoding. We do this
129
156
        # by ui.text.show_warning
130
157
        default_get_terminal_enc = osutils.get_terminal_encoding
131
158
        try:
132
 
            osutils.get_terminal_encoding = lambda: 'ascii'
 
159
            osutils.get_terminal_encoding = lambda trace=None: 'ascii'
133
160
            file_name = u'foo\u1234'
134
 
            open(file_name, 'w').write('hello world')
 
161
            with open(file_name, 'w') as f:
 
162
                f.write('hello world')
135
163
            self.run_bzr(['add'])
136
164
            out, err = self.run_bzr(['commit', '-m', file_name])
137
 
            reflags = re.MULTILINE|re.DOTALL|re.UNICODE
 
165
            reflags = re.MULTILINE | re.DOTALL | re.UNICODE
138
166
            te = osutils.get_terminal_encoding()
139
 
            self.assertContainsRe(err.decode(te, 'replace'),
140
 
                u'The commit message is a file name:',
141
 
                flags=reflags)
 
167
            self.assertContainsRe(err,
 
168
                                  u'The commit message is a file name:',
 
169
                                  flags=reflags)
142
170
        finally:
143
171
            osutils.get_terminal_encoding = default_get_terminal_enc
144
172
 
 
173
    def test_non_ascii_file_unversioned_utf8(self):
 
174
        self.requireFeature(features.UnicodeFilenameFeature)
 
175
        tree = self.make_branch_and_tree(".")
 
176
        self.build_tree(["f"])
 
177
        tree.add(["f"])
 
178
        out, err = self.run_bzr_raw(["commit", "-m", "Wrong filename", u"\xa7"],
 
179
                                    encoding="utf-8", retcode=3)
 
180
        self.assertContainsRe(err, b"(?m)not versioned: \"\xc2\xa7\"$")
 
181
 
 
182
    def test_non_ascii_file_unversioned_iso_8859_5(self):
 
183
        self.requireFeature(features.UnicodeFilenameFeature)
 
184
        tree = self.make_branch_and_tree(".")
 
185
        self.build_tree(["f"])
 
186
        tree.add(["f"])
 
187
        out, err = self.run_bzr_raw(["commit", "-m", "Wrong filename", u"\xa7"],
 
188
                                    encoding="iso-8859-5", retcode=3)
 
189
        self.assertNotContainsString(err, b"\xc2\xa7")
 
190
        self.assertContainsRe(err, b"(?m)not versioned: \"\xfd\"$")
 
191
 
145
192
    def test_warn_about_forgotten_commit_message(self):
146
193
        """Test that the lack of -m parameter is caught"""
147
194
        wt = self.make_branch_and_tree('.')
157
204
        out, err = self.run_bzr('commit -m renamed')
158
205
        self.assertEqual('', out)
159
206
        self.assertContainsRe(err, '^Committing to: .*\n'
160
 
                              'renamed hello\.txt => gutentag\.txt\n'
161
 
                              'Committed revision 2\.$\n')
 
207
                              'renamed hello\\.txt => gutentag\\.txt\n'
 
208
                              'Committed revision 2\\.$\n')
162
209
 
163
210
    def test_verbose_commit_moved(self):
164
211
        # Verbose commit of file moved to new directory should say so
168
215
        wt.rename_one('hello.txt', 'subdir/hello.txt')
169
216
        out, err = self.run_bzr('commit -m renamed')
170
217
        self.assertEqual('', out)
171
 
        self.assertEqual(set([
 
218
        self.assertEqual({
172
219
            'Committing to: %s/' % osutils.getcwd(),
173
220
            'added subdir',
174
221
            'renamed hello.txt => subdir/hello.txt',
175
222
            'Committed revision 2.',
176
223
            '',
177
 
            ]), set(err.split('\n')))
 
224
            }, set(err.split('\n')))
178
225
 
179
226
    def test_verbose_commit_with_unknown(self):
180
227
        """Unknown files should not be listed by default in verbose output"""
181
228
        # Is that really the best policy?
182
 
        wt = BzrDir.create_standalone_workingtree('.')
 
229
        wt = ControlDir.create_standalone_workingtree('.')
183
230
        self.build_tree(['hello.txt', 'extra.txt'])
184
231
        wt.add(['hello.txt'])
185
 
        out,err = self.run_bzr('commit -m added')
 
232
        out, err = self.run_bzr('commit -m added')
186
233
        self.assertEqual('', out)
187
234
        self.assertContainsRe(err, '^Committing to: .*\n'
188
 
                              'added hello\.txt\n'
189
 
                              'Committed revision 1\.\n$')
 
235
                              'added hello\\.txt\n'
 
236
                              'Committed revision 1\\.\n$')
190
237
 
191
238
    def test_verbose_commit_with_unchanged(self):
192
239
        """Unchanged files should not be listed by default in verbose output"""
195
242
        tree.add('unchanged.txt')
196
243
        self.run_bzr('commit -m unchanged unchanged.txt')
197
244
        tree.add("hello.txt")
198
 
        out,err = self.run_bzr('commit -m added')
 
245
        out, err = self.run_bzr('commit -m added')
199
246
        self.assertEqual('', out)
200
247
        self.assertContainsRe(err, '^Committing to: .*\n'
201
 
                              'added hello\.txt\n'
202
 
                              'Committed revision 2\.$\n')
 
248
                              'added hello\\.txt\n'
 
249
                              'Committed revision 2\\.$\n')
203
250
 
204
251
    def test_verbose_commit_includes_master_location(self):
205
252
        """Location of master is displayed when committing to bound branch"""
216
263
 
217
264
    def test_commit_sanitizes_CR_in_message(self):
218
265
        # See bug #433779, basically Emacs likes to pass '\r\n' style line
219
 
        # endings to 'bzr commit -m ""' which breaks because we don't allow
 
266
        # endings to 'brz commit -m ""' which breaks because we don't allow
220
267
        # '\r' in commit messages. (Mostly because of issues where XML style
221
268
        # formats arbitrarily strip it out of the data while parsing.)
222
269
        # To make life easier for users, we just always translate '\r\n' =>
234
281
 
235
282
    def test_commit_merge_reports_all_modified_files(self):
236
283
        # the commit command should show all the files that are shown by
237
 
        # bzr diff or bzr status when committing, even when they were not
 
284
        # brz diff or brz status when committing, even when they were not
238
285
        # changed by the user but rather through doing a merge.
239
286
        this_tree = self.make_branch_and_tree('this')
240
287
        # we need a bunch of files and dirs, to perform one action on each.
261
308
            'filetoleave']
262
309
            )
263
310
        this_tree.commit('create_files')
264
 
        other_dir = this_tree.bzrdir.sprout('other')
 
311
        other_dir = this_tree.controldir.sprout('other')
265
312
        other_tree = other_dir.open_workingtree()
266
 
        other_tree.lock_write()
267
 
        # perform the needed actions on the files and dirs.
268
 
        try:
 
313
        with other_tree.lock_write():
 
314
            # perform the needed actions on the files and dirs.
269
315
            other_tree.rename_one('dirtorename', 'renameddir')
270
316
            other_tree.rename_one('dirtoreparent', 'renameddir/reparenteddir')
271
317
            other_tree.rename_one('filetorename', 'renamedfile')
274
320
            other_tree.remove(['dirtoremove', 'filetoremove'])
275
321
            self.build_tree_contents([
276
322
                ('other/newdir/',),
277
 
                ('other/filetomodify', 'new content'),
278
 
                ('other/newfile', 'new file content')])
 
323
                ('other/filetomodify', b'new content'),
 
324
                ('other/newfile', b'new file content')])
279
325
            other_tree.add('newfile')
280
326
            other_tree.add('newdir/')
281
327
            other_tree.commit('modify all sample files and dirs.')
282
 
        finally:
283
 
            other_tree.unlock()
284
328
        this_tree.merge_from_branch(other_tree.branch)
285
 
        os.chdir('this')
286
 
        out,err = self.run_bzr('commit -m added')
 
329
        out, err = self.run_bzr('commit -m added', working_dir='this')
287
330
        self.assertEqual('', out)
288
 
        self.assertEqual(set([
289
 
            'Committing to: %s/' % osutils.getcwd(),
 
331
        self.assertEqual({
 
332
            'Committing to: %s/' % osutils.pathjoin(osutils.getcwd(), 'this'),
290
333
            'modified filetomodify',
291
334
            'added newdir',
292
335
            'added newfile',
298
341
            'deleted filetoremove',
299
342
            'Committed revision 2.',
300
343
            ''
301
 
            ]), set(err.split('\n')))
 
344
            }, set(err.split('\n')))
302
345
 
303
346
    def test_empty_commit_message(self):
304
347
        tree = self.make_branch_and_tree('.')
305
 
        self.build_tree_contents([('foo.c', 'int main() {}')])
306
 
        tree.add('foo.c')
307
 
        self.run_bzr('commit -m ""', retcode=3)
308
 
 
309
 
    def test_unsupported_encoding_commit_message(self):
310
 
        if sys.platform == 'win32':
311
 
            raise tests.TestNotApplicable('Win32 parses arguments directly'
312
 
                ' as Unicode, so we can\'t pass invalid non-ascii')
313
 
        tree = self.make_branch_and_tree('.')
314
 
        self.build_tree_contents([('foo.c', 'int main() {}')])
315
 
        tree.add('foo.c')
316
 
        # LANG env variable has no effect on Windows
317
 
        # but some characters anyway cannot be represented
318
 
        # in default user encoding
319
 
        char = probe_bad_non_ascii(osutils.get_user_encoding())
320
 
        if char is None:
321
 
            raise TestSkipped('Cannot find suitable non-ascii character'
322
 
                'for user_encoding (%s)' % osutils.get_user_encoding())
323
 
        out,err = self.run_bzr_subprocess('commit -m "%s"' % char,
324
 
                                          retcode=1,
325
 
                                          env_changes={'LANG': 'C'})
326
 
        self.assertContainsRe(err, r'bzrlib.errors.BzrError: Parameter.*is '
327
 
                                    'unsupported by the current encoding.')
 
348
        self.build_tree_contents([('foo.c', b'int main() {}')])
 
349
        tree.add('foo.c')
 
350
        self.run_bzr('commit -m ""')
328
351
 
329
352
    def test_other_branch_commit(self):
330
353
        # this branch is to ensure consistent behaviour, whether we're run
332
355
        outer_tree = self.make_branch_and_tree('.')
333
356
        inner_tree = self.make_branch_and_tree('branch')
334
357
        self.build_tree_contents([
335
 
            ('branch/foo.c', 'int main() {}'),
336
 
            ('branch/bar.c', 'int main() {}')])
 
358
            ('branch/foo.c', b'int main() {}'),
 
359
            ('branch/bar.c', b'int main() {}')])
337
360
        inner_tree.add(['foo.c', 'bar.c'])
338
361
        # can't commit files in different trees; sane error
339
362
        self.run_bzr('commit -m newstuff branch/foo.c .', retcode=3)
342
365
        # can commit to branch - records bar.c
343
366
        self.run_bzr('commit -m newstuff branch')
344
367
        # No changes left
345
 
        self.run_bzr_error(["No changes to commit"], 'commit -m newstuff branch')
 
368
        self.run_bzr_error(["No changes to commit"],
 
369
                           'commit -m newstuff branch')
346
370
 
347
371
    def test_out_of_date_tree_commit(self):
348
372
        # check we get an error code and a clear message committing with an out
353
377
        # commit to the original branch to make the checkout out of date
354
378
        tree.commit('message branch', allow_pointless=True)
355
379
        # now commit to the checkout should emit
356
 
        # ERROR: Out of date with the branch, 'bzr update' is suggested
 
380
        # ERROR: Out of date with the branch, 'brz update' is suggested
357
381
        output = self.run_bzr('commit --unchanged -m checkout_message '
358
 
                             'checkout', retcode=3)
 
382
                              'checkout', retcode=3)
359
383
        self.assertEqual(output,
360
384
                         ('',
361
 
                          "bzr: ERROR: Working tree is out of date, please "
362
 
                          "run 'bzr update'.\n"))
 
385
                          "brz: ERROR: Working tree is out of date, please "
 
386
                          "run 'brz update'.\n"))
363
387
 
364
388
    def test_local_commit_unbound(self):
365
389
        # a --local commit on an unbound branch is an error
366
390
        self.make_branch_and_tree('.')
367
391
        out, err = self.run_bzr('commit --local', retcode=3)
368
392
        self.assertEqualDiff('', out)
369
 
        self.assertEqualDiff('bzr: ERROR: Cannot perform local-only commits '
 
393
        self.assertEqualDiff('brz: ERROR: Cannot perform local-only commits '
370
394
                             'on unbound branches.\n', err)
371
395
 
372
396
    def test_commit_a_text_merge_in_a_checkout(self):
378
402
        trunk = self.make_branch_and_tree('trunk')
379
403
 
380
404
        u1 = trunk.branch.create_checkout('u1')
381
 
        self.build_tree_contents([('u1/hosts', 'initial contents\n')])
 
405
        self.build_tree_contents([('u1/hosts', b'initial contents\n')])
382
406
        u1.add('hosts')
383
407
        self.run_bzr('commit -m add-hosts u1')
384
408
 
385
409
        u2 = trunk.branch.create_checkout('u2')
386
 
        self.build_tree_contents([('u2/hosts', 'altered in u2\n')])
 
410
        self.build_tree_contents([('u2/hosts', b'altered in u2\n')])
387
411
        self.run_bzr('commit -m checkin-from-u2 u2')
388
412
 
389
413
        # make an offline commits
390
 
        self.build_tree_contents([('u1/hosts', 'first offline change in u1\n')])
 
414
        self.build_tree_contents(
 
415
            [('u1/hosts', b'first offline change in u1\n')])
391
416
        self.run_bzr('commit -m checkin-offline --local u1')
392
417
 
393
418
        # now try to pull in online work from u2, and then commit our offline
394
419
        # work as a merge
395
420
        # retcode 1 as we expect a text conflict
396
421
        self.run_bzr('update u1', retcode=1)
397
 
        self.assertFileEqual('''\
 
422
        self.assertFileEqual(b'''\
398
423
<<<<<<< TREE
399
424
first offline change in u1
400
425
=======
407
432
        # add a text change here to represent resolving the merge conflicts in
408
433
        # favour of a new version of the file not identical to either the u1
409
434
        # version or the u2 version.
410
 
        self.build_tree_contents([('u1/hosts', 'merge resolution\n')])
 
435
        self.build_tree_contents([('u1/hosts', b'merge resolution\n')])
411
436
        self.run_bzr('commit -m checkin-merge-of-the-offline-work-from-u1 u1')
412
437
 
413
438
    def test_commit_exclude_excludes_modified_files(self):
446
471
        t.add(['file-a', 'dir-a', 'dir-a/file-b'])
447
472
        t.commit('Create')
448
473
        t.remove(['file-a', 'dir-a/file-b'])
449
 
        os.chdir('dir-a')
450
 
        result = self.run_bzr('commit . -m removed-file-b')[1]
 
474
        result = self.run_bzr('commit . -m removed-file-b',
 
475
                              working_dir='dir-a')[1]
451
476
        self.assertNotContainsRe(result, 'file-a')
452
 
        result = self.run_bzr('status')[0]
 
477
        result = self.run_bzr('status', working_dir='dir-a')[0]
453
478
        self.assertContainsRe(result, 'removed:\n  file-a')
454
479
 
455
480
    def test_strict_commit(self):
459
484
        self.build_tree(['tree/a'])
460
485
        tree.add('a')
461
486
        # A simple change should just work
462
 
        self.run_bzr('commit --strict -m adding-a',
463
 
                     working_dir='tree')
 
487
        self.run_bzr('commit --strict -m adding-a', working_dir='tree')
464
488
 
465
489
    def test_strict_commit_no_changes(self):
466
490
        """commit --strict gives "no changes" if there is nothing to commit"""
506
530
            'commit -m hello --fixes=lp:23452 tree/hello.txt')
507
531
        self.assertEqual('', output)
508
532
        self.assertContainsRe(err, 'Committing to: .*\n'
509
 
                              'added hello\.txt\n'
510
 
                              'Committed revision 1\.\n')
 
533
                              'added hello\\.txt\n'
 
534
                              'Committed revision 1\\.\n')
 
535
 
 
536
    def test_fixes_bug_unicode(self):
 
537
        """commit --fixes=lp:unicode succeeds without output."""
 
538
        tree = self.make_branch_and_tree('tree')
 
539
        self.build_tree(['tree/hello.txt'])
 
540
        tree.add('hello.txt')
 
541
        output, err = self.run_bzr_raw(
 
542
            ['commit', '-m', 'hello',
 
543
             u'--fixes=generic:\u20ac', 'tree/hello.txt'],
 
544
            encoding='utf-8', retcode=3)
 
545
        self.assertEqual(b'', output)
 
546
        self.assertContainsRe(err,
 
547
                              b'brz: ERROR: Unrecognized bug generic:\xe2\x82\xac\\. Commit refused.\n')
511
548
 
512
549
    def test_no_bugs_no_properties(self):
513
550
        """If no bugs are fixed, the bugs property is not set.
517
554
        tree = self.make_branch_and_tree('tree')
518
555
        self.build_tree(['tree/hello.txt'])
519
556
        tree.add('hello.txt')
520
 
        self.run_bzr( 'commit -m hello tree/hello.txt')
 
557
        self.run_bzr('commit -m hello tree/hello.txt')
521
558
        # Get the revision properties, ignoring the branch-nick property, which
522
559
        # we don't care about for this test.
523
560
        last_rev = tree.branch.repository.get_revision(tree.last_revision())
525
562
        del properties['branch-nick']
526
563
        self.assertFalse('bugs' in properties)
527
564
 
 
565
    def test_bugs_sets_property(self):
 
566
        """commit --bugs=lp:234 sets the lp:234 revprop to 'related'."""
 
567
        tree = self.make_branch_and_tree('tree')
 
568
        self.build_tree(['tree/hello.txt'])
 
569
        tree.add('hello.txt')
 
570
        self.run_bzr('commit -m hello --bugs=lp:234 tree/hello.txt')
 
571
 
 
572
        # Get the revision properties, ignoring the branch-nick property, which
 
573
        # we don't care about for this test.
 
574
        last_rev = tree.branch.repository.get_revision(tree.last_revision())
 
575
        properties = dict(last_rev.properties)
 
576
        del properties[u'branch-nick']
 
577
 
 
578
        self.assertEqual({u'bugs': 'https://launchpad.net/bugs/234 related'},
 
579
                         properties)
 
580
 
528
581
    def test_fixes_bug_sets_property(self):
529
582
        """commit --fixes=lp:234 sets the lp:234 revprop to 'fixed'."""
530
583
        tree = self.make_branch_and_tree('tree')
536
589
        # we don't care about for this test.
537
590
        last_rev = tree.branch.repository.get_revision(tree.last_revision())
538
591
        properties = dict(last_rev.properties)
539
 
        del properties['branch-nick']
 
592
        del properties[u'branch-nick']
540
593
 
541
 
        self.assertEqual({'bugs': 'https://launchpad.net/bugs/234 fixed'},
 
594
        self.assertEqual({u'bugs': 'https://launchpad.net/bugs/234 fixed'},
542
595
                         properties)
543
596
 
544
597
    def test_fixes_multiple_bugs_sets_properties(self):
556
609
        del properties['branch-nick']
557
610
 
558
611
        self.assertEqual(
559
 
            {'bugs': 'https://launchpad.net/bugs/123 fixed\n'
560
 
                     'https://launchpad.net/bugs/235 fixed'},
 
612
            {u'bugs': 'https://launchpad.net/bugs/123 fixed\n'
 
613
             'https://launchpad.net/bugs/235 fixed'},
561
614
            properties)
562
615
 
563
616
    def test_fixes_bug_with_alternate_trackers(self):
569
622
            'trac_twisted_url', 'http://twistedmatrix.com/trac')
570
623
        self.build_tree(['tree/hello.txt'])
571
624
        tree.add('hello.txt')
572
 
        self.run_bzr('commit -m hello --fixes=lp:123 --fixes=twisted:235 tree/')
 
625
        self.run_bzr(
 
626
            'commit -m hello --fixes=lp:123 --fixes=twisted:235 tree/')
573
627
 
574
628
        # Get the revision properties, ignoring the branch-nick property, which
575
629
        # we don't care about for this test.
591
645
            'commit -m add-b --fixes=xxx:123',
592
646
            working_dir='tree')
593
647
 
 
648
    def test_fixes_bug_with_default_tracker(self):
 
649
        """commit --fixes=234 uses the default bug tracker."""
 
650
        tree = self.make_branch_and_tree('tree')
 
651
        self.build_tree(['tree/hello.txt'])
 
652
        tree.add('hello.txt')
 
653
        self.run_bzr_error(
 
654
            ["brz: ERROR: No tracker specified for bug 123. Use the form "
 
655
             "'tracker:id' or specify a default bug tracker using the "
 
656
             "`bugtracker` option.\n"
 
657
             "See \"brz help bugs\" for more information on this feature. "
 
658
             "Commit refused."],
 
659
            'commit -m add-b --fixes=123',
 
660
            working_dir='tree')
 
661
        tree.branch.get_config_stack().set("bugtracker", "lp")
 
662
        self.run_bzr('commit -m hello --fixes=234 tree/hello.txt')
 
663
        last_rev = tree.branch.repository.get_revision(tree.last_revision())
 
664
        self.assertEqual('https://launchpad.net/bugs/234 fixed',
 
665
                         last_rev.properties['bugs'])
 
666
 
594
667
    def test_fixes_invalid_bug_number(self):
595
668
        tree = self.make_branch_and_tree('tree')
596
669
        self.build_tree(['tree/hello.txt'])
597
670
        tree.add('hello.txt')
598
671
        self.run_bzr_error(
599
672
            ["Did not understand bug identifier orange: Must be an integer. "
600
 
             "See \"bzr help bugs\" for more information on this feature.\n"
 
673
             "See \"brz help bugs\" for more information on this feature.\n"
601
674
             "Commit refused."],
602
675
            'commit -m add-b --fixes=lp:orange',
603
676
            working_dir='tree')
608
681
        self.build_tree(['tree/hello.txt'])
609
682
        tree.add('hello.txt')
610
683
        self.run_bzr_error(
611
 
            [r"Invalid bug orange. Must be in the form of 'tracker:id'\. "
612
 
             r"See \"bzr help bugs\" for more information on this feature.\n"
613
 
             r"Commit refused\."],
614
 
            'commit -m add-b --fixes=orange',
 
684
            [r"Invalid bug orange:apples:bananas. Must be in the form of "
 
685
             r"'tracker:id'\. See \"brz help bugs\" for more information on "
 
686
             r"this feature.\nCommit refused\."],
 
687
            'commit -m add-b --fixes=orange:apples:bananas',
615
688
            working_dir='tree')
616
689
 
617
690
    def test_no_author(self):
619
692
        tree = self.make_branch_and_tree('tree')
620
693
        self.build_tree(['tree/hello.txt'])
621
694
        tree.add('hello.txt')
622
 
        self.run_bzr( 'commit -m hello tree/hello.txt')
 
695
        self.run_bzr('commit -m hello tree/hello.txt')
623
696
        last_rev = tree.branch.repository.get_revision(tree.last_revision())
624
697
        properties = last_rev.properties
625
698
        self.assertFalse('author' in properties)
633
706
        tree.add('hello.txt')
634
707
        self.run_bzr(["commit", '-m', 'hello',
635
708
                      '--author', u'John D\xf6 <jdoe@example.com>',
636
 
                     "tree/hello.txt"])
 
709
                      "tree/hello.txt"])
637
710
        last_rev = tree.branch.repository.get_revision(tree.last_revision())
638
711
        properties = last_rev.properties
639
 
        self.assertEqual(u'John D\xf6 <jdoe@example.com>', properties['authors'])
 
712
        self.assertEqual(u'John D\xf6 <jdoe@example.com>',
 
713
                         properties['authors'])
640
714
 
641
715
    def test_author_no_email(self):
642
716
        """Author's name without an email address is allowed, too."""
665
739
        self.build_tree(['tree/hello.txt'])
666
740
        tree.add('hello.txt')
667
741
        out, err = self.run_bzr("commit -m hello "
668
 
            "--commit-time='2009-10-10 08:00:00 +0100' tree/hello.txt")
 
742
                                "--commit-time='2009-10-10 08:00:00 +0100' tree/hello.txt")
669
743
        last_rev = tree.branch.repository.get_revision(tree.last_revision())
670
744
        self.assertEqual(
671
745
            'Sat 2009-10-10 08:00:00 +0100',
672
746
            osutils.format_date(last_rev.timestamp, last_rev.timezone))
673
 
        
 
747
 
674
748
    def test_commit_time_bad_time(self):
675
749
        tree = self.make_branch_and_tree('tree')
676
750
        self.build_tree(['tree/hello.txt'])
677
751
        tree.add('hello.txt')
678
752
        out, err = self.run_bzr("commit -m hello "
679
 
            "--commit-time='NOT A TIME' tree/hello.txt", retcode=3)
680
 
        self.assertStartsWith(
681
 
            err, "bzr: ERROR: Could not parse --commit-time:")
 
753
                                "--commit-time='NOT A TIME' tree/hello.txt", retcode=3)
 
754
        self.assertStartsWith(
 
755
            err, "brz: ERROR: Could not parse --commit-time:")
 
756
 
 
757
    def test_commit_time_missing_tz(self):
 
758
        tree = self.make_branch_and_tree('tree')
 
759
        self.build_tree(['tree/hello.txt'])
 
760
        tree.add('hello.txt')
 
761
        out, err = self.run_bzr("commit -m hello "
 
762
                                "--commit-time='2009-10-10 08:00:00' tree/hello.txt", retcode=3)
 
763
        self.assertStartsWith(
 
764
            err, "brz: ERROR: Could not parse --commit-time:")
 
765
        # Test that it is actually checking and does not simply crash with
 
766
        # some other exception
 
767
        self.assertContainsString(err, "missing a timezone offset")
682
768
 
683
769
    def test_partial_commit_with_renames_in_tree(self):
684
770
        # this test illustrates bug #140419
691
777
        # then during partial commit we have error
692
778
        # parent_id {dir-XXX} not in inventory
693
779
        t.rename_one('dir/a', 'a')
694
 
        self.build_tree_contents([('test', 'changes in test')])
 
780
        self.build_tree_contents([('test', b'changes in test')])
695
781
        # partial commit
696
782
        out, err = self.run_bzr('commit test -m "partial commit"')
697
 
        self.assertEquals('', out)
 
783
        self.assertEqual('', out)
698
784
        self.assertContainsRe(err, r'modified test\nCommitted revision 2.')
699
785
 
700
786
    def test_commit_readonly_checkout(self):
701
 
        # https://bugs.edge.launchpad.net/bzr/+bug/129701
 
787
        # https://bugs.launchpad.net/bzr/+bug/129701
702
788
        # "UnlockableTransport error trying to commit in checkout of readonly
703
789
        # branch"
704
790
        self.make_branch('master')
705
 
        master = BzrDir.open_from_transport(
 
791
        master = ControlDir.open_from_transport(
706
792
            self.get_readonly_transport('master')).open_branch()
707
793
        master.create_checkout('checkout')
708
794
        out, err = self.run_bzr(['commit', '--unchanged', '-mfoo', 'checkout'],
709
 
            retcode=3)
 
795
                                retcode=3)
710
796
        self.assertContainsRe(err,
711
 
            r'^bzr: ERROR: Cannot lock.*readonly transport')
 
797
                              r'^brz: ERROR: Cannot lock.*readonly transport')
712
798
 
713
799
    def setup_editor(self):
714
800
        # Test that commit template hooks work
715
801
        if sys.platform == "win32":
716
 
            f = file('fed.bat', 'w')
717
 
            f.write('@rem dummy fed')
718
 
            f.close()
719
 
            osutils.set_or_unset_env('BZR_EDITOR', "fed.bat")
 
802
            with open('fed.bat', 'w') as f:
 
803
                f.write('@rem dummy fed')
 
804
            self.overrideEnv('BRZ_EDITOR', "fed.bat")
720
805
        else:
721
 
            f = file('fed.sh', 'wb')
722
 
            f.write('#!/bin/sh\n')
723
 
            f.close()
724
 
            os.chmod('fed.sh', 0755)
725
 
            osutils.set_or_unset_env('BZR_EDITOR', "./fed.sh")
 
806
            with open('fed.sh', 'wb') as f:
 
807
                f.write(b'#!/bin/sh\n')
 
808
            os.chmod('fed.sh', 0o755)
 
809
            self.overrideEnv('BRZ_EDITOR', "./fed.sh")
726
810
 
727
811
    def setup_commit_with_template(self):
728
812
        self.setup_editor()
729
813
        msgeditor.hooks.install_named_hook("commit_message_template",
730
 
                lambda commit_obj, msg: "save me some typing\n", None)
 
814
                                           lambda commit_obj, msg: "save me some typing\n", None)
731
815
        tree = self.make_branch_and_tree('tree')
732
816
        self.build_tree(['tree/hello.txt'])
733
817
        tree.add('hello.txt')
734
818
        return tree
735
819
 
 
820
    def test_edit_empty_message(self):
 
821
        tree = self.make_branch_and_tree('tree')
 
822
        self.setup_editor()
 
823
        self.build_tree(['tree/hello.txt'])
 
824
        tree.add('hello.txt')
 
825
        out, err = self.run_bzr("commit tree/hello.txt", retcode=3,
 
826
                                stdin="y\n")
 
827
        self.assertContainsRe(err,
 
828
                              "brz: ERROR: Empty commit message specified")
 
829
 
736
830
    def test_commit_hook_template_accepted(self):
737
831
        tree = self.setup_commit_with_template()
738
832
        out, err = self.run_bzr("commit tree/hello.txt", stdin="y\n")
742
836
    def test_commit_hook_template_rejected(self):
743
837
        tree = self.setup_commit_with_template()
744
838
        expected = tree.last_revision()
745
 
        out, err = self.run_bzr_error(["empty commit message"],
746
 
            "commit tree/hello.txt", stdin="n\n")
 
839
        out, err = self.run_bzr_error(["Empty commit message specified."
 
840
                                       " Please specify a commit message with either"
 
841
                                       " --message or --file or leave a blank message"
 
842
                                       " with --message \"\"."],
 
843
                                      "commit tree/hello.txt", stdin="n\n")
747
844
        self.assertEqual(expected, tree.last_revision())
748
845
 
 
846
    def test_set_commit_message(self):
 
847
        msgeditor.hooks.install_named_hook("set_commit_message",
 
848
                                           lambda commit_obj, msg: "save me some typing\n", None)
 
849
        tree = self.make_branch_and_tree('tree')
 
850
        self.build_tree(['tree/hello.txt'])
 
851
        tree.add('hello.txt')
 
852
        out, err = self.run_bzr("commit tree/hello.txt")
 
853
        last_rev = tree.branch.repository.get_revision(tree.last_revision())
 
854
        self.assertEqual('save me some typing\n', last_rev.message)
 
855
 
749
856
    def test_commit_without_username(self):
750
857
        """Ensure commit error if username is not set.
751
858
        """
752
859
        self.run_bzr(['init', 'foo'])
753
 
        os.chdir('foo')
754
 
        open('foo.txt', 'w').write('hello')
755
 
        self.run_bzr(['add'])
756
 
        osutils.set_or_unset_env('EMAIL', None)
757
 
        osutils.set_or_unset_env('BZR_EMAIL', None)
758
 
        out, err = self.run_bzr(['commit', '-m', 'initial'], 3)
759
 
        self.assertContainsRe(err, 'Unable to determine your name')
 
860
        with open('foo/foo.txt', 'w') as f:
 
861
            f.write('hello')
 
862
        self.run_bzr(['add'], working_dir='foo')
 
863
        override_whoami(self)
 
864
        self.run_bzr_error(
 
865
            ['Unable to determine your name'],
 
866
            ['commit', '-m', 'initial'], working_dir='foo')
 
867
 
 
868
    def test_commit_recursive_checkout(self):
 
869
        """Ensure that a commit to a recursive checkout fails cleanly.
 
870
        """
 
871
        self.run_bzr(['init', 'test_branch'])
 
872
        self.run_bzr(['checkout', 'test_branch', 'test_checkout'])
 
873
        # bind to self
 
874
        self.run_bzr(['bind', '.'], working_dir='test_checkout')
 
875
        with open('test_checkout/foo.txt', 'w') as f:
 
876
            f.write('hello')
 
877
        self.run_bzr(['add'], working_dir='test_checkout')
 
878
        out, err = self.run_bzr_error(
 
879
            ['Branch.*test_checkout.*appears to be bound to itself'],
 
880
            ['commit', '-m', 'addedfoo'], working_dir='test_checkout')
 
881
 
 
882
    def test_mv_dirs_non_ascii(self):
 
883
        """Move directory with non-ascii name and containing files.
 
884
 
 
885
        Regression test for bug 185211.
 
886
        """
 
887
        tree = self.make_branch_and_tree('.')
 
888
        self.build_tree([u'abc\xa7/', u'abc\xa7/foo'])
 
889
 
 
890
        tree.add([u'abc\xa7/', u'abc\xa7/foo'])
 
891
        tree.commit('checkin')
 
892
 
 
893
        tree.rename_one(u'abc\xa7', 'abc')
 
894
 
 
895
        self.run_bzr('ci -m "non-ascii mv"')
 
896