~ubuntu-branches/ubuntu/hardy/bzr/hardy-updates

« back to all changes in this revision

Viewing changes to bzrlib/selftest/test_commit.py

  • Committer: Bazaar Package Importer
  • Author(s): Jeff Bailey
  • Date: 2005-11-07 13:17:53 UTC
  • Revision ID: james.westby@ubuntu.com-20051107131753-qsy145z1rfug5i27
Tags: upstream-0.6.2
ImportĀ upstreamĀ versionĀ 0.6.2

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.selftest import TestCaseInTempDir
 
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(TestCaseInTempDir):
 
47
 
 
48
    def test_simple_commit(self):
 
49
        """Commit and check two versions of a single file."""
 
50
        b = Branch.initialize('.')
 
51
        file('hello', 'w').write('hello world')
 
52
        b.add('hello')
 
53
        b.commit(message='add hello')
 
54
        file_id = b.working_tree().path2id('hello')
 
55
 
 
56
        file('hello', 'w').write('version 2')
 
57
        b.commit(message='commit 2')
 
58
 
 
59
        eq = self.assertEquals
 
60
        eq(b.revno(), 2)
 
61
        rh = b.revision_history()
 
62
        rev = b.get_revision(rh[0])
 
63
        eq(rev.message, 'add hello')
 
64
 
 
65
        tree1 = b.revision_tree(rh[0])
 
66
        text = tree1.get_file_text(file_id)
 
67
        eq(text, 'hello world')
 
68
 
 
69
        tree2 = b.revision_tree(rh[1])
 
70
        eq(tree2.get_file_text(file_id), 'version 2')
 
71
 
 
72
    def test_delete_commit(self):
 
73
        """Test a commit with a deleted file"""
 
74
        b = Branch.initialize('.')
 
75
        file('hello', 'w').write('hello world')
 
76
        b.add(['hello'], ['hello-id'])
 
77
        b.commit(message='add hello')
 
78
 
 
79
        os.remove('hello')
 
80
        b.commit('removed hello', rev_id='rev2')
 
81
 
 
82
        tree = b.revision_tree('rev2')
 
83
        self.assertFalse(tree.has_id('hello-id'))
 
84
 
 
85
 
 
86
    def test_pointless_commit(self):
 
87
        """Commit refuses unless there are changes or it's forced."""
 
88
        b = Branch.initialize('.')
 
89
        file('hello', 'w').write('hello')
 
90
        b.add(['hello'])
 
91
        b.commit(message='add hello')
 
92
        self.assertEquals(b.revno(), 1)
 
93
        self.assertRaises(PointlessCommit,
 
94
                          b.commit,
 
95
                          message='fails',
 
96
                          allow_pointless=False)
 
97
        self.assertEquals(b.revno(), 1)
 
98
        
 
99
 
 
100
 
 
101
    def test_commit_empty(self):
 
102
        """Commiting an empty tree works."""
 
103
        b = Branch.initialize('.')
 
104
        b.commit(message='empty tree', allow_pointless=True)
 
105
        self.assertRaises(PointlessCommit,
 
106
                          b.commit,
 
107
                          message='empty tree',
 
108
                          allow_pointless=False)
 
109
        b.commit(message='empty tree', allow_pointless=True)
 
110
        self.assertEquals(b.revno(), 2)
 
111
 
 
112
 
 
113
    def test_selective_delete(self):
 
114
        """Selective commit in tree with deletions"""
 
115
        b = Branch.initialize('.')
 
116
        file('hello', 'w').write('hello')
 
117
        file('buongia', 'w').write('buongia')
 
118
        b.add(['hello', 'buongia'],
 
119
              ['hello-id', 'buongia-id'])
 
120
        b.commit(message='add files',
 
121
                 rev_id='test@rev-1')
 
122
        
 
123
        os.remove('hello')
 
124
        file('buongia', 'w').write('new text')
 
125
        b.commit(message='update text',
 
126
                 specific_files=['buongia'],
 
127
                 allow_pointless=False,
 
128
                 rev_id='test@rev-2')
 
129
 
 
130
        b.commit(message='remove hello',
 
131
                 specific_files=['hello'],
 
132
                 allow_pointless=False,
 
133
                 rev_id='test@rev-3')
 
134
 
 
135
        eq = self.assertEquals
 
136
        eq(b.revno(), 3)
 
137
 
 
138
        tree2 = b.revision_tree('test@rev-2')
 
139
        self.assertTrue(tree2.has_filename('hello'))
 
140
        self.assertEquals(tree2.get_file_text('hello-id'), 'hello')
 
141
        self.assertEquals(tree2.get_file_text('buongia-id'), 'new text')
 
142
        
 
143
        tree3 = b.revision_tree('test@rev-3')
 
144
        self.assertFalse(tree3.has_filename('hello'))
 
145
        self.assertEquals(tree3.get_file_text('buongia-id'), 'new text')
 
146
 
 
147
 
 
148
    def test_commit_rename(self):
 
149
        """Test commit of a revision where a file is renamed."""
 
150
        b = Branch.initialize('.')
 
151
        self.build_tree(['hello'])
 
