/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 bzrlib/tests/test_commit.py

  • Committer: Robert Collins
  • Date: 2007-04-19 02:27:44 UTC
  • mto: This revision was merged to the branch mainline in revision 2426.
  • Revision ID: robertc@robertcollins.net-20070419022744-pfdqz42kp1wizh43
``make docs`` now creates a man page at ``man1/bzr.1`` fixing bug 107388.
(Robert Collins)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2012, 2016 Canonical Ltd
 
1
# Copyright (C) 2005, 2006 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
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
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
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
17
17
 
18
18
import os
19
 
from io import BytesIO
20
19
 
21
 
import breezy
22
 
from .. import (
23
 
    config,
24
 
    controldir,
 
20
import bzrlib
 
21
from bzrlib import (
25
22
    errors,
26
 
    trace,
27
 
    )
28
 
from ..branch import Branch
29
 
from ..bzr.bzrdir import BzrDirMetaFormat1
30
 
from ..commit import (
31
 
    CannotCommitSelectedFileMerge,
32
 
    Commit,
33
 
    NullCommitReporter,
34
 
    PointlessCommit,
35
 
    filter_excluded,
36
 
    )
37
 
from ..errors import (
38
 
    BzrError,
39
 
    LockContention,
40
 
    )
41
 
from ..bzr.inventorytree import InventoryTreeChange
42
 
from . import (
43
 
    TestCase,
44
 
    TestCaseWithTransport,
45
 
    test_foreign,
46
 
    )
47
 
from .features import (
48
 
    SymlinkFeature,
49
 
    )
50
 
from .matchers import MatchesAncestry
 
23
    lockdir,
 
24
    osutils,
 
25
    tests,
 
26
    )
 
27
from bzrlib.branch import Branch
 
28
from bzrlib.bzrdir import BzrDir, BzrDirMetaFormat1
 
29
from bzrlib.commit import Commit, NullCommitReporter
 
30
from bzrlib.config import BranchConfig
 
31
from bzrlib.errors import (PointlessCommit, BzrError, SigningFailed, 
 
32
                           LockContention)
 
33
from bzrlib.tests import TestCaseWithTransport
 
34
from bzrlib.workingtree import WorkingTree
51
35
 
52
36
 
53
37
# TODO: Test commit with some added, and added-but-missing files
54
38
 
55
 
class MustSignConfig(config.MemoryStack):
56
 
 
57
 
    def __init__(self):
58
 
        super(MustSignConfig, self).__init__(b'''
59
 
create_signatures=always
60
 
''')
 
39
class MustSignConfig(BranchConfig):
 
40
 
 
41
    def signature_needed(self):
 
42
        return True
 
43
 
 
44
    def gpg_signing_command(self):
 
45
        return ['cat', '-']
 
46
 
 
47
 
 
48
class BranchWithHooks(BranchConfig):
 
49
 
 
50
    def post_commit(self):
 
51
        return "bzrlib.ahook bzrlib.ahook"
61
52
 
62
53
 
63
54
class CapturingReporter(NullCommitReporter):
79
70
    def renamed(self, change, old_path, new_path):
80
71
        self.calls.append(('renamed', change, old_path, new_path))
81
72
 
82
 
    def is_verbose(self):
83
 
        return True
84
 
 
85
73
 
86
74
class TestCommit(TestCaseWithTransport):
87
75
 
89
77
        """Commit and check two versions of a single file."""
90
78
        wt = self.make_branch_and_tree('.')
91
79
        b = wt.branch
92
 
        with open('hello', 'w') as f:
93
 
            f.write('hello world')
 
80
        file('hello', 'w').write('hello world')
94
81
        wt.add('hello')
95
 
        rev1 = wt.commit(message='add hello')
96
 
 
97
 
        with open('hello', 'w') as f:
98
 
            f.write('version 2')
99
 
        rev2 = wt.commit(message='commit 2')
100
 
 
101
 
        eq = self.assertEqual
 
82
        wt.commit(message='add hello')
 
83
        file_id = wt.path2id('hello')
 
84
 
 
85
        file('hello', 'w').write('version 2')
 
86
        wt.commit(message='commit 2')
 
87
 
 
88
        eq = self.assertEquals
102
89
        eq(b.revno(), 2)
103
 
        rev = b.repository.get_revision(rev1)
 
90
        rh = b.revision_history()
 
91
        rev = b.repository.get_revision(rh[0])
104
92
        eq(rev.message, 'add hello')
105
93
 
106
 
        tree1 = b.repository.revision_tree(rev1)
107
 
        tree1.lock_read()
108
 
        text = tree1.get_file_text('hello')
109
 
        tree1.unlock()
110
 
        self.assertEqual(b'hello world', text)
111
 
 
112
 
        tree2 = b.repository.revision_tree(rev2)
113
 
        tree2.lock_read()
114
 
        text = tree2.get_file_text('hello')
115
 
        tree2.unlock()
116
 
        self.assertEqual(b'version 2', text)
117
 
 
118
 
    def test_commit_lossy_native(self):
119
 
        """Attempt a lossy commit to a native branch."""
120
 
        wt = self.make_branch_and_tree('.')
121
 
        b = wt.branch
122
 
        with open('hello', 'w') as f:
123
 
            f.write('hello world')
124
 
        wt.add('hello')
125
 
        revid = wt.commit(message='add hello', rev_id=b'revid', lossy=True)
126
 
        self.assertEqual(b'revid', revid)
127
 
 
128
 
    def test_commit_lossy_foreign(self):
129
 
        """Attempt a lossy commit to a foreign branch."""
130
 
        test_foreign.register_dummy_foreign_for_test(self)
131
 
        wt = self.make_branch_and_tree('.',
132
 
                                       format=test_foreign.DummyForeignVcsDirFormat())
133
 
        b = wt.branch
134
 
        with open('hello', 'w') as f:
135
 
            f.write('hello world')
136
 
        wt.add('hello')
137
 
        revid = wt.commit(message='add hello', lossy=True,
138
 
                          timestamp=1302659388, timezone=0)
139
 
        self.assertEqual(b'dummy-v1:1302659388-0-UNKNOWN', revid)
140
 
 
141
 
    def test_commit_bound_lossy_foreign(self):
142
 
        """Attempt a lossy commit to a bzr branch bound to a foreign branch."""
143
 
        test_foreign.register_dummy_foreign_for_test(self)
144
 
        foreign_branch = self.make_branch('foreign',
145
 
                                          format=test_foreign.DummyForeignVcsDirFormat())
146
 
        wt = foreign_branch.create_checkout("local")
147
 
        b = wt.branch
148
 
        with open('local/hello', 'w') as f:
149
 
            f.write('hello world')
150
 
        wt.add('hello')
