~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_commit.py

  • Committer: Erik Bågfors
  • Date: 2006-02-03 19:50:59 UTC
  • mto: (1185.50.77 bzr-jam-integration)
  • mto: This revision was merged to the branch mainline in revision 1554.
  • Revision ID: erik@bagfors.nu-20060203195059-1cf8ff5aa68de0ea
Support for plugins to register log formatters and set default formatter
Also, change one command line option for "log"

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2005 by Canonical Ltd
 
2
 
 
3
# This program is free software; you can redistribute it and/or modify
 
4
# it under the terms of the GNU General Public License as published by
 
5
# the Free Software Foundation; either version 2 of the License, or
 
6
# (at your option) any later version.
 
7
 
 
8
# This program is distributed in the hope that it will be useful,
 
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
# GNU General Public License for more details.
 
12
 
 
13
# You should have received a copy of the GNU General Public License
 
14
# along with this program; if not, write to the Free Software
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
16
 
 
17
 
 
18
import os
 
19
 
 
20
import bzrlib
 
21
from bzrlib.tests import TestCaseWithTransport
 
22
from bzrlib.branch import Branch
 
23
from bzrlib.workingtree import WorkingTree
 
24
from bzrlib.commit import Commit
 
25
from bzrlib.config import BranchConfig
 
26
from bzrlib.errors import PointlessCommit, BzrError, SigningFailed
 
27
 
 
28
 
 
29
# TODO: Test commit with some added, and added-but-missing files
 
30
 
 
31
class MustSignConfig(BranchConfig):
 
32
 
 
33
    def signature_needed(self):
 
34
        return True
 
35
 
 
36
    def gpg_signing_command(self):
 
37
        return ['cat', '-']
 
38
 
 
39
 
 
40
class BranchWithHooks(BranchConfig):
 
41
 
 
42
    def post_commit(self):
 
43
        return "bzrlib.ahook bzrlib.ahook"
 
44
 
 
45
 
 
46
class TestCommit(TestCaseWithTransport):
 
47
 
 
48
    def test_simple_commit(self):
 
49
        """Commit and check two versions of a single file."""
 
50
        wt = self.make_branch_and_tree('.')
 
51
        b = wt.branch
 
52
        file('hello', 'w').write('hello world')
 
53
        wt.add('hello')
 
54
        wt.commit(message='add hello')
 
55
        file_id = wt.path2id('hello')
 
56
 
 
57
        file('hello', 'w').write('version 2')
 
58
        wt.commit(message='commit 2')
 
59
 
 
60
        eq = self.assertEquals
 
61
        eq(b.revno(), 2)
 
62
        rh = b.revision_history()
 
63
        rev = b.repository.get_revision(rh[0])
 
64
        eq(rev.message, 'add hello')
 
65
 
 
66
        tree1 = b.repository.revision_tree(rh[0])
 
67
        text = tree1.get_file_text(file_id)
 
68
        eq(text, 'hello world')
 
69
 
 
70
        tree2 = b.repository.revision_tree(rh[1])
 
71
        eq(tree2.get_file_text(file_id), 'version 2')
 
72
 
 
73
    def test_delete_commit(self):
 
74
        """Test a commit with a deleted file"""
 
75
        wt = self.make_branch_and_tree('.')
 
76
        b = wt.branch
 
77
        file('hello', 'w').write('hello world')
 
78
        wt.add(['hello'], ['hello-id'])
 
79
        wt.commit(message='add hello')
 
80
 
 
81
        os.remove('hello')
 
82
        wt.commit('removed hello', rev_id='rev2')
 
83
 
 
84
        tree = b.repository.revision_tree('rev2')
 
85
        self.assertFalse(tree.has_id('hello-id'))
 
86
 
 
87
    def test_pointless_commit(self):
 
88
        """Commit refuses unless there are changes or it's forced."""
 
89
        wt = self.make_branch_and_tree('.')
 
90
        b = wt.branch
 
91
        file('hello', 'w').write('hello')
 
92
        wt.add(['hello'])
 
93
        wt.commit(message='add hello')
 
94
        self.assertEquals(b.revno(), 1)
 
95
        self.assertRaises(PointlessCommit,
 
96
                          wt.commit,
 
97
                          message='fails',
 
98
                          allow_pointless=False)
 
99
        self.assertEquals(b.revno(), 1)
 
100
        
 
101
    def test_commit_empty(self):
 
102
        """Commiting an empty tree works."""
 
103
        wt = self.make_branch_and_tree('.')
 
104
        b = wt.branch
 