152
        b.add(['hello'], ['hello-id'])
 
153
        b.commit(message='one', rev_id='test@rev-1', allow_pointless=False)
 
154
 
 
155
        b.rename_one('hello', 'fruity')
 
156
        b.commit(message='renamed', rev_id='test@rev-2', allow_pointless=False)
 
157
 
 
158
        eq = self.assertEquals
 
159
        tree1 = b.revision_tree('test@rev-1')
 
160
        eq(tree1.id2path('hello-id'), 'hello')
 
161
        eq(tree1.get_file_text('hello-id'), 'contents of hello\n')
 
162
        self.assertFalse(tree1.has_filename('fruity'))
 
163
        self.check_inventory_shape(tree1.inventory, ['hello'])
 
164
        ie = tree1.inventory['hello-id']
 
165
        eq(ie.revision, 'test@rev-1')
 
166
 
 
167
        tree2 = b.revision_tree('test@rev-2')
 
168
        eq(tree2.id2path('hello-id'), 'fruity')
 
169
        eq(tree2.get_file_text('hello-id'), 'contents of hello\n')
 
170
        self.check_inventory_shape(tree2.inventory, ['fruity'])
 
171
        ie = tree2.inventory['hello-id']
 
172
        eq(ie.revision, 'test@rev-2')
 
173
 
 
174
 
 
175
    def test_reused_rev_id(self):
 
176
        """Test that a revision id cannot be reused in a branch"""
 
177
        b = Branch.initialize('.')
 
178
        b.commit('initial', rev_id='test@rev-1', allow_pointless=True)
 
179
        self.assertRaises(Exception,
 
180
                          b.commit,
 
181
                          message='reused id',
 
182
                          rev_id='test@rev-1',
 
183
                          allow_pointless=True)
 
184
                          
 
185
 
 
186
 
 
187
    def test_commit_move(self):
 
188
        """Test commit of revisions with moved files and directories"""
 
189
        eq = self.assertEquals
 
190
        b = Branch.initialize('.')
 
191
        r1 = 'test@rev-1'
 
192
        self.build_tree(['hello', 'a/', 'b/'])
 
193
        b.add(['hello', 'a', 'b'], ['hello-id', 'a-id', 'b-id'])
 
194
        b.commit('initial', rev_id=r1, allow_pointless=False)
 
195
 
 
196
        b.move(['hello'], 'a')
 
197
        r2 = 'test@rev-2'
 
198
        b.commit('two', rev_id=r2, allow_pointless=False)
 
199
        self.check_inventory_shape(b.inventory,
 
200
                                   ['a', 'a/hello', 'b'])
 
201
 
 
202
        b.move(['b'], 'a')
 
203
        r3 = 'test@rev-3'
 
204
        b.commit('three', rev_id=r3, allow_pointless=False)
 
205
        self.check_inventory_shape(b.inventory,
 
206
                                   ['a', 'a/hello', 'a/b'])
 
207
        self.check_inventory_shape(b.get_revision_inventory(r3),
 
208
                                   ['a', 'a/hello', 'a/b'])
 
209
 
 
210
        b.move([os.sep.join(['a', 'hello'])],
 
211
               os.sep.join(['a', 'b']))
 
212
        r4 = 'test@rev-4'
 
213
        b.commit('four', rev_id=r4, allow_pointless=False)
 
214
        self.check_inventory_shape(b.inventory,
 
215
                                   ['a', 'a/b/hello', 'a/b'])
 
216
 
 
217
        inv = b.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
 
 
222
        
 
223
    def test_removed_commit(self):
 
224
        """Commit with a removed file"""
 
225
        b = Branch.initialize('.')
 
226
        wt = b.working_tree()
 
227
        file('hello', 'w').write('hello world')
 
228
        b.add(['hello'], ['hello-id'])
 
229
        b.commit(message='add hello')
 
230
 
 
231
        wt = b.working_tree()  # FIXME: kludge for aliasing of working inventory
 
232
        wt.remove('hello')
 
233
        b.commit('removed hello', rev_id='rev2')
 
234
 
 
235
        tree = b.revision_tree('rev2')
 
236
        self.assertFalse(tree.has_id('hello-id'))
 
237
 
 
238
 
 
239
    def test_committed_ancestry(self):
 
240
        """Test commit appends revisions to ancestry."""
 
241
        b = Branch.initialize('.')
 
242
        rev_ids = []
 
243
        for i in range(4):
 
244
            file('hello', 'w').write((str(i) * 4) + '\n')
 
245
            if i == 0:
 
246
                b.add(['hello'], ['hello-id'])
 
247
            rev_id = 'test@rev-%d' % (i+1)
 
248
            rev_ids.append(rev_id)
 
249
            b.commit(message='rev %d' % (i+1),
 
250
                     rev_id=rev_id)
 
251
        eq = self.assertEquals
 
252
        eq(b.revision_history(), rev_ids)
 
253
        for i in range(4):
 
254
            anc = b.get_ancestry(rev_ids[i])
 
255
            eq(anc, [None] + rev_ids[:i+1])
 
256
 
 
257
    def test_commit_new_subdir_child_selective(self):
 