151
 
        revid = wt.commit(message='add hello', lossy=True,
152
 
                          timestamp=1302659388, timezone=0)
153
 
        self.assertEqual(b'dummy-v1:1302659388-0-0', revid)
154
 
        self.assertEqual(b'dummy-v1:1302659388-0-0',
155
 
                         foreign_branch.last_revision())
156
 
        self.assertEqual(b'dummy-v1:1302659388-0-0',
157
 
                         wt.branch.last_revision())
158
 
 
159
 
    def test_missing_commit(self):
160
 
        """Test a commit with a missing file"""
161
 
        wt = self.make_branch_and_tree('.')
162
 
        b = wt.branch
163
 
        with open('hello', 'w') as f:
164
 
            f.write('hello world')
165
 
        wt.add(['hello'], [b'hello-id'])
 
94
        tree1 = b.repository.revision_tree(rh[0])
 
95
        text = tree1.get_file_text(file_id)
 
96
        eq(text, 'hello world')
 
97
 
 
98
        tree2 = b.repository.revision_tree(rh[1])
 
99
        eq(tree2.get_file_text(file_id), 'version 2')
 
100
 
 
101
    def test_delete_commit(self):
 
102
        """Test a commit with a deleted file"""
 
103
        wt = self.make_branch_and_tree('.')
 
104
        b = wt.branch
 
105
        file('hello', 'w').write('hello world')
 
106
        wt.add(['hello'], ['hello-id'])
166
107
        wt.commit(message='add hello')
167
108
 
168
109
        os.remove('hello')
169
 
        reporter = CapturingReporter()
170
 
        wt.commit('removed hello', rev_id=b'rev2', reporter=reporter)
171
 
        self.assertEqual(
172
 
            [('missing', u'hello'), ('deleted', u'hello')],
173
 
            reporter.calls)
174
 
 
175
 
        tree = b.repository.revision_tree(b'rev2')
176
 
        self.assertFalse(tree.has_filename('hello'))
177
 
 
178
 
    def test_partial_commit_move(self):
179
 
        """Test a partial commit where a file was renamed but not committed.
180
 
 
181
 
        https://bugs.launchpad.net/bzr/+bug/83039
182
 
 
183
 
        If not handled properly, commit will try to snapshot
184
 
        dialog.py with olive/ as a parent, while
185
 
        olive/ has not been snapshotted yet.
186
 
        """
187
 
        wt = self.make_branch_and_tree('.')
188
 
        b = wt.branch
189
 
        self.build_tree(['annotate/', 'annotate/foo.py',
190
 
                         'olive/', 'olive/dialog.py'
191
 
                         ])
192
 
        wt.add(['annotate', 'olive', 'annotate/foo.py', 'olive/dialog.py'])
193
 
        wt.commit(message='add files')
194
 
        wt.rename_one("olive/dialog.py", "aaa")
195
 
        self.build_tree_contents([('annotate/foo.py', b'modified\n')])
196
 
        wt.commit('renamed hello', specific_files=["annotate"])
 
110
        wt.commit('removed hello', rev_id='rev2')
 
111
 
 
112
        tree = b.repository.revision_tree('rev2')
 
113
        self.assertFalse(tree.has_id('hello-id'))
197
114
 
198
115
    def test_pointless_commit(self):
199
116
        """Commit refuses unless there are changes or it's forced."""
200
117
        wt = self.make_branch_and_tree('.')
201
118
        b = wt.branch
202
 
        with open('hello', 'w') as f:
203
 
            f.write('hello')
 
119
        file('hello', 'w').write('hello')
204
120
        wt.add(['hello'])
205
121
        wt.commit(message='add hello')
206
 
        self.assertEqual(b.revno(), 1)
 
122
        self.assertEquals(b.revno(), 1)
207
123
        self.assertRaises(PointlessCommit,
208
124
                          wt.commit,
209
125
                          message='fails',
210
126
                          allow_pointless=False)
211
 
        self.assertEqual(b.revno(), 1)
212
 
 
 
127
        self.assertEquals(b.revno(), 1)
 
128
        
213
129
    def test_commit_empty(self):
214
130
        """Commiting an empty tree works."""
215
131
        wt = self.make_branch_and_tree('.')
220
136
                          message='empty tree',
221
137
                          allow_pointless=False)
222
138
        wt.commit(message='empty tree', allow_pointless=True)
223
 
        self.assertEqual(b.revno(), 2)
 
139
        self.assertEquals(b.revno(), 2)
224
140
 
225
141
    def test_selective_delete(self):
226
142
        """Selective commit in tree with deletions"""
227
143
        wt = self.make_branch_and_tree('.')
228
144
        b = wt.branch
229
 
        with open('hello', 'w') as f:
230
 
            f.write('hello')
231
 
        with open('buongia', 'w') as f:
232
 
            f.write('buongia')
 
145
        file('hello', 'w').write('hello')
 
146
        file('buongia', 'w').write('buongia')
233
147
        wt.add(['hello', 'buongia'],
234
 
               [b'hello-id', b'buongia-id'])
 
148
              ['hello-id', 'buongia-id'])
235
149
        wt.commit(message='add files',
236
 
                  rev_id=b'test@rev-1')
237
 
 
 
150
                 rev_id='test@rev-1')
 
151
        
238
152
        os.remove('hello')
239
 
        with open('buongia', 'w') as f:
240
 
            f.write('new text')
 
153
        file('buongia', 'w').write('new text')
241
154
        wt.commit(message='update text',
242
 
                  specific_files=['buongia'],
243
 
                  allow_pointless=False,
244
 
                  rev_id=b'test@rev-2')
 
155
                 specific_files=['buongia'],
 
156
                 allow_pointless=False,
 
157
                 rev_id='test@rev-2')
245
158
 
246
159
        wt.commit(message='remove hello',
247
 
                  specific_files=['hello'],
248
 
                  allow_pointless=False,
249
 
                  rev_id=b'test@rev-3')
 
160
                 specific_files=['hello'],
 
161
                 allow_pointless=False,
 
162
                 rev_id='test@rev-3')
250
163
 
251
 
        eq = self.assertEqual
 
164
        eq = self.assertEquals
252
165
        eq(b.revno(), 3)
253
166
 
254
 
        tree2 = b.repository.revision_tree(b'test@rev-2')
255
 
        tree2.lock_read()
256
 
        self.addCleanup(tree2.unlock)
 
167
        tree2 = b.repository.revision_tree('test@rev-2')
257
168
        self.assertTrue(tree2.has_filename('hello'))
258
 
        self.assertEqual(tree2.get_file_text('hello'), b'hello')
259
 
        self.assertEqual(tree2.get_file_text('buongia'), b'new text')
260
 
 
261
 
        tree3 = b.repository.revision_tree(b'test@rev-3')
