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

  • Committer: Breezy landing bot
  • Author(s): Jelmer Vernooij
  • Date: 2019-01-24 02:11:03 UTC
  • mfrom: (7240.6.2 release-notes)
  • Revision ID: breezy.the.bot@gmail.com-20190124021103-hlav1a0ga9gv4stf
Add some release notes ahead of beta1.

Merged from https://code.launchpad.net/~jelmer/brz/release-notes/+merge/361717

Show diffs side-by-side

added added

removed removed

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