258
        b = Branch.initialize('.')
 
259
        self.build_tree(['dir/', 'dir/file1', 'dir/file2'])
 
260
        b.add(['dir', 'dir/file1', 'dir/file2'],
 
261
              ['dirid', 'file1id', 'file2id'])
 
262
        b.commit('dir/file1', specific_files=['dir/file1'], rev_id='1')
 
263
        inv = b.get_inventory('1')
 
264
        self.assertEqual('1', inv['dirid'].revision)
 
265
        self.assertEqual('1', inv['file1id'].revision)
 
266
        # FIXME: This should raise a KeyError I think, rbc20051006
 
267
        self.assertRaises(BzrError, inv.__getitem__, 'file2id')
 
268
 
 
269
    def test_strict_commit(self):
 
270
        """Try and commit with unknown files and strict = True, should fail."""
 
271
        from bzrlib.errors import StrictCommitFailed
 
272
        b = Branch.initialize('.')
 
273
        file('hello', 'w').write('hello world')
 
274
        b.add('hello')
 
275
        file('goodbye', 'w').write('goodbye cruel world!')
 
276
        self.assertRaises(StrictCommitFailed, b.commit,
 
277
            message='add hello but not goodbye', strict=True)
 
278
 
 
279
    def test_strict_commit_without_unknowns(self):
 
280
        """Try and commit with no unknown files and strict = True,
 
281
        should work."""
 
282
        from bzrlib.errors import StrictCommitFailed
 
283
        b = Branch.initialize('.')
 
284
        file('hello', 'w').write('hello world')
 
285
        b.add('hello')
 
286
        b.commit(message='add hello', strict=True)
 
287
 
 
288
    def test_nonstrict_commit(self):
 
289
        """Try and commit with unknown files and strict = False, should work."""
 
290
        b = Branch.initialize('.')
 
291
        file('hello', 'w').write('hello world')
 
292
        b.add('hello')
 
293
        file('goodbye', 'w').write('goodbye cruel world!')
 
294
        b.commit(message='add hello but not goodbye', strict=False)
 
295
 
 
296
    def test_nonstrict_commit_without_unknowns(self):
 
297
        """Try and commit with no unknown files and strict = False,
 
298
        should work."""
 
299
        b = Branch.initialize('.')
 
300
        file('hello', 'w').write('hello world')
 
301
        b.add('hello')
 
302
        b.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
        branch = Branch.initialize('.')
 
309
        branch.commit("base", allow_pointless=True, rev_id='A')
 
310
        self.failIf(branch.revision_store.has_id('A', 'sig'))
 
311
        try:
 
312
            from bzrlib.testament import Testament
 
313
            # monkey patch gpg signing mechanism
 
314
            bzrlib.gpg.GPGStrategy = bzrlib.gpg.LoopbackGPGStrategy
 
315
            commit.Commit(config=MustSignConfig(branch)).commit(branch, "base",
 
316
                                                      allow_pointless=True,
 
317
                                                      rev_id='B')
 
318
            self.assertEqual(Testament.from_revision(branch,'B').as_short_text(),
 
319
                             branch.revision_store.get('B', 'sig').read())
 
320
        finally:
 
321
            bzrlib.gpg.GPGStrategy = oldstrategy
 
322
 
 
323
    def test_commit_failed_signature(self):
 
324
        import bzrlib.gpg
 
325
        import bzrlib.commit as commit
 
326
        oldstrategy = bzrlib.gpg.GPGStrategy
 
327
        branch = Branch.initialize('.')
 
328
        branch.commit("base", allow_pointless=True, rev_id='A')
 
329
        self.failIf(branch.revision_store.has_id('A', 'sig'))
 
330
        try:
 
331
            from bzrlib.testament import Testament
 
332
            # monkey patch gpg signing mechanism
 
333
            bzrlib.gpg.GPGStrategy = bzrlib.gpg.DisabledGPGStrategy
 
334
            config = MustSignConfig(branch)
 
335
            self.assertRaises(SigningFailed,
 
336
                              commit.Commit(config=config).commit,
 
337
                              branch, "base",
 
338
                              allow_pointless=True,
 
339
                              rev_id='B')
 
340
            branch = Branch.open('.')
 
341
            self.assertEqual(branch.revision_history(), ['A'])
 
342
            self.failIf(branch.revision_store.has_id('B'))
 
343
        finally:
 
344
            bzrlib.gpg.GPGStrategy = oldstrategy
 
345
 
 
346
    def test_commit_invokes_hooks(self):
 
347
        import bzrlib.commit as commit
 
348
        branch = Branch.initialize('.')
 
349
        calls = []
 
350
        def called(branch, rev_id):
 
351
            calls.append('called')
 
352
        bzrlib.ahook = called
 
353
        try:
 
354
            config = BranchWithHooks(branch)
 
355
            commit.Commit(config=config).commit(
 
356
                            branch, "base",
 
357
                            allow_pointless=True,
 
358
                            rev_id='A')
 
359
            self.assertEqual(['called', 'called'], calls)
 
360
        finally:
 
361
            del bzrlib.ahook