262
 
        tree3.lock_read()
263
 
        self.addCleanup(tree3.unlock)
 
169
        self.assertEquals(tree2.get_file_text('hello-id'), 'hello')
 
170
        self.assertEquals(tree2.get_file_text('buongia-id'), 'new text')
 
171
        
 
172
        tree3 = b.repository.revision_tree('test@rev-3')
264
173
        self.assertFalse(tree3.has_filename('hello'))
265
 
        self.assertEqual(tree3.get_file_text('buongia'), b'new text')
 
174
        self.assertEquals(tree3.get_file_text('buongia-id'), 'new text')
266
175
 
267
176
    def test_commit_rename(self):
268
177
        """Test commit of a revision where a file is renamed."""
269
178
        tree = self.make_branch_and_tree('.')
270
179
        b = tree.branch
271
180
        self.build_tree(['hello'], line_endings='binary')
272
 
        tree.add(['hello'], [b'hello-id'])
273
 
        tree.commit(message='one', rev_id=b'test@rev-1', allow_pointless=False)
 
181
        tree.add(['hello'], ['hello-id'])
 
182
        tree.commit(message='one', rev_id='test@rev-1', allow_pointless=False)
274
183
 
275
184
        tree.rename_one('hello', 'fruity')
276
 
        tree.commit(message='renamed', rev_id=b'test@rev-2',
277
 
                    allow_pointless=False)
 
185
        tree.commit(message='renamed', rev_id='test@rev-2', allow_pointless=False)
278
186
 
279
 
        eq = self.assertEqual
280
 
        tree1 = b.repository.revision_tree(b'test@rev-1')
281
 
        tree1.lock_read()
282
 
        self.addCleanup(tree1.unlock)
283
 
        eq(tree1.id2path(b'hello-id'), 'hello')
284
 
        eq(tree1.get_file_text('hello'), b'contents of hello\n')
 
187
        eq = self.assertEquals
 
188
        tree1 = b.repository.revision_tree('test@rev-1')
 
189
        eq(tree1.id2path('hello-id'), 'hello')
 
190
        eq(tree1.get_file_text('hello-id'), 'contents of hello\n')
285
191
        self.assertFalse(tree1.has_filename('fruity'))
286
 
        self.check_tree_shape(tree1, ['hello'])
287
 
        eq(tree1.get_file_revision('hello'), b'test@rev-1')
 
192
        self.check_inventory_shape(tree1.inventory, ['hello'])
 
193
        ie = tree1.inventory['hello-id']
 
194
        eq(ie.revision, 'test@rev-1')
288
195
 
289
 
        tree2 = b.repository.revision_tree(b'test@rev-2')
290
 
        tree2.lock_read()
291
 
        self.addCleanup(tree2.unlock)
292
 
        eq(tree2.id2path(b'hello-id'), 'fruity')
293
 
        eq(tree2.get_file_text('fruity'), b'contents of hello\n')
294
 
        self.check_tree_shape(tree2, ['fruity'])
295
 
        eq(tree2.get_file_revision('fruity'), b'test@rev-2')
 
196
        tree2 = b.repository.revision_tree('test@rev-2')
 
197
        eq(tree2.id2path('hello-id'), 'fruity')
 
198
        eq(tree2.get_file_text('hello-id'), 'contents of hello\n')
 
199
        self.check_inventory_shape(tree2.inventory, ['fruity'])
 
200
        ie = tree2.inventory['hello-id']
 
201
        eq(ie.revision, 'test@rev-2')
296
202
 
297
203
    def test_reused_rev_id(self):
298
204
        """Test that a revision id cannot be reused in a branch"""
299
205
        wt = self.make_branch_and_tree('.')
300
206
        b = wt.branch
301
 
        wt.commit('initial', rev_id=b'test@rev-1', allow_pointless=True)
 
207
        wt.commit('initial', rev_id='test@rev-1', allow_pointless=True)
302
208
        self.assertRaises(Exception,
303
209
                          wt.commit,
304
210
                          message='reused id',
305
 
                          rev_id=b'test@rev-1',
 
211
                          rev_id='test@rev-1',
306
212
                          allow_pointless=True)
307
213
 
308
214
    def test_commit_move(self):
309
215
        """Test commit of revisions with moved files and directories"""
310
 
        eq = self.assertEqual
 
216
        eq = self.assertEquals
311
217
        wt = self.make_branch_and_tree('.')
312
218
        b = wt.branch
313
 
        r1 = b'test@rev-1'
 
219
        r1 = 'test@rev-1'
314
220
        self.build_tree(['hello', 'a/', 'b/'])
315
 
        wt.add(['hello', 'a', 'b'], [b'hello-id', b'a-id', b'b-id'])
 
221
        wt.add(['hello', 'a', 'b'], ['hello-id', 'a-id', 'b-id'])
316
222
        wt.commit('initial', rev_id=r1, allow_pointless=False)
317
223
        wt.move(['hello'], 'a')
318
 
        r2 = b'test@rev-2'
 
224
        r2 = 'test@rev-2'
319
225
        wt.commit('two', rev_id=r2, allow_pointless=False)
320
226
        wt.lock_read()
321
227
        try:
322
 
            self.check_tree_shape(wt, ['a/', 'a/hello', 'b/'])
 
228
            self.check_inventory_shape(wt.read_working_inventory(),
 
229
                                       ['a', 'a/hello', 'b'])
323
230
        finally:
324
231
            wt.unlock()
325
232
 
326
233
        wt.move(['b'], 'a')
327
 
        r3 = b'test@rev-3'
 
234
        r3 = 'test@rev-3'
328
235
        wt.commit('three', rev_id=r3, allow_pointless=False)
329
236
        wt.lock_read()
330
237
        try:
331
 
            self.check_tree_shape(wt,
332
 
                                  ['a/', 'a/hello', 'a/b/'])
333
 
            self.check_tree_shape(b.repository.revision_tree(r3),
334
 
                                  ['a/', 'a/hello', 'a/b/'])
 
238
            self.check_inventory_shape(wt.read_working_inventory(),
 
239
                                       ['a', 'a/hello', 'a/b'])
 
240
            self.check_inventory_shape(b.repository.get_revision_inventory(r3),
 
241
                                       ['a', 'a/hello', 'a/b'])
335
242
        finally:
336
243
            wt.unlock()
337
244
 
338
245
        wt.move(['a/hello'], 'a/b')
339
 
        r4 = b'test@rev-4'
 
246
        r4 = 'test@rev-4'
340
247
        wt.commit('four', rev_id=r4, allow_pointless=False)
341
248
        wt.lock_read()
342
249
        try:
343
 
            self.check_tree_shape(wt, ['a/', 'a/b/hello', 'a/b/'])
 
