1
# Copyright (C) 2005 by Canonical Ltd
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.
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.
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
20
from bzrlib.selftest import TestCaseInTempDir
21
from bzrlib.branch import Branch
22
from bzrlib.commit import Commit
23
from bzrlib.config import BranchConfig
24
from bzrlib.errors import PointlessCommit, BzrError, SigningFailed
27
# TODO: Test commit with some added, and added-but-missing files
29
class MustSignConfig(BranchConfig):
31
def signature_needed(self):
34
def gpg_signing_command(self):
38
class TestCommit(TestCaseInTempDir):
40
def test_simple_commit(self):
41
"""Commit and check two versions of a single file."""
42
b = Branch.initialize('.')
43
file('hello', 'w').write('hello world')
45
b.commit(message='add hello')
46
file_id = b.working_tree().path2id('hello')
48
file('hello', 'w').write('version 2')
49
b.commit(message='commit 2')
51
eq = self.assertEquals
53
rh = b.revision_history()
54
rev = b.get_revision(rh[0])
55
eq(rev.message, 'add hello')
57
tree1 = b.revision_tree(rh[0])
58
text = tree1.get_file_text(file_id)
59
eq(text, 'hello world')
61
tree2 = b.revision_tree(rh[1])
62
eq(tree2.get_file_text(file_id), 'version 2')
64
def test_delete_commit(self):
65
"""Test a commit with a deleted file"""
66
b = Branch.initialize('.')
67
file('hello', 'w').write('hello world')
68
b.add(['hello'], ['hello-id'])
69
b.commit(message='add hello')
72
b.commit('removed hello', rev_id='rev2')
74
tree = b.revision_tree('rev2')
75
self.assertFalse(tree.has_id('hello-id'))
78
def test_pointless_commit(self):
79
"""Commit refuses unless there are changes or it's forced."""
80
b = Branch.initialize('.')
81
file('hello', 'w').write('hello')
83
b.commit(message='add hello')
84
self.assertEquals(b.revno(), 1)
85
self.assertRaises(PointlessCommit,
88
allow_pointless=False)
89
self.assertEquals(b.revno(), 1)
93
def test_commit_empty(self):
94
"""Commiting an empty tree works."""
95
b = Branch.initialize('.')
96
b.commit(message='empty tree', allow_pointless=True)
97
self.assertRaises(PointlessCommit,
100
allow_pointless=False)
101
b.commit(message='empty tree', allow_pointless=True)
102
self.assertEquals(b.revno(), 2)
105
def test_selective_delete(self):
106
"""Selective commit in tree with deletions"""
107
b = Branch.initialize('.')
108
file('hello', 'w').write('hello')
109
file('buongia', 'w').write('buongia')
110
b.add(['hello', 'buongia'],
111
['hello-id', 'buongia-id'])
112
b.commit(message='add files',
116
file('buongia', 'w').write('new text')
117
b.commit(message='update text',
118
specific_files=['buongia'],
119
allow_pointless=False,
122
b.commit(message='remove hello',
123
specific_files=['hello'],
124
allow_pointless=False,
127
eq = self.assertEquals
130
tree2 = b.revision_tree('test@rev-2')
131
self.assertTrue(tree2.has_filename('hello'))
132
self.assertEquals(tree2.get_file_text('hello-id'), 'hello')
133
self.assertEquals(tree2.get_file_text('buongia-id'), 'new text')
135
tree3 = b.revision_tree('test@rev-3')
136
self.assertFalse(tree3.has_filename('hello'))
137
self.assertEquals(tree3.get_file_text('buongia-id'), 'new text')
140
def test_commit_rename(self):
141
"""Test commit of a revision where a file is renamed."""
142
b = Branch.initialize('.')
143
self.build_tree(['hello'])
144
b.add(['hello'], ['hello-id'])
145
b.commit(message='one', rev_id='test@rev-1', allow_pointless=False)
147
b.rename_one('hello', 'fruity')
148
b.commit(message='renamed', rev_id='test@rev-2', allow_pointless=False)
150
eq = self.assertEquals
151
tree1 = b.revision_tree('test@rev-1')
152
eq(tree1.id2path('hello-id'), 'hello')
153
eq(tree1.get_file_text('hello-id'), 'contents of hello\n')
154
self.assertFalse(tree1.has_filename('fruity'))
155
self.check_inventory_shape(tree1.inventory, ['hello'])
156
ie = tree1.inventory['hello-id']
157
eq(ie.revision, 'test@rev-1')
159
tree2 = b.revision_tree('test@rev-2')
160
eq(tree2.id2path('hello-id'), 'fruity')
161
eq(tree2.get_file_text('hello-id'), 'contents of hello\n')
162
self.check_inventory_shape(tree2.inventory, ['fruity'])
163
ie = tree2.inventory['hello-id']
164
eq(ie.revision, 'test@rev-2')
167
def test_reused_rev_id(self):
168
"""Test that a revision id cannot be reused in a branch"""
169
b = Branch.initialize('.')
170
b.commit('initial', rev_id='test@rev-1', allow_pointless=True)
171
self.assertRaises(Exception,
175
allow_pointless=True)
179
def test_commit_move(self):
180
"""Test commit of revisions with moved files and directories"""
181
eq = self.assertEquals
182
b = Branch.initialize('.')
184
self.build_tree(['hello', 'a/', 'b/'])
185
b.add(['hello', 'a', 'b'], ['hello-id', 'a-id', 'b-id'])
186
b.commit('initial', rev_id=r1, allow_pointless=False)
188
b.move(['hello'], 'a')
190
b.commit('two', rev_id=r2, allow_pointless=False)
191
self.check_inventory_shape(b.inventory,
192
['a', 'a/hello', 'b'])
196
b.commit('three', rev_id=r3, allow_pointless=False)
197
self.check_inventory_shape(b.inventory,
198
['a', 'a/hello', 'a/b'])
199
self.check_inventory_shape(b.get_revision_inventory(r3),
200
['a', 'a/hello', 'a/b'])
202
b.move([os.sep.join(['a', 'hello'])],
203
os.sep.join(['a', 'b']))
205
b.commit('four', rev_id=r4, allow_pointless=False)
206
self.check_inventory_shape(b.inventory,
207
['a', 'a/b/hello', 'a/b'])
209
inv = b.get_revision_inventory(r4)
210
eq(inv['hello-id'].revision, r4)
211
eq(inv['a-id'].revision, r1)
212
eq(inv['b-id'].revision, r3)
215
def test_removed_commit(self):
216
"""Test a commit with a removed file"""
217
b = Branch.initialize('.')
218
file('hello', 'w').write('hello world')
219
b.add(['hello'], ['hello-id'])
220
b.commit(message='add hello')
223
b.commit('removed hello', rev_id='rev2')
225
tree = b.revision_tree('rev2')
226
self.assertFalse(tree.has_id('hello-id'))
229
def test_committed_ancestry(self):
230
"""Test commit appends revisions to ancestry."""
231
b = Branch.initialize('.')
234
file('hello', 'w').write((str(i) * 4) + '\n')
236
b.add(['hello'], ['hello-id'])
237
rev_id = 'test@rev-%d' % (i+1)
238
rev_ids.append(rev_id)
239
b.commit(message='rev %d' % (i+1),
241
eq = self.assertEquals
242
eq(b.revision_history(), rev_ids)
244
anc = b.get_ancestry(rev_ids[i])
245
eq(anc, [None] + rev_ids[:i+1])
247
def test_commit_new_subdir_child_selective(self):
248
b = Branch.initialize('.')
249
self.build_tree(['dir/', 'dir/file1', 'dir/file2'])
250
b.add(['dir', 'dir/file1', 'dir/file2'],
251
['dirid', 'file1id', 'file2id'])
252
b.commit('dir/file1', specific_files=['dir/file1'], rev_id='1')
253
inv = b.get_inventory('1')
254
self.assertEqual('1', inv['dirid'].revision)
255
self.assertEqual('1', inv['file1id'].revision)
256
# FIXME: This should raise a KeyError I think, rbc20051006
257
self.assertRaises(BzrError, inv.__getitem__, 'file2id')
259
def test_signed_commit(self):
261
import bzrlib.commit as commit
262
oldstrategy = bzrlib.gpg.GPGStrategy
263
branch = Branch.initialize('.')
264
branch.commit("base", allow_pointless=True, rev_id='A')
265
self.failIf(branch.revision_store.has_id('A', 'sig'))
267
from bzrlib.testament import Testament
268
# monkey patch gpg signing mechanism
269
bzrlib.gpg.GPGStrategy = bzrlib.gpg.LoopbackGPGStrategy
270
commit.Commit(config=MustSignConfig(branch)).commit(branch, "base",
271
allow_pointless=True,
273
self.assertEqual(Testament.from_revision(branch,'B').as_short_text(),
274
branch.revision_store.get('B', 'sig').read())
276
bzrlib.gpg.GPGStrategy = oldstrategy
278
def test_commit_failed_signature(self):
280
import bzrlib.commit as commit
281
oldstrategy = bzrlib.gpg.GPGStrategy
282
branch = Branch.initialize('.')
283
branch.commit("base", allow_pointless=True, rev_id='A')
284
self.failIf(branch.revision_store.has_id('A', 'sig'))
286
from bzrlib.testament import Testament
287
# monkey patch gpg signing mechanism
288
bzrlib.gpg.GPGStrategy = bzrlib.gpg.DisabledGPGStrategy
289
config = MustSignConfig(branch)
290
self.assertRaises(SigningFailed,
291
commit.Commit(config=config).commit,
293
allow_pointless=True,
295
branch = Branch.open('.')
296
self.assertEqual(branch.revision_history(), ['A'])
297
self.failIf(branch.revision_store.has_id('B'))
299
bzrlib.gpg.GPGStrategy = oldstrategy