105
        wt.commit(message='empty tree', allow_pointless=True)
 
106
        self.assertRaises(PointlessCommit,
 
107
                          wt.commit,
 
108
                          message='empty tree',
 
109
                          allow_pointless=False)
 
110
        wt.commit(message='empty tree', allow_pointless=True)
 
111
        self.assertEquals(b.revno(), 2)
 
112
 
 
113
    def test_selective_delete(self):
 
114
        """Selective commit in tree with deletions"""
 
115
        wt = self.make_branch_and_tree('.')
 
116
        b = wt.branch
 
117
        file('hello', 'w').write('hello')
 
118
        file('buongia', 'w').write('buongia')
 
119
        wt.add(['hello', 'buongia'],
 
120
              ['hello-id', 'buongia-id'])
 
121
        wt.commit(message='add files',
 
122
                 rev_id='test@rev-1')
 
123
        
 
124
        os.remove('hello')
 
125
        file('buongia', 'w').write('new text')
 
126
        wt.commit(message='update text',
 
127
                 specific_files=['buongia'],
 
128
                 allow_pointless=False,
 
129
                 rev_id='test@rev-2')
 
130
 
 
131
        wt.commit(message='remove hello',
 
132
                 specific_files=['hello'],
 
133
                 allow_pointless=False,
 
134
                 rev_id='test@rev-3')
 
135
 
 
136
        eq = self.assertEquals
 
137
        eq(b.revno(), 3)
 
138
 
 
139
        tree2 = b.repository.revision_tree('test@rev-2')
 
140
        self.assertTrue(tree2.has_filename('hello'))
 
141
        self.assertEquals(tree2.get_file_text('hello-id'), 'hello')
 
142
        self.assertEquals(tree2.get_file_text('buongia-id'), 'new text')
 
143
        
 
144
        tree3 = b.repository.revision_tree('test@rev-3')
 
145
        self.assertFalse(tree3.has_filename('hello'))
 
146
        self.assertEquals(tree3.get_file_text('buongia-id'), 'new text')
 
147
 
 
148
    def test_commit_rename(self):
 
149
        """Test commit of a revision where a file is renamed."""
 
150
        tree = self.make_branch_and_tree('.')
 
151
        b = tree.branch
 
152
        self.build_tree(['hello'], line_endings='binary')
 
153
        tree.add(['hello'], ['hello-id'])
 
154
        tree.commit(message='one', rev_id='test@rev-1', allow_pointless=False)
 
155
 
 
156
        tree.rename_one('hello', 'fruity')
 
157
        tree.commit(message='renamed', rev_id='test@rev-2', allow_pointless=False)
 
158
 
 
159
        eq = self.assertEquals
 
160
        tree1 = b.repository.revision_tree('test@rev-1')
 
161
        eq(tree1.id2path('hello-id'), 'hello')
 
162
        eq(tree1.get_file_text('hello-id'), 'contents of hello\n')
 
163
        self.assertFalse(tree1.has_filename('fruity'))
 
164
        self.check_inventory_shape(tree1.inventory, ['hello'])
 
165
        ie = tree1.inventory['hello-id']
 
166
        eq(ie.revision, 'test@rev-1')
 
167
 
 
168
        tree2 = b.repository.revision_tree('test@rev-2')
 
169
        eq(tree2.id2path('hello-id'), 'fruity')
 
170
        eq(tree2.get_file_text('hello-id'), 'contents of hello\n')
 
171
        self.check_inventory_shape(tree2.inventory, ['fruity'])
 
172
        ie = tree2.inventory['hello-id']
 
173
        eq(ie.revision, 'test@rev-2')
 
174
 
 
175
    def test_reused_rev_id(self):
 
176
        """Test that a revision id cannot be reused in a branch"""
 
177
        wt = self.make_branch_and_tree('.')
 
178
        b = wt.branch
 
179
        wt.commit('initial', rev_id='test@rev-1', allow_pointless=True)
 
180
        self.assertRaises(Exception,
 
181
                          b.working_tree().commit,
 
182
                          message='reused id',
 
183
                          rev_id='test@rev-1',
 
184
                          allow_pointless=True)
 
185
 
 
186
    def test_commit_move(self):
 
187
        """Test commit of revisions with moved files and directories"""
 
188
        eq = self.assertEquals
 
189
        wt = self.make_branch_and_tree('.')
 
190
        b = wt.branch
 
191
        r1 = 'test@rev-1'
 
192
        self.build_tree(['hello', 'a/', 'b/'])
 