250
            self.check_inventory_shape(wt.read_working_inventory(),
 
251
                                       ['a', 'a/b/hello', 'a/b'])
344
252
        finally:
345
253
            wt.unlock()
346
254
 
347
 
        inv = b.repository.get_inventory(r4)
348
 
        eq(inv.get_entry(b'hello-id').revision, r4)
349
 
        eq(inv.get_entry(b'a-id').revision, r1)
350
 
        eq(inv.get_entry(b'b-id').revision, r3)
 
255
        inv = b.repository.get_revision_inventory(r4)
 
256
        eq(inv['hello-id'].revision, r4)
 
257
        eq(inv['a-id'].revision, r1)
 
258
        eq(inv['b-id'].revision, r3)
351
259
 
352
260
    def test_removed_commit(self):
353
261
        """Commit with a removed file"""
354
262
        wt = self.make_branch_and_tree('.')
355
263
        b = wt.branch
356
 
        with open('hello', 'w') as f:
357
 
            f.write('hello world')
358
 
        wt.add(['hello'], [b'hello-id'])
 
264
        file('hello', 'w').write('hello world')
 
265
        wt.add(['hello'], ['hello-id'])
359
266
        wt.commit(message='add hello')
360
267
        wt.remove('hello')
361
 
        wt.commit('removed hello', rev_id=b'rev2')
 
268
        wt.commit('removed hello', rev_id='rev2')
362
269
 
363
 
        tree = b.repository.revision_tree(b'rev2')
364
 
        self.assertFalse(tree.has_filename('hello'))
 
270
        tree = b.repository.revision_tree('rev2')
 
271
        self.assertFalse(tree.has_id('hello-id'))
365
272
 
366
273
    def test_committed_ancestry(self):
367
274
        """Test commit appends revisions to ancestry."""
369
276
        b = wt.branch
370
277
        rev_ids = []
371
278
        for i in range(4):
372
 
            with open('hello', 'w') as f:
373
 
                f.write((str(i) * 4) + '\n')
 
279
            file('hello', 'w').write((str(i) * 4) + '\n')
374
280
            if i == 0:
375
 
                wt.add(['hello'], [b'hello-id'])
376
 
            rev_id = b'test@rev-%d' % (i + 1)
 
281
                wt.add(['hello'], ['hello-id'])
 
282
            rev_id = 'test@rev-%d' % (i+1)
377
283
            rev_ids.append(rev_id)
378
 
            wt.commit(message='rev %d' % (i + 1),
379
 
                      rev_id=rev_id)
 
284
            wt.commit(message='rev %d' % (i+1),
 
285
                     rev_id=rev_id)
 
286
        eq = self.assertEquals
 
287
        eq(b.revision_history(), rev_ids)
380
288
        for i in range(4):
381
 
            self.assertThat(rev_ids[:i + 1],
382
 
                            MatchesAncestry(b.repository, rev_ids[i]))
 
289
            anc = b.repository.get_ancestry(rev_ids[i])
 
290
            eq(anc, [None] + rev_ids[:i+1])
383
291
 
384
292
    def test_commit_new_subdir_child_selective(self):
385
293
        wt = self.make_branch_and_tree('.')
386
294
        b = wt.branch
387
295
        self.build_tree(['dir/', 'dir/file1', 'dir/file2'])
388
296
        wt.add(['dir', 'dir/file1', 'dir/file2'],
389
 
               [b'dirid', b'file1id', b'file2id'])
390
 
        wt.commit('dir/file1', specific_files=['dir/file1'], rev_id=b'1')
391
 
        inv = b.repository.get_inventory(b'1')
392
 
        self.assertEqual(b'1', inv.get_entry(b'dirid').revision)
393
 
        self.assertEqual(b'1', inv.get_entry(b'file1id').revision)
 
297
              ['dirid', 'file1id', 'file2id'])
 
298
        wt.commit('dir/file1', specific_files=['dir/file1'], rev_id='1')
 
299
        inv = b.repository.get_inventory('1')
 
300
        self.assertEqual('1', inv['dirid'].revision)
 
301
        self.assertEqual('1', inv['file1id'].revision)
394
302
        # FIXME: This should raise a KeyError I think, rbc20051006
395
 
        self.assertRaises(BzrError, inv.get_entry, b'file2id')
 
303
        self.assertRaises(BzrError, inv.__getitem__, 'file2id')
396
304
 
397
305
    def test_strict_commit(self):
398
306
        """Try and commit with unknown files and strict = True, should fail."""
399
 
        from ..errors import StrictCommitFailed
 
307
        from bzrlib.errors import StrictCommitFailed
400
308
        wt = self.make_branch_and_tree('.')
401
309
        b = wt.branch
402
 
        with open('hello', 'w') as f:
403
 
            f.write('hello world')
 
310
        file('hello', 'w').write('hello world')
404
311
        wt.add('hello')
405
 
        with open('goodbye', 'w') as f:
406
 
            f.write('goodbye cruel world!')
 
312
        file('goodbye', 'w').write('goodbye cruel world!')
407
313
        self.assertRaises(StrictCommitFailed, wt.commit,
408
 
                          message='add hello but not goodbye', strict=True)
 
314
            message='add hello but not goodbye', strict=True)
409
315
 
410
316
    def test_strict_commit_without_unknowns(self):
411
317
        """Try and commit with no unknown files and strict = True,
412
318
        should work."""
 
319
        from bzrlib.errors import StrictCommitFailed
413
320
        wt = self.make_branch_and_tree('.')
414
321
        b = wt.branch
415
 
        with open('hello', 'w') as f:
416
 
            f.write('hello world')
 
322
        file('hello', 'w').write('hello world')
417
323
        wt.add('hello')
418
324
        wt.commit(message='add hello', strict=True)
419
325
 
421
327
        """Try and commit with unknown files and strict = False, should work."""
422
328
        wt = self.make_branch_and_tree('.')
423
329
        b = wt.branch
424
 
        with open('hello', 'w') as f:
425
 
            f.write('hello world')
 
330
        file('hello', 'w').write('hello world')
426
331
        wt.add('hello')
427
 
        with open('goodbye', 'w') as f:
428
 
            f.write('goodbye cruel world!')
 
332
        file('goodbye', 'w').write('goodbye cruel world!')
429
333
        wt.commit(message='add hello but not goodbye', strict=False)
430
334
 
431
335
    def test_nonstrict_commit_without_unknowns(self):
