17
17
"""Tests for the BranchBuilder class."""
20
20
branch as _mod_branch,
21
21
revision as _mod_revision,
25
branch as _mod_bzrbranch,
27
from ..branchbuilder import BranchBuilder
24
from bzrlib.branchbuilder import BranchBuilder
30
27
class TestBranchBuilder(tests.TestCaseWithMemoryTransport):
49
46
"""Making a BranchBuilder with a format option sets the branch type."""
50
47
builder = BranchBuilder(self.get_transport(), format='dirstate-tags')
51
48
branch = builder.get_branch()
52
self.assertIsInstance(branch, _mod_bzrbranch.BzrBranch6)
49
self.assertIsInstance(branch, _mod_branch.BzrBranch6)
54
51
def test_build_one_commit(self):
55
52
"""doing build_commit causes a commit to happen."""
117
114
def build_a_rev(self):
118
115
builder = BranchBuilder(self.get_transport().clone('foo'))
119
rev_id1 = builder.build_snapshot(None,
116
rev_id1 = builder.build_snapshot('A-id', None,
120
117
[('add', ('', 'a-root-id', 'directory', None)),
121
('add', ('a', 'a-id', 'file', 'contents'))],
118
('add', ('a', 'a-id', 'file', 'contents'))])
123
119
self.assertEqual('A-id', rev_id1)
132
128
self.addCleanup(rev_tree.unlock)
133
129
self.assertTreeShape([(u'', 'a-root-id', 'directory'),
134
130
(u'a', 'a-id', 'file')], rev_tree)
135
self.assertEqual('contents', rev_tree.get_file_text('a'))
131
self.assertEqual('contents', rev_tree.get_file_text('a-id'))
137
133
def test_add_second_file(self):
138
134
builder = self.build_a_rev()
139
rev_id2 = builder.build_snapshot(None,
140
[('add', ('b', 'b-id', 'file', 'content_b'))],
135
rev_id2 = builder.build_snapshot('B-id', None,
136
[('add', ('b', 'b-id', 'file', 'content_b'))])
142
137
self.assertEqual('B-id', rev_id2)
143
138
branch = builder.get_branch()
144
139
self.assertEqual((2, rev_id2), branch.last_revision_info())
148
143
self.assertTreeShape([(u'', 'a-root-id', 'directory'),
149
144
(u'a', 'a-id', 'file'),
150
145
(u'b', 'b-id', 'file')], rev_tree)
151
self.assertEqual('content_b', rev_tree.get_file_text('b'))
146
self.assertEqual('content_b', rev_tree.get_file_text('b-id'))
153
148
def test_add_empty_dir(self):
154
149
builder = self.build_a_rev()
155
rev_id2 = builder.build_snapshot(None,
156
[('add', ('b', 'b-id', 'directory', None))],
150
rev_id2 = builder.build_snapshot('B-id', None,
151
[('add', ('b', 'b-id', 'directory', None))])
158
152
rev_tree = builder.get_branch().repository.revision_tree('B-id')
159
153
self.assertTreeShape([(u'', 'a-root-id', 'directory'),
160
154
(u'a', 'a-id', 'file'),
164
158
def test_commit_timestamp(self):
165
159
builder = self.make_branch_builder('foo')
166
rev_id = builder.build_snapshot(None,
160
rev_id = builder.build_snapshot(None, None,
167
161
[('add', (u'', None, 'directory', None))],
168
162
timestamp=1234567890)
169
163
rev = builder.get_branch().repository.get_revision(rev_id)
174
168
def test_commit_message_default(self):
175
169
builder = BranchBuilder(self.get_transport().clone('foo'))
176
rev_id = builder.build_snapshot(None,
170
rev_id = builder.build_snapshot(None, None,
177
171
[('add', (u'', None, 'directory', None))])
178
172
branch = builder.get_branch()
179
173
rev = branch.repository.get_revision(rev_id)
182
176
def test_commit_message_supplied(self):
183
177
builder = BranchBuilder(self.get_transport().clone('foo'))
184
rev_id = builder.build_snapshot(None,
178
rev_id = builder.build_snapshot(None, None,
185
179
[('add', (u'', None, 'directory', None))],
187
181
branch = builder.get_branch()
191
185
def test_commit_message_callback(self):
192
186
builder = BranchBuilder(self.get_transport().clone('foo'))
193
rev_id = builder.build_snapshot(None,
187
rev_id = builder.build_snapshot(None, None,
194
188
[('add', (u'', None, 'directory', None))],
195
189
message_callback=lambda x:u'Foo')
196
190
branch = builder.get_branch()
200
194
def test_modify_file(self):
201
195
builder = self.build_a_rev()
202
rev_id2 = builder.build_snapshot(None,
203
[('modify', ('a', 'new\ncontent\n'))],
196
rev_id2 = builder.build_snapshot('B-id', None,
197
[('modify', ('a-id', 'new\ncontent\n'))])
205
198
self.assertEqual('B-id', rev_id2)
206
199
branch = builder.get_branch()
207
200
rev_tree = branch.repository.revision_tree(rev_id2)
208
201
rev_tree.lock_read()
209
202
self.addCleanup(rev_tree.unlock)
210
self.assertEqual('new\ncontent\n',
211
rev_tree.get_file_text(rev_tree.id2path(b'a-id')))
203
self.assertEqual('new\ncontent\n', rev_tree.get_file_text('a-id'))
213
205
def test_delete_file(self):
214
206
builder = self.build_a_rev()
215
rev_id2 = builder.build_snapshot(None,
216
[('unversion', 'a')], revision_id='B-id')
207
rev_id2 = builder.build_snapshot('B-id', None,
208
[('unversion', 'a-id')])
217
209
self.assertEqual('B-id', rev_id2)
218
210
branch = builder.get_branch()
219
211
rev_tree = branch.repository.revision_tree(rev_id2)
224
216
def test_delete_directory(self):
225
217
builder = self.build_a_rev()
226
rev_id2 = builder.build_snapshot(None,
218
rev_id2 = builder.build_snapshot('B-id', None,
227
219
[('add', ('b', 'b-id', 'directory', None)),
228
220
('add', ('b/c', 'c-id', 'file', 'foo\n')),
229
221
('add', ('b/d', 'd-id', 'directory', None)),
230
222
('add', ('b/d/e', 'e-id', 'file', 'eff\n')),
231
], revision_id='B-id')
232
224
rev_tree = builder.get_branch().repository.revision_tree('B-id')
233
225
self.assertTreeShape([(u'', 'a-root-id', 'directory'),
234
226
(u'a', 'a-id', 'file'),
237
229
(u'b/d', 'd-id', 'directory'),
238
230
(u'b/d/e', 'e-id', 'file')], rev_tree)
239
231
# Removing a directory removes all child dirs
240
builder.build_snapshot(
241
None, [('unversion', 'b')],
232
builder.build_snapshot('C-id', None, [('unversion', 'b-id')])
243
233
rev_tree = builder.get_branch().repository.revision_tree('C-id')
244
234
self.assertTreeShape([(u'', 'a-root-id', 'directory'),
245
235
(u'a', 'a-id', 'file'),
248
238
def test_unknown_action(self):
249
239
builder = self.build_a_rev()
250
240
e = self.assertRaises(ValueError,
251
builder.build_snapshot, None, [('weirdo', ('foo',))],
241
builder.build_snapshot, 'B-id', None, [('weirdo', ('foo',))])
253
242
self.assertEqual('Unknown build action: "weirdo"', str(e))
255
244
def test_rename(self):
256
245
builder = self.build_a_rev()
257
builder.build_snapshot(None,
258
[('rename', ('a', 'b'))], revision_id='B-id')
246
builder.build_snapshot('B-id', None,
247
[('rename', ('a', 'b'))])
259
248
rev_tree = builder.get_branch().repository.revision_tree('B-id')
260
249
self.assertTreeShape([(u'', 'a-root-id', 'directory'),
261
250
(u'b', 'a-id', 'file')], rev_tree)
263
252
def test_rename_into_subdir(self):
264
253
builder = self.build_a_rev()
265
builder.build_snapshot(None,
254
builder.build_snapshot('B-id', None,
266
255
[('add', ('dir', 'dir-id', 'directory', None)),
267
('rename', ('a', 'dir/a'))], revision_id='B-id')
256
('rename', ('a', 'dir/a'))])
268
257
rev_tree = builder.get_branch().repository.revision_tree('B-id')
269
258
self.assertTreeShape([(u'', 'a-root-id', 'directory'),
270
259
(u'dir', 'dir-id', 'directory'),
273
262
def test_rename_out_of_unversioned_subdir(self):
274
263
builder = self.build_a_rev()
275
builder.build_snapshot(None,
264
builder.build_snapshot('B-id', None,
276
265
[('add', ('dir', 'dir-id', 'directory', None)),
277
('rename', ('a', 'dir/a'))],
279
builder.build_snapshot(None,
266
('rename', ('a', 'dir/a'))])
267
builder.build_snapshot('C-id', None,
280
268
[('rename', ('dir/a', 'a')),
281
('unversion', 'dir')], revision_id='C-id')
269
('unversion', 'dir-id')])
282
270
rev_tree = builder.get_branch().repository.revision_tree('C-id')
283
271
self.assertTreeShape([(u'', 'a-root-id', 'directory'),
284
272
(u'a', 'a-id', 'file')], rev_tree)
287
275
builder = self.build_a_rev()
288
276
builder.start_series()
289
277
self.addCleanup(builder.finish_series)
290
builder.build_snapshot(['A-id'],
291
[('modify', ('a', 'new\ncontent\n'))],
293
builder.build_snapshot(['A-id'],
294
[('add', ('c', 'c-id', 'file', 'alt\ncontent\n'))],
278
builder.build_snapshot('B-id', ['A-id'],
279
[('modify', ('a-id', 'new\ncontent\n'))])
280
builder.build_snapshot('C-id', ['A-id'],
281
[('add', ('c', 'c-id', 'file', 'alt\ncontent\n'))])
296
282
# We should now have a graph:
305
291
self.assertTreeShape([(u'', 'a-root-id', 'directory'),
306
292
(u'a', 'a-id', 'file'),
308
self.assertEqual('new\ncontent\n', b_tree.get_file_text('a'))
294
self.assertEqual('new\ncontent\n', b_tree.get_file_text('a-id'))
310
296
# We should still be using the content from A in C, not from B
311
297
c_tree = repo.revision_tree('C-id')
313
299
(u'a', 'a-id', 'file'),
314
300
(u'c', 'c-id', 'file'),
316
self.assertEqual('contents', c_tree.get_file_text('a'))
317
self.assertEqual('alt\ncontent\n', c_tree.get_file_text('c'))
302
self.assertEqual('contents', c_tree.get_file_text('a-id'))
303
self.assertEqual('alt\ncontent\n', c_tree.get_file_text('c-id'))
319
305
def test_set_merge_parent(self):
320
306
builder = self.build_a_rev()
321
307
builder.start_series()
322
308
self.addCleanup(builder.finish_series)
323
builder.build_snapshot(['A-id'],
324
[('add', ('b', 'b-id', 'file', 'b\ncontent\n'))],
326
builder.build_snapshot(['A-id'],
327
[('add', ('c', 'c-id', 'file', 'alt\ncontent\n'))],
329
builder.build_snapshot(['B-id', 'C-id'], [], revision_id='D-id')
309
builder.build_snapshot('B-id', ['A-id'],
310
[('add', ('b', 'b-id', 'file', 'b\ncontent\n'))])
311
builder.build_snapshot('C-id', ['A-id'],
312
[('add', ('c', 'c-id', 'file', 'alt\ncontent\n'))])
313
builder.build_snapshot('D-id', ['B-id', 'C-id'], [])
330
314
repo = builder.get_branch().repository
331
315
self.assertEqual({'B-id': ('A-id',), 'C-id': ('A-id',),
332
316
'D-id': ('B-id', 'C-id')},
343
327
builder = self.build_a_rev()
344
328
builder.start_series()
345
329
self.addCleanup(builder.finish_series)
346
builder.build_snapshot(['A-id'],
347
[('add', ('b', 'b-id', 'file', 'b\ncontent\n'))],
349
builder.build_snapshot(['A-id'],
350
[('add', ('c', 'c-id', 'file', 'alt\ncontent\n'))],
352
builder.build_snapshot(['B-id', 'C-id'],
353
[('add', ('c', 'c-id', 'file', 'alt\ncontent\n'))],
330
builder.build_snapshot('B-id', ['A-id'],
331
[('add', ('b', 'b-id', 'file', 'b\ncontent\n'))])
332
builder.build_snapshot('C-id', ['A-id'],
333
[('add', ('c', 'c-id', 'file', 'alt\ncontent\n'))])
334
builder.build_snapshot('D-id', ['B-id', 'C-id'],
335
[('add', ('c', 'c-id', 'file', 'alt\ncontent\n'))])
355
336
repo = builder.get_branch().repository
356
337
self.assertEqual({'B-id': ('A-id',), 'C-id': ('A-id',),
357
338
'D-id': ('B-id', 'C-id')},
365
346
# Because we copied the exact text into *this* tree, the 'c' file
366
347
# should look like it was not modified in the merge
367
self.assertEqual('C-id', d_tree.get_file_revision('c'))
348
self.assertEqual('C-id', d_tree.get_file_revision('c-id'))
369
350
def test_set_parent_to_null(self):
370
351
builder = self.build_a_rev()
371
352
builder.start_series()
372
353
self.addCleanup(builder.finish_series)
373
builder.build_snapshot([],
374
[('add', ('', None, 'directory', None))],
354
builder.build_snapshot('B-id', [],
355
[('add', ('', None, 'directory', None))])
376
356
# We should now have a graph:
398
378
builder = BranchBuilder(self.get_transport().clone('foo'))
399
379
builder.start_series()
401
builder.build_snapshot(['ghost'],
381
builder.build_snapshot('tip', ['ghost'],
402
382
[('add', ('', 'ROOT_ID', 'directory', ''))],
403
allow_leftmost_as_ghost=True, revision_id='tip')
383
allow_leftmost_as_ghost=True)
405
385
builder.finish_series()
406
386
b = builder.get_branch()
412
392
def test_unversion_root_add_new_root(self):
413
393
builder = BranchBuilder(self.get_transport().clone('foo'))
414
394
builder.start_series()
415
builder.build_snapshot(None,
416
[('add', ('', 'TREE_ROOT', 'directory', ''))],
418
builder.build_snapshot(None,
420
('add', ('', 'my-root', 'directory', ''))],
395
builder.build_snapshot('rev-1', None,
396
[('add', ('', 'TREE_ROOT', 'directory', ''))])
397
builder.build_snapshot('rev-2', None,
398
[('unversion', 'TREE_ROOT'),
399
('add', ('', 'my-root', 'directory', ''))])
422
400
builder.finish_series()
423
401
rev_tree = builder.get_branch().repository.revision_tree('rev-2')
424
402
self.assertTreeShape([(u'', 'my-root', 'directory')], rev_tree)
427
405
"""A flush with no actions before it is a no-op."""
428
406
builder = BranchBuilder(self.get_transport().clone('foo'))
429
407
builder.start_series()
430
builder.build_snapshot(None,
431
[('add', ('', 'TREE_ROOT', 'directory', ''))],
433
builder.build_snapshot(None, [('flush', None)], revision_id='rev-2')
408
builder.build_snapshot('rev-1', None,
409
[('add', ('', 'TREE_ROOT', 'directory', ''))])
410
builder.build_snapshot('rev-2', None, [('flush', None)])
434
411
builder.finish_series()
435
412
rev_tree = builder.get_branch().repository.revision_tree('rev-2')
436
413
self.assertTreeShape([(u'', 'TREE_ROOT', 'directory')], rev_tree)
442
419
builder = BranchBuilder(self.get_transport().clone('foo'))
443
420
builder.start_series()
444
builder.build_snapshot(None,
421
builder.build_snapshot('A-id', None,
445
422
[('add', (u'', 'a-root-id', 'directory', None)),
446
('add', (u'a', 'a-id', 'file', 'content\n'))],
448
builder.build_snapshot(None,
423
('add', (u'a', 'a-id', 'file', 'content\n'))])
424
builder.build_snapshot('B-id', None,
425
[('unversion', 'a-id'),
451
('add', (u'a', 'a-id', 'directory', None))],
427
('add', (u'a', 'a-id', 'directory', None))])
453
428
builder.finish_series()
454
429
rev_tree = builder.get_branch().repository.revision_tree('B-id')
455
430
self.assertTreeShape(
463
438
builder = BranchBuilder(self.get_transport().clone('foo'))
464
439
builder.start_series()
465
builder.build_snapshot(None,
440
builder.build_snapshot('A-id', None,
466
441
[('add', (u'', 'orig-root', 'directory', None)),
467
('add', (u'dir', 'dir-id', 'directory', None))],
469
builder.build_snapshot(None,
470
[('unversion', ''), # implicitly unversions all children
442
('add', (u'dir', 'dir-id', 'directory', None))])
443
builder.build_snapshot('B-id', None,
444
[('unversion', 'orig-root'), # implicitly unversions all children
472
('add', (u'', 'dir-id', 'directory', None))],
446
('add', (u'', 'dir-id', 'directory', None))])
474
447
builder.finish_series()
475
448
rev_tree = builder.get_branch().repository.revision_tree('B-id')
476
449
self.assertTreeShape([(u'', 'dir-id', 'directory')], rev_tree)