~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/selftest/test_commit.py

  • Committer: Robert Collins
  • Date: 2005-10-24 13:59:18 UTC
  • mfrom: (1185.20.1)
  • Revision ID: robertc@robertcollins.net-20051024135918-024629d7ee347b5c
fix upgrading of trees with no commits

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_nonstrict_commit(self):
 
280
        """Try and commit with unknown files and strict = False, should work."""
 
281
        b = Branch.initialize('.')
 
282
        file('hello', 'w').write('hello world')
 
283
        b.add('hello')
 
284
        file('goodbye', 'w').write('goodbye cruel world!')
 
285
        b.commit(message='add hello but not goodbye', strict=False)
 
286
 
 
287
    def test_signed_commit(self):
 
288
        import bzrlib.gpg
 
289
        import bzrlib.commit as commit
 
290
        oldstrategy = bzrlib.gpg.GPGStrategy
 
291
        branch = Branch.initialize('.')
 
292
        branch.commit("base", allow_pointless=True, rev_id='A')
 
293
        self.failIf(branch.revision_store.has_id('A', 'sig'))
 
294
        try:
 
295
            from bzrlib.testament import Testament
 
296
            # monkey patch gpg signing mechanism
 
297
            bzrlib.gpg.GPGStrategy = bzrlib.gpg.LoopbackGPGStrategy
 
298
            commit.Commit(config=MustSignConfig(branch)).commit(branch, "base",
 
299
                                                      allow_pointless=True,
 
300
                                                      rev_id='B')
 
301
            self.assertEqual(Testament.from_revision(branch,'B').as_short_text(),
 
302
                             branch.revision_store.get('B', 'sig').read())
 
303
        finally:
 
304
            bzrlib.gpg.GPGStrategy = oldstrategy
 
305
 
 
306
    def test_commit_failed_signature(self):
 
307
        import bzrlib.gpg
 
308
        import bzrlib.commit as commit
 
309
        oldstrategy = bzrlib.gpg.GPGStrategy
 
310
        branch = Branch.initialize('.')
 
311
        branch.commit("base", allow_pointless=True, rev_id='A')
 
312
        self.failIf(branch.revision_store.has_id('A', 'sig'))
 
313
        try:
 
314
            from bzrlib.testament import Testament
 
315
            # monkey patch gpg signing mechanism
 
316
            bzrlib.gpg.GPGStrategy = bzrlib.gpg.DisabledGPGStrategy
 
317
            config = MustSignConfig(branch)
 
318
            self.assertRaises(SigningFailed,
 
319
                              commit.Commit(config=config).commit,
 
320
                              branch, "base",
 
321
                              allow_pointless=True,
 
322
                              rev_id='B')
 
323
            branch = Branch.open('.')
 
324
            self.assertEqual(branch.revision_history(), ['A'])
 
325
            self.failIf(branch.revision_store.has_id('B'))
 
326
        finally:
 
327
            bzrlib.gpg.GPGStrategy = oldstrategy
 
328
 
 
329
    def test_commit_invokes_hooks(self):
 
330
        import bzrlib.commit as commit
 
331
        branch = Branch.initialize('.')
 
332
        calls = []
 
333
        def called(branch, rev_id):
 
334
            calls.append('called')
 
335
        bzrlib.ahook = called
 
336
        try:
 
337
            config = BranchWithHooks(branch)
 
338
            commit.Commit(config=config).commit(
 
339
                            branch, "base",
 
340
                            allow_pointless=True,
 
341
                            rev_id='A')
 
342
            self.assertEqual(['called', 'called'], calls)
 
343
        finally:
 
344
            del bzrlib.ahook