433
337
        should work."""
434
338
        wt = self.make_branch_and_tree('.')
435
339
        b = wt.branch
436
 
        with open('hello', 'w') as f:
437
 
            f.write('hello world')
 
340
        file('hello', 'w').write('hello world')
438
341
        wt.add('hello')
439
342
        wt.commit(message='add hello', strict=False)
440
343
 
441
344
    def test_signed_commit(self):
442
 
        import breezy.gpg
443
 
        import breezy.commit as commit
444
 
        oldstrategy = breezy.gpg.GPGStrategy
 
345
        import bzrlib.gpg
 
346
        import bzrlib.commit as commit
 
347
        oldstrategy = bzrlib.gpg.GPGStrategy
445
348
        wt = self.make_branch_and_tree('.')
446
349
        branch = wt.branch
447
 
        wt.commit("base", allow_pointless=True, rev_id=b'A')
448
 
        self.assertFalse(branch.repository.has_signature_for_revision_id(b'A'))
 
350
        wt.commit("base", allow_pointless=True, rev_id='A')
 
351
        self.failIf(branch.repository.has_signature_for_revision_id('A'))
449
352
        try:
450
 
            from ..bzr.testament import Testament
 
353
            from bzrlib.testament import Testament
451
354
            # monkey patch gpg signing mechanism
452
 
            breezy.gpg.GPGStrategy = breezy.gpg.LoopbackGPGStrategy
453
 
            conf = config.MemoryStack(b'''
454
 
create_signatures=always
455
 
''')
456
 
            commit.Commit(config_stack=conf).commit(
457
 
                message="base", allow_pointless=True, rev_id=b'B',
458
 
                working_tree=wt)
459
 
 
 
355
            bzrlib.gpg.GPGStrategy = bzrlib.gpg.LoopbackGPGStrategy
 
356
            commit.Commit(config=MustSignConfig(branch)).commit(message="base",
 
357
                                                      allow_pointless=True,
 
358
                                                      rev_id='B',
 
359
                                                      working_tree=wt)
460
360
            def sign(text):
461
 
                return breezy.gpg.LoopbackGPGStrategy(None).sign(
462
 
                    text, breezy.gpg.MODE_CLEAR)
 
361
                return bzrlib.gpg.LoopbackGPGStrategy(None).sign(text)
463
362
            self.assertEqual(sign(Testament.from_revision(branch.repository,
464
 
                                                          b'B').as_short_text()),
465
 
                             branch.repository.get_signature_text(b'B'))
 
363
                             'B').as_short_text()),
 
364
                             branch.repository.get_signature_text('B'))
466
365
        finally:
467
 
            breezy.gpg.GPGStrategy = oldstrategy
 
366
            bzrlib.gpg.GPGStrategy = oldstrategy
468
367
 
469
368
    def test_commit_failed_signature(self):
470
 
        import breezy.gpg
471
 
        import breezy.commit as commit
472
 
        oldstrategy = breezy.gpg.GPGStrategy
 
369
        import bzrlib.gpg
 
370
        import bzrlib.commit as commit
 
371
        oldstrategy = bzrlib.gpg.GPGStrategy
473
372
        wt = self.make_branch_and_tree('.')
474
373
        branch = wt.branch
475
 
        wt.commit("base", allow_pointless=True, rev_id=b'A')
476
 
        self.assertFalse(branch.repository.has_signature_for_revision_id(b'A'))
 
374
        wt.commit("base", allow_pointless=True, rev_id='A')
 
375
        self.failIf(branch.repository.has_signature_for_revision_id('A'))
477
376
        try:
 
377
            from bzrlib.testament import Testament
478
378
            # monkey patch gpg signing mechanism
479
 
            breezy.gpg.GPGStrategy = breezy.gpg.DisabledGPGStrategy
480
 
            conf = config.MemoryStack(b'''
481
 
create_signatures=always
482
 
''')
483
 
            self.assertRaises(breezy.gpg.SigningFailed,
484
 
                              commit.Commit(config_stack=conf).commit,
 
379
            bzrlib.gpg.GPGStrategy = bzrlib.gpg.DisabledGPGStrategy
 
380
            config = MustSignConfig(branch)
 
381
            self.assertRaises(SigningFailed,
 
382
                              commit.Commit(config=config).commit,
485
383
                              message="base",
486
384
                              allow_pointless=True,
487
 
                              rev_id=b'B',
 
385
                              rev_id='B',
488
386
                              working_tree=wt)
489
387
            branch = Branch.open(self.get_url('.'))
490
 
            self.assertEqual(branch.last_revision(), b'A')
491
 
            self.assertFalse(branch.repository.has_revision(b'B'))
 
388
            self.assertEqual(branch.revision_history(), ['A'])
 
389
            self.failIf(branch.repository.has_revision('B'))
492
390
        finally:
493
 
            breezy.gpg.GPGStrategy = oldstrategy
 
391
            bzrlib.gpg.GPGStrategy = oldstrategy
494
392
 
495
393
    def test_commit_invokes_hooks(self):
496
 
        import breezy.commit as commit
 
394
        import bzrlib.commit as commit
497
395
        wt = self.make_branch_and_tree('.')
498
396
        branch = wt.branch
499
397
        calls = []
500
 
 
501
398
        def called(branch, rev_id):
502
399
            calls.append('called')
503
 
        breezy.ahook = called
 
400
        bzrlib.ahook = called
504
401
        try:
505
 
            conf = config.MemoryStack(b'post_commit=breezy.ahook breezy.ahook')
506
 
            commit.Commit(config_stack=conf).commit(
507
 
                message="base", allow_pointless=True, rev_id=b'A',
508
 
                working_tree=wt)
 
402
            config = BranchWithHooks(branch)
 
403
            commit.Commit(config=config).commit(
 
404
                            message = "base",
 
405
                            allow_pointless=True,
 
406
                            rev_id='A', working_tree = wt)
509
407
            self.assertEqual(['called', 'called'], calls)
510
408
        finally:
511
 
            del breezy.ahook
 
409
            del bzrlib.ahook
512
410
 
513
411
    def test_commit_object_doesnt_set_nick(self):
514
412
        # using the Commit object directly does not set the branch nick.
515
413
        wt = self.make_branch_and_tree('.')
516
414
        c = Commit()
517
415
        c.commit(working_tree=wt, message='empty tree', allow_pointless=True)
518
 
        self.assertEqual(wt.branch.revno(), 1)
 
416
        self.assertEquals(wt.branch.revno(), 1)
519
417
        self.assertEqual({},
520
418
                         wt.branch.repository.get_revision(
521
 
            wt.branch.last_revision()).properties)
 
419
                            wt.branch.last_revision()).properties)
522
420
 
523
421
    def test_safe_master_lock(self):
524
422
        os.mkdir('master')
529
427
        bound = master.sprout('bound')
530
428
        wt = bound.open_workingtree()
531
429
        wt.branch.set_bound_location(os.path.realpath('master'))
532
 
        with master_branch.lock_write():
 
430
 
 
431
        orig_default = lockdir._DEFAULT_TIMEOUT_SECONDS
 
432
        master_branch.lock_write()
 
433
        try:
 
434
            lockdir._DEFAULT_TIMEOUT_SECONDS = 1
533
435
            self.assertRaises(LockContention, wt.commit, 'silly')
 
436
        finally:
 
437
            lockdir._DEFAULT_TIMEOUT_SECONDS = orig_default
 
438
            master_branch.unlock()
534
439
 
535
440
    def test_commit_bound_merge(self):
536
441
        # see bug #43959; commit of a merge in a bound branch fails to push
539
444
        bound_tree = self.make_branch_and_tree('bound')
540
445
        bound_tree.branch.bind(master_branch)
541
446
 
542
 
        self.build_tree_contents(
543
 
            [('bound/content_file', b'initial contents\n')])
 
447
        self.build_tree_contents([('bound/content_file', 'initial contents\n')])
544
448
        bound_tree.add(['content_file'])
545
449
        bound_tree.commit(message='woo!')
546
450
 
547
 
        other_bzrdir = master_branch.controldir.sprout('other')
 
451
        other_bzrdir = master_branch.bzrdir.sprout('other')
548
452
        other_tree = other_bzrdir.open_workingtree()
549
453
 
550
 
        # do a commit to the other branch changing the content file so
 
454
        # do a commit to the the other branch changing the content file so
551
455
        # that our commit after merging will have a merged revision in the
552
456
        # content file history.
553
 
        self.build_tree_contents(
554
 
            [('other/content_file', b'change in other\n')])
 
457
        self.build_tree_contents([('other/content_file', 'change in other\n')])
555
458
        other_tree.commit('change in other')
556
459
 
557
460
        # do a merge into the bound branch from other, and then change the
558
461
        # content file locally to force a new revision (rather than using the
559
462
        # revision from other). This forces extra processing in commit.
560
463
        bound_tree.merge_from_branch(other_tree.branch)
561
 
        self.build_tree_contents(
562
 
            [('bound/content_file', b'change in bound\n')])
 
464
        self.build_tree_contents([('bound/content_file', 'change in bound\n')])
563
465
 
564
466
        # before #34959 was fixed, this failed with 'revision not present in
565
467
        # weave' when trying to implicitly push from the bound branch to the master
566
468
        bound_tree.commit(message='commit of merge in bound tree')
567
469
 
568
470
    def test_commit_reporting_after_merge(self):
569
 
        # when doing a commit of a merge, the reporter needs to still
 
471
        # when doing a commit of a merge, the reporter needs to still 
570
472
        # be called for each item that is added/removed/deleted.
571
473
        this_tree = self.make_branch_and_tree('this')
572
474
        # we need a bunch of files and dirs, to perform one action on each.
593
495
            'filetoleave']
594
496
            )
595
497
        this_tree.commit('create_files')
596
 
        other_dir = this_tree.controldir.sprout('other')
 
498
        other_dir = this_tree.bzrdir.sprout('other')
597
499
        other_tree = other_dir.open_workingtree()
598
500
        other_tree.lock_write()
599
501
        # perform the needed actions on the files and dirs.
601
503
            other_tree.rename_one('dirtorename', 'renameddir')
602
504
            other_tree.rename_one('dirtoreparent', 'renameddir/reparenteddir')
603
505
            other_tree.rename_one('filetorename', 'renamedfile')
604
 
            other_tree.rename_one(
605
 
                'filetoreparent', 'renameddir/reparentedfile')
 
506
            other_tree.rename_one('filetoreparent', 'renameddir/reparentedfile')
606
507
            other_tree.remove(['dirtoremove', 'filetoremove'])
607
508
            self.build_tree_contents([
608
509
                ('other/newdir/', ),
609
 
                ('other/filetomodify', b'new content'),
610
 
                ('other/newfile', b'new file content')])
 
510
                ('other/filetomodify', 'new content'),
 
511
                ('other/newfile', 'new file content')])
611
512
            other_tree.add('newfile')
612
513
            other_tree.add('newdir/')
613
514
            other_tree.commit('modify all sample files and dirs.')
616
517
        this_tree.merge_from_branch(other_tree.branch)
617
518
        reporter = CapturingReporter()
618
519
        this_tree.commit('do the commit', reporter=reporter)
619
 
        expected = {
 
520
        self.assertEqual([
 
521
            ('change', 'unchanged', ''),
 
522
            ('change', 'unchanged', 'dirtoleave'),
 
523
            ('change', 'unchanged', 'filetoleave'),
620
524
            ('change', 'modified', 'filetomodify'),
621
525
            ('change', 'added', 'newdir'),
622
526
            ('change', 'added', 'newfile'),
623
527
            ('renamed', 'renamed', 'dirtorename', 'renameddir'),
624
 
            ('renamed', 'renamed', 'filetorename', 'renamedfile'),
625
528
            ('renamed', 'renamed', 'dirtoreparent', 'renameddir/reparenteddir'),
626
529
            ('renamed', 'renamed', 'filetoreparent', 'renameddir/reparentedfile'),
 
530
            ('renamed', 'renamed', 'filetorename', 'renamedfile'),
627
531
            ('deleted', 'dirtoremove'),
628
532
            ('deleted', 'filetoremove'),
629
 
            }
630
 
        result = set(reporter.calls)
631
 
        missing = expected - result
632
 
        new = result - expected
633
 
        self.assertEqual((set(), set()), (missing, new))
 
533
            ],
 
534
            reporter.calls)
634
535
 
635
536
    def test_commit_removals_respects_filespec(self):
636
537
        """Commit respects the specified_files for removals."""
641
542
        tree.remove(['a', 'b'])
642
543
        tree.commit('removed a', specific_files='a')
643
544
        basis = tree.basis_tree()
644
 
        with tree.lock_read():
645
 
            self.assertFalse(basis.is_versioned('a'))
646
 
            self.assertTrue(basis.is_versioned('b'))
 
545
        tree.lock_read()
 
546
        try:
 
547
            self.assertIs(None, basis.path2id('a'))
 
548
            self.assertFalse(basis.path2id('b') is None)
 
549
        finally:
 
550
            tree.unlock()
647
551
 
648
552
    def test_commit_saves_1ms_timestamp(self):
649
553
        """Passing in a timestamp is saved with 1ms resolution"""
651
555
        self.build_tree(['a'])
652
556
        tree.add('a')
653
557
        tree.commit('added a', timestamp=1153248633.4186721, timezone=0,
654
 
                    rev_id=b'a1')
 
558
                    rev_id='a1')
655
559
 
656
 
        rev = tree.branch.repository.get_revision(b'a1')
 
560
        rev = tree.branch.repository.get_revision('a1')
657
561
        self.assertEqual(1153248633.419, rev.timestamp)
658
562
 
659
563
    def test_commit_has_1ms_resolution(self):
661
565
        tree = self.make_branch_and_tree('.')
662
566
        self.build_tree(['a'])
663
567
        tree.add('a')
664
 
        tree.commit('added a', rev_id=b'a1')
 
568
        tree.commit('added a', rev_id='a1')
665
569
 
666
 
        rev = tree.branch.repository.get_revision(b'a1')
 
570
        rev = tree.branch.repository.get_revision('a1')
667
571
        timestamp = rev.timestamp
668
572
        timestamp_1ms = round(timestamp, 3)
669
573
        self.assertEqual(timestamp_1ms, timestamp)
670
574
 
671
 
    def assertBasisTreeKind(self, kind, tree, path):
 
575
    def assertBasisTreeKind(self, kind, tree, file_id):
672
576
        basis = tree.basis_tree()
673
577
        basis.lock_read()
674
578
        try:
675
 
            self.assertEqual(kind, basis.kind(path))
 
579
            self.assertEqual(kind, basis.kind(file_id))
676
580
        finally:
677
581
            basis.unlock()
678
582
 
679
 
    def test_unsupported_symlink_commit(self):
680
 
        self.requireFeature(SymlinkFeature)
681
 
        tree = self.make_branch_and_tree('.')
682
 
        self.build_tree(['hello'])
683
 
        tree.add('hello')
684
 
        tree.commit('added hello', rev_id=b'hello_id')
685
 
        os.symlink('hello', 'foo')
686
 
        tree.add('foo')
687
 
        tree.commit('added foo', rev_id=b'foo_id')
688
 
        log = BytesIO()
689
 
        trace.push_log_file(log)
690
 
        os_symlink = getattr(os, 'symlink', None)
691
 
        os.symlink = None
692
 
        try:
693
 
            # At this point as bzr thinks symlinks are not supported
694
 
            # we should get a warning about symlink foo and bzr should
695
 
            # not think its removed.
696
 
            os.unlink('foo')
697
 
            self.build_tree(['world'])
698
 
            tree.add('world')
699
 
            tree.commit('added world', rev_id=b'world_id')
700
 
        finally:
701
 
            if os_symlink:
702
 
                os.symlink = os_symlink
703
 
        self.assertContainsRe(
704
 
            log.getvalue(),
705
 
            b'Ignoring "foo" as symlinks are not '
706
 
            b'supported on this filesystem\\.')
707
 
 
708
583
    def test_commit_kind_changes(self):
709
 
        self.requireFeature(SymlinkFeature)
 
584
        if not osutils.has_symlinks():
 
585
            raise tests.TestSkipped('Test requires symlink support')
710
586
        tree = self.make_branch_and_tree('.')
711
587
        os.symlink('target', 'name')
712
 
        tree.add('name', b'a-file-id')
 
588
        tree.add('name', 'a-file-id')
713
589
        tree.commit('Added a symlink')
714
 
        self.assertBasisTreeKind('symlink', tree, 'name')
 
590
        self.assertBasisTreeKind('symlink', tree, 'a-file-id')
715
591
 
716
592
        os.unlink('name')
717
593
        self.build_tree(['name'])
718
594
        tree.commit('Changed symlink to file')
719
 
        self.assertBasisTreeKind('file', tree, 'name')
 
595
        self.assertBasisTreeKind('file', tree, 'a-file-id')
720
596
 
721
597
        os.unlink('name')
722
598
        os.symlink('target', 'name')
723
599
        tree.commit('file to symlink')
724
 
        self.assertBasisTreeKind('symlink', tree, 'name')
 
600
        self.assertBasisTreeKind('symlink', tree, 'a-file-id')
725
601
 
726
602
        os.unlink('name')
727
603
        os.mkdir('name')
728
604
        tree.commit('symlink to directory')
729
 
        self.assertBasisTreeKind('directory', tree, 'name')
 
605
        self.assertBasisTreeKind('directory', tree, 'a-file-id')
730
606
 
731
607
        os.rmdir('name')
732
608
        os.symlink('target', 'name')
733
609
        tree.commit('directory to symlink')
734
 
        self.assertBasisTreeKind('symlink', tree, 'name')
 
610
        self.assertBasisTreeKind('symlink', tree, 'a-file-id')
735
611
 
736
612
        # prepare for directory <-> file tests
737
613
        os.unlink('name')
738
614
        os.mkdir('name')
739
615
        tree.commit('symlink to directory')
740
 
        self.assertBasisTreeKind('directory', tree, 'name')
 
616
        self.assertBasisTreeKind('directory', tree, 'a-file-id')
741
617
 
742
618
        os.rmdir('name')
743
619
        self.build_tree(['name'])
744
620
        tree.commit('Changed directory to file')
745
 
        self.assertBasisTreeKind('file', tree, 'name')
 
621
        self.assertBasisTreeKind('file', tree, 'a-file-id')
746
622
 
747
623
        os.unlink('name')
748
624
        os.mkdir('name')
749
625
        tree.commit('file to directory')
750
 
        self.assertBasisTreeKind('directory', tree, 'name')
 
626
        self.assertBasisTreeKind('directory', tree, 'a-file-id')
751
627
 
752
628
    def test_commit_unversioned_specified(self):
753
629
        """Commit should raise if specified files isn't in basis or worktree"""