193
        wt.add(['hello', 'a', 'b'], ['hello-id', 'a-id', 'b-id'])
 
194
        wt.commit('initial', rev_id=r1, allow_pointless=False)
 
195
        wt.move(['hello'], 'a')
 
196
        r2 = 'test@rev-2'
 
197
        wt.commit('two', rev_id=r2, allow_pointless=False)
 
198
        self.check_inventory_shape(b.working_tree().read_working_inventory(),
 
199
                                   ['a', 'a/hello', 'b'])
 
200
 
 
201
        wt.move(['b'], 'a')
 
202
        r3 = 'test@rev-3'
 
203
        wt.commit('three', rev_id=r3, allow_pointless=False)
 
204
        self.check_inventory_shape(wt.read_working_inventory(),
 
205
                                   ['a', 'a/hello', 'a/b'])
 
206
        self.check_inventory_shape(b.repository.get_revision_inventory(r3),
 
207
                                   ['a', 'a/hello', 'a/b'])
 
208
 
 
209
        wt.move(['a/hello'], 'a/b')
 
210
        r4 = 'test@rev-4'
 
211
        wt.commit('four', rev_id=r4, allow_pointless=False)
 
212
        self.check_inventory_shape(wt.read_working_inventory(),
 
213
                                   ['a', 'a/b/hello', 'a/b'])
 
214
 
 
215
        inv = b.repository.get_revision_inventory(r4)
 
216
        eq(inv['hello-id'].revision, r4)
 
217
        eq(inv['a-id'].revision, r1)
 
218
        eq(inv['b-id'].revision, r3)
 
219
        
 
220
    def test_removed_commit(self):
 
221
        """Commit with a removed file"""
 
222
        wt = self.make_branch_and_tree('.')
 
223
        b = wt.branch
 
224
        file('hello', 'w').write('hello world')
 
225
        wt.add(['hello'], ['hello-id'])
 
226
        wt.commit(message='add hello')
 
227
        wt.remove('hello')
 
228
        wt.commit('removed hello', rev_id='rev2')
 
229
 
 
230
        tree = b.repository.revision_tree('rev2')
 
231
        self.assertFalse(tree.has_id('hello-id'))
 
232
 
 
233
    def test_committed_ancestry(self):
 
234
        """Test commit appends revisions to ancestry."""
 
235
        wt = self.make_branch_and_tree('.')
 
236
        b = wt.branch
 
237
        rev_ids = []
 
238
        for i in range(4):
 
239
            file('hello', 'w').write((str(i) * 4) + '\n')
 
240
            if i == 0:
 
241
                wt.add(['hello'], ['hello-id'])
 
242
            rev_id = 'test@rev-%d' % (i+1)
 
243
            rev_ids.append(rev_id)
 
244
            wt.commit(message='rev %d' % (i+1),
 
245
                     rev_id=rev_id)
 
246
        eq = self.assertEquals
 
247
        eq(b.revision_history(), rev_ids)
 
248
        for i in range(4):
 
249
            anc = b.repository.get_ancestry(rev_ids[i])
 
250
            eq(anc, [None] + rev_ids[:i+1])
 
251
 
 
252
    def test_commit_new_subdir_child_selective(self):
 
253
        wt = self.make_branch_and_tree('.')
 
254
        b = wt.branch
 
255
        self.build_tree(['dir/', 'dir/file1', 'dir/file2'])
 
256
        wt.add(['dir', 'dir/file1', 'dir/file2'],
 
257
              ['dirid', 'file1id', 'file2id'])
 
258
        wt.commit('dir/file1', specific_files=['dir/file1'], rev_id='1')
 
259
        inv = b.repository.get_inventory('1')
 
260
        self.assertEqual('1', inv['dirid'].revision)
 
261
        self.assertEqual('1', inv['file1id'].revision)
 
262
        # FIXME: This should raise a KeyError I think, rbc20051006
 
263
        self.assertRaises(BzrError, inv.__getitem__, 'file2id')
 
264
 
 
265
    def test_strict_commit(self):
 
266
        """Try and commit with unknown files and strict = True, should fail."""
 
267
        from bzrlib.errors import StrictCommitFailed
 
268
        wt = self.make_branch_and_tree('.')
 
269
        b = wt.branch
 
270
        file('hello', 'w').write('hello world')
 
271
        wt.add('hello')
 
272
        file('goodbye', 'w').write('goodbye cruel world!')
 
273
        self.assertRaises(StrictCommitFailed, b.working_tree().commit,
 
274
            message='add hello but not goodbye', strict=True)
 