754
630
        tree = self.make_branch_and_tree('.')
755
 
        self.assertRaises(errors.PathsNotVersionedError, tree.commit,
 
631
        self.assertRaises(errors.PathsNotVersionedError, tree.commit, 
756
632
                          'message', specific_files=['bogus'])
757
633
 
758
634
    class Callback(object):
759
 
 
 
635
        
760
636
        def __init__(self, message, testcase):
761
637
            self.called = False
762
638
            self.message = message
773
649
        tree = self.make_branch_and_tree('.')
774
650
        try:
775
651
            tree.commit()
776
 
        except Exception as e:
 
652
        except Exception, e:
777
653
            self.assertTrue(isinstance(e, BzrError))
778
654
            self.assertEqual('The message or message_callback keyword'
779
655
                             ' parameter is required for commit().', str(e))
790
666
        """Callback should not be invoked for pointless commit"""
791
667
        tree = self.make_branch_and_tree('.')
792
668
        cb = self.Callback(u'commit 2', self)
793
 
        self.assertRaises(PointlessCommit, tree.commit, message_callback=cb,
 
669
        self.assertRaises(PointlessCommit, tree.commit, message_callback=cb, 
794
670
                          allow_pointless=False)
795
671
        self.assertFalse(cb.called)
796
672
 
800
676
        cb = self.Callback(u'commit 2', self)
801
677
        repository = tree.branch.repository
802
678
        # simulate network failure
803
 
 
804
 
        def raise_(self, arg, arg2, arg3=None, arg4=None):
 
679
        def raise_(self, arg, arg2):
805
680
            raise errors.NoSuchFile('foo')
806
681
        repository.add_inventory = raise_
807
 
        repository.add_inventory_by_delta = raise_
808
682
        self.assertRaises(errors.NoSuchFile, tree.commit, message_callback=cb)
809
683
        self.assertFalse(cb.called)
810
 
 
811
 
    def test_selected_file_merge_commit(self):
812
 
        """Ensure the correct error is raised"""
813
 
        tree = self.make_branch_and_tree('foo')
814
 
        # pending merge would turn into a left parent
815
 
        tree.commit('commit 1')
816
 
        tree.add_parent_tree_id(b'example')
817
 
        self.build_tree(['foo/bar', 'foo/baz'])
818
 
        tree.add(['bar', 'baz'])
819
 
        err = self.assertRaises(CannotCommitSelectedFileMerge,
820
 
                                tree.commit, 'commit 2', specific_files=['bar', 'baz'])
821
 
        self.assertEqual(['bar', 'baz'], err.files)
822
 
        self.assertEqual('Selected-file commit of merges is not supported'
823
 
                         ' yet: files bar, baz', str(err))
824
 
 
825
 
    def test_commit_ordering(self):
826
 
        """Test of corner-case commit ordering error"""
827
 
        tree = self.make_branch_and_tree('.')
828
 
        self.build_tree(['a/', 'a/z/', 'a/c/', 'a/z/x', 'a/z/y'])
829
 
        tree.add(['a/', 'a/z/', 'a/c/', 'a/z/x', 'a/z/y'])
830
 
        tree.commit('setup')
831
 
        self.build_tree(['a/c/d/'])
832
 
        tree.add('a/c/d')
833
 
        tree.rename_one('a/z/x', 'a/c/d/x')
834
 
        tree.commit('test', specific_files=['a/z/y'])
835
 
 
836
 
    def test_commit_no_author(self):
837
 
        """The default kwarg author in MutableTree.commit should not add
838
 
        the 'author' revision property.
839
 
        """
840
 
        tree = self.make_branch_and_tree('foo')
841
 
        rev_id = tree.commit('commit 1')
842
 
        rev = tree.branch.repository.get_revision(rev_id)
843
 
        self.assertFalse('author' in rev.properties)
844
 
        self.assertFalse('authors' in rev.properties)
845
 
 
846
 
    def test_commit_author(self):
847
 
        """Passing a non-empty authors kwarg to MutableTree.commit should add
848
 
        the 'author' revision property.
849
 
        """
850
 
        tree = self.make_branch_and_tree('foo')
851
 
        rev_id = tree.commit(
852
 
            'commit 1',
853
 
            authors=['John Doe <jdoe@example.com>'])
854
 
        rev = tree.branch.repository.get_revision(rev_id)
855
 
        self.assertEqual('John Doe <jdoe@example.com>',
856
 
                         rev.properties['authors'])
857
 
        self.assertFalse('author' in rev.properties)
858
 
 
859
 
    def test_commit_empty_authors_list(self):
860
 
        """Passing an empty list to authors shouldn't add the property."""
861
 
        tree = self.make_branch_and_tree('foo')
862
 
        rev_id = tree.commit('commit 1', authors=[])
863
 
        rev = tree.branch.repository.get_revision(rev_id)
864
 
        self.assertFalse('author' in rev.properties)
865
 
        self.assertFalse('authors' in rev.properties)
866
 
 
867
 
    def test_multiple_authors(self):
868
 
        tree = self.make_branch_and_tree('foo')
869
 
        rev_id = tree.commit('commit 1',
870
 
                             authors=['John Doe <jdoe@example.com>',
871
 
                                      'Jane Rey <jrey@example.com>'])
872
 
        rev = tree.branch.repository.get_revision(rev_id)
873
 
        self.assertEqual('John Doe <jdoe@example.com>\n'
874
 
                         'Jane Rey <jrey@example.com>', rev.properties['authors'])
875
 
        self.assertFalse('author' in rev.properties)
876
 
 
877
 
    def test_author_with_newline_rejected(self):
878
 
        tree = self.make_branch_and_tree('foo')
879
 
        self.assertRaises(AssertionError, tree.commit, 'commit 1',
880
 
                          authors=['John\nDoe <jdoe@example.com>'])
881
 
 
882
 
    def test_commit_with_checkout_and_branch_sharing_repo(self):
883
 
        repo = self.make_repository('repo', shared=True)
884
 
        # make_branch_and_tree ignores shared repos
885
 
        branch = controldir.ControlDir.create_branch_convenience('repo/branch')
886
 
        tree2 = branch.create_checkout('repo/tree2')
887
 
        tree2.commit('message', rev_id=b'rev1')
888
 
        self.assertTrue(tree2.branch.repository.has_revision(b'rev1'))
889
 
 
890
 
 
891
 
class FilterExcludedTests(TestCase):
892
 
 
893
 
    def test_add_file_not_excluded(self):
894
 
        changes = [
895
 
            InventoryTreeChange(
896
 
                'fid', (None, 'newpath'),
897
 
                0, (False, False), ('pid', 'pid'), ('newpath', 'newpath'),
898
 
                ('file', 'file'), (True, True))]
899
 
        self.assertEqual(changes, list(
900
 
            filter_excluded(changes, ['otherpath'])))
901
 
 
902
 
    def test_add_file_excluded(self):
903
 
        changes = [
904
 
            InventoryTreeChange(
905
 
                'fid', (None, 'newpath'),
906
 
                0, (False, False), ('pid', 'pid'), ('newpath', 'newpath'),
907
 
                ('file', 'file'), (True, True))]
908
 
        self.assertEqual([], list(filter_excluded(changes, ['newpath'])))
909
 
 
910
 
    def test_delete_file_excluded(self):
911
 
        changes = [
912
 
            InventoryTreeChange(
913
 
                'fid', ('somepath', None),
914
 
                0, (False, None), ('pid', None), ('newpath', None),
915
 
                ('file', None), (True, None))]
916
 
        self.assertEqual([], list(filter_excluded(changes, ['somepath'])))
917
 
 
918
 
    def test_move_from_or_to_excluded(self):
919
 
        changes = [
920
 
            InventoryTreeChange(
921
 
                'fid', ('oldpath', 'newpath'),
922
 
                0, (False, False), ('pid', 'pid'), ('oldpath', 'newpath'),
923
 
                ('file', 'file'), (True, True))]
924
 
        self.assertEqual([], list(filter_excluded(changes, ['oldpath'])))
925
 
        self.assertEqual([], list(filter_excluded(changes, ['newpath'])))