275
 
 
276
    def test_strict_commit_without_unknowns(self):
 
277
        """Try and commit with no unknown files and strict = True,
 
278
        should work."""
 
279
        from bzrlib.errors import StrictCommitFailed
 
280
        wt = self.make_branch_and_tree('.')
 
281
        b = wt.branch
 
282
        file('hello', 'w').write('hello world')
 
283
        wt.add('hello')
 
284
        wt.commit(message='add hello', strict=True)
 
285
 
 
286
    def test_nonstrict_commit(self):
 
287
        """Try and commit with unknown files and strict = False, should work."""
 
288
        wt = self.make_branch_and_tree('.')
 
289
        b = wt.branch
 
290
        file('hello', 'w').write('hello world')
 
291
        wt.add('hello')
 
292
        file('goodbye', 'w').write('goodbye cruel world!')
 
293
        wt.commit(message='add hello but not goodbye', strict=False)
 
294
 
 
295
    def test_nonstrict_commit_without_unknowns(self):
 
296
        """Try and commit with no unknown files and strict = False,
 
297
        should work."""
 
298
        wt = self.make_branch_and_tree('.')
 
299
        b = wt.branch
 
300
        file('hello', 'w').write('hello world')
 
301
        wt.add('hello')
 
302
        wt.commit(message='add hello', strict=False)
 
303
 
 
304
    def test_signed_commit(self):
 
305
        import bzrlib.gpg
 
306
        import bzrlib.commit as commit
 
307
        oldstrategy = bzrlib.gpg.GPGStrategy
 
308
        wt = self.make_branch_and_tree('.')
 
309
        branch = wt.branch
 
310
        wt.commit("base", allow_pointless=True, rev_id='A')
 
311
        self.failIf(branch.repository.revision_store.has_id('A', 'sig'))
 
312
        try:
 
313
            from bzrlib.testament import Testament
 
314
            # monkey patch gpg signing mechanism
 
315
            bzrlib.gpg.GPGStrategy = bzrlib.gpg.LoopbackGPGStrategy
 
316
            commit.Commit(config=MustSignConfig(branch)).commit(message="base",
 
317
                                                      allow_pointless=True,
 
318
                                                      rev_id='B',
 
319
                                                      working_tree=wt)
 
320
            self.assertEqual(Testament.from_revision(branch.repository,
 
321
                             'B').as_short_text(),
 
322
                             branch.repository.revision_store.get('B', 
 
323
                                                               'sig').read())
 
324
        finally:
 
325
            bzrlib.gpg.GPGStrategy = oldstrategy
 
326
 
 
327
    def test_commit_failed_signature(self):
 
328
        import bzrlib.gpg
 
329
        import bzrlib.commit as commit
 
330
        oldstrategy = bzrlib.gpg.GPGStrategy
 
331
        wt = self.make_branch_and_tree('.')
 
332
        branch = wt.branch
 
333
        wt.commit("base", allow_pointless=True, rev_id='A')
 
334
        self.failIf(branch.repository.revision_store.has_id('A', 'sig'))
 
335
        try:
 
336
            from bzrlib.testament import Testament
 
337
            # monkey patch gpg signing mechanism
 
338
            bzrlib.gpg.GPGStrategy = bzrlib.gpg.DisabledGPGStrategy
 
339
            config = MustSignConfig(branch)
 
340
            self.assertRaises(SigningFailed,
 
341
                              commit.Commit(config=config).commit,
 
342
                              branch, "base",
 
343
                              allow_pointless=True,
 
344
                              rev_id='B')
 
345
            branch = Branch.open(self.get_url('.'))
 
346
            self.assertEqual(branch.revision_history(), ['A'])
 
347
            self.failIf(branch.repository.revision_store.has_id('B'))
 
348
        finally:
 
349
            bzrlib.gpg.GPGStrategy = oldstrategy
 
350
 
 
351
    def test_commit_invokes_hooks(self):
 
352
        import bzrlib.commit as commit
 
353
        wt = self.make_branch_and_tree('.')
 
354
        branch = wt.branch
 
355
        calls = []
 
356
        def called(branch, rev_id):
 
357
            calls.append('called')
 
358
        bzrlib.ahook = called
 
359
        try:
 
360
            config = BranchWithHooks(branch)
 
361
            commit.Commit(config=config).commit(
 
362
                            message = "base",
 
363
                            allow_pointless=True,
 
364
                            rev_id='A', working_tree = wt)
 
365
            self.assertEqual(['called', 'called'], calls)
 
366
        finally:
 
367
            del bzrlib.ahook