191
179
def test_find_format_string(self):
192
180
# is the right format object found for a working tree?
193
181
branch = self.make_branch('branch')
195
errors.NoWorkingTree,
196
bzrworkingtree.WorkingTreeFormatMetaDir.find_format_string,
198
transport = branch.controldir.get_workingtree_transport(None)
182
self.assertRaises(errors.NoWorkingTree,
183
workingtree.WorkingTreeFormatMetaDir.find_format_string, branch.bzrdir)
184
transport = branch.bzrdir.get_workingtree_transport(None)
199
185
transport.mkdir('.')
200
transport.put_bytes("format", b"some format name")
186
transport.put_bytes("format", "some format name")
201
187
# The format does not have to be known by Bazaar,
202
188
# find_format_string just retrieves the name
205
bzrworkingtree.WorkingTreeFormatMetaDir.find_format_string(
189
self.assertEqual("some format name",
190
workingtree.WorkingTreeFormatMetaDir.find_format_string(branch.bzrdir))
208
192
def test_find_format(self):
209
193
# is the right format object found for a working tree?
210
194
# create a branch with a few known format objects.
211
195
self.build_tree(["foo/", "bar/"])
213
196
def check_format(format, url):
214
dir = format._matchingcontroldir.initialize(url)
197
dir = format._matchingbzrdir.initialize(url)
215
198
dir.create_repository()
216
199
dir.create_branch()
217
200
format.initialize(dir)
218
found_format = bzrworkingtree.WorkingTreeFormatMetaDir.find_format(
201
t = transport.get_transport(url)
202
found_format = workingtree.WorkingTreeFormatMetaDir.find_format(dir)
220
203
self.assertIsInstance(found_format, format.__class__)
221
204
check_format(workingtree_3.WorkingTreeFormat3(), "bar")
223
206
def test_find_format_no_tree(self):
224
207
dir = bzrdir.BzrDirMetaFormat1().initialize('.')
225
208
self.assertRaises(errors.NoWorkingTree,
226
bzrworkingtree.WorkingTreeFormatMetaDir.find_format,
209
workingtree.WorkingTreeFormatMetaDir.find_format,
229
212
def test_find_format_unknown_format(self):
232
215
dir.create_branch()
233
216
SampleTreeFormat().initialize(dir)
234
217
self.assertRaises(errors.UnknownFormatError,
235
bzrworkingtree.WorkingTreeFormatMetaDir.find_format,
218
workingtree.WorkingTreeFormatMetaDir.find_format,
238
221
def test_find_format_with_features(self):
239
222
tree = self.make_branch_and_tree('.', format='2a')
240
tree.update_feature_flags({b"name": b"necessity"})
241
found_format = bzrworkingtree.WorkingTreeFormatMetaDir.find_format(
223
tree.update_feature_flags({"name": "necessity"})
224
found_format = workingtree.WorkingTreeFormatMetaDir.find_format(
243
226
self.assertIsInstance(found_format, workingtree.WorkingTreeFormat)
244
self.assertEqual(found_format.features.get(b"name"), b"necessity")
246
bzrdir.MissingFeature, found_format.check_support_status, True)
248
bzrworkingtree.WorkingTreeFormatMetaDir.unregister_feature,
250
bzrworkingtree.WorkingTreeFormatMetaDir.register_feature(b"name")
227
self.assertEqual(found_format.features.get("name"), "necessity")
228
self.assertRaises(errors.MissingFeature, found_format.check_support_status,
230
self.addCleanup(workingtree.WorkingTreeFormatMetaDir.unregister_feature,
232
workingtree.WorkingTreeFormatMetaDir.register_feature("name")
251
233
found_format.check_support_status(True)
256
238
def make_simple_tree(self):
257
239
tree = self.make_branch_and_tree('tree', format='development-subtree')
258
240
self.build_tree(['tree/a/', 'tree/a/b/', 'tree/a/b/c'])
259
tree.set_root_id(b'root-id')
260
tree.add(['a', 'a/b', 'a/b/c'], [b'a-id', b'b-id', b'c-id'])
241
tree.set_root_id('root-id')
242
tree.add(['a', 'a/b', 'a/b/c'], ['a-id', 'b-id', 'c-id'])
261
243
tree.commit('initial')
264
246
def test_just_directory(self):
265
247
tree = self.make_simple_tree()
266
self.assertEqual([('directory', b'root-id'),
267
('directory', b'a-id'),
268
('directory', b'b-id'),
248
self.assertEqual([('directory', 'root-id'),
249
('directory', 'a-id'),
250
('directory', 'b-id'),
270
252
[(ie.kind, ie.file_id)
271
253
for path, ie in tree.iter_entries_by_dir()])
272
self.make_branch_and_tree('tree/a/b')
273
self.assertEqual([('tree-reference', b'b-id')],
254
subtree = self.make_branch_and_tree('tree/a/b')
255
self.assertEqual([('tree-reference', 'b-id')],
274
256
[(ie.kind, ie.file_id)
275
for path, ie in tree.iter_entries_by_dir(
276
specific_files=['a/b'])])
257
for path, ie in tree.iter_entries_by_dir(['b-id'])])
278
259
def test_direct_subtree(self):
279
260
tree = self.make_simple_tree()
280
self.make_branch_and_tree('tree/a/b')
281
self.assertEqual([('directory', b'root-id'),
282
('directory', b'a-id'),
283
('tree-reference', b'b-id')],
261
subtree = self.make_branch_and_tree('tree/a/b')
262
self.assertEqual([('directory', 'root-id'),
263
('directory', 'a-id'),
264
('tree-reference', 'b-id')],
284
265
[(ie.kind, ie.file_id)
285
266
for path, ie in tree.iter_entries_by_dir()])
287
268
def test_indirect_subtree(self):
288
269
tree = self.make_simple_tree()
289
self.make_branch_and_tree('tree/a')
290
self.assertEqual([('directory', b'root-id'),
291
('tree-reference', b'a-id')],
270
subtree = self.make_branch_and_tree('tree/a')
271
self.assertEqual([('directory', 'root-id'),
272
('tree-reference', 'a-id')],
292
273
[(ie.kind, ie.file_id)
293
274
for path, ie in tree.iter_entries_by_dir()])
389
371
self.assertEqual([], tree.get_parent_ids())
374
class InstrumentedTree(object):
375
"""A instrumented tree to check the needs_tree_write_lock decorator."""
380
def lock_tree_write(self):
381
self._locks.append('t')
383
@needs_tree_write_lock
384
def method_with_tree_write_lock(self, *args, **kwargs):
385
"""A lock_tree_write decorated method that returns its arguments."""
388
@needs_tree_write_lock
389
def method_that_raises(self):
390
"""This method causes an exception when called with parameters.
392
This allows the decorator code to be checked - it should still call
397
self._locks.append('u')
400
class TestInstrumentedTree(TestCase):
402
def test_needs_tree_write_lock(self):
403
"""@needs_tree_write_lock should be semantically transparent."""
404
tree = InstrumentedTree()
406
'method_with_tree_write_lock',
407
tree.method_with_tree_write_lock.__name__)
408
self.assertDocstring(
409
"A lock_tree_write decorated method that returns its arguments.",
410
tree.method_with_tree_write_lock)
413
result = tree.method_with_tree_write_lock(1,2,3, a='b')
414
self.assertEqual((args, kwargs), result)
415
self.assertEqual(['t', 'u'], tree._locks)
416
self.assertRaises(TypeError, tree.method_that_raises, 'foo')
417
self.assertEqual(['t', 'u', 't', 'u'], tree._locks)
392
420
class TestRevert(TestCaseWithTransport):
394
422
def test_revert_conflicts_recursive(self):
395
423
this_tree = self.make_branch_and_tree('this-tree')
396
424
self.build_tree_contents([('this-tree/foo/',),
397
('this-tree/foo/bar', b'bar')])
425
('this-tree/foo/bar', 'bar')])
398
426
this_tree.add(['foo', 'foo/bar'])
399
427
this_tree.commit('created foo/bar')
400
other_tree = this_tree.controldir.sprout(
401
'other-tree').open_workingtree()
402
self.build_tree_contents([('other-tree/foo/bar', b'baz')])
428
other_tree = this_tree.bzrdir.sprout('other-tree').open_workingtree()
429
self.build_tree_contents([('other-tree/foo/bar', 'baz')])
403
430
other_tree.commit('changed bar')
404
self.build_tree_contents([('this-tree/foo/bar', b'qux')])
431
self.build_tree_contents([('this-tree/foo/bar', 'qux')])
405
432
this_tree.commit('changed qux')
406
433
this_tree.merge_from_branch(other_tree.branch)
407
434
self.assertEqual(1, len(this_tree.conflicts()))
412
439
class TestAutoResolve(TestCaseWithTransport):
414
def _auto_resolve(self, tree):
415
"""Call auto_resolve on tree expecting deprecation"""
416
return self.applyDeprecated(
417
symbol_versioning.deprecated_in((3, 0, 1)),
420
441
def test_auto_resolve(self):
421
442
base = self.make_branch_and_tree('base')
422
self.build_tree_contents([('base/hello', b'Hello')])
423
base.add('hello', b'hello_id')
443
self.build_tree_contents([('base/hello', 'Hello')])
444
base.add('hello', 'hello_id')
424
445
base.commit('Hello')
425
other = base.controldir.sprout('other').open_workingtree()
426
self.build_tree_contents([('other/hello', b'hELLO')])
446
other = base.bzrdir.sprout('other').open_workingtree()
447
self.build_tree_contents([('other/hello', 'hELLO')])
427
448
other.commit('Case switch')
428
this = base.controldir.sprout('this').open_workingtree()
449
this = base.bzrdir.sprout('this').open_workingtree()
429
450
self.assertPathExists('this/hello')
430
self.build_tree_contents([('this/hello', b'Hello World')])
451
self.build_tree_contents([('this/hello', 'Hello World')])
431
452
this.commit('Add World')
432
453
this.merge_from_branch(other.branch)
433
self.assertEqual([conflicts.TextConflict('hello', b'hello_id')],
454
self.assertEqual([conflicts.TextConflict('hello', 'hello_id')],
434
455
this.conflicts())
435
self._auto_resolve(this)
436
self.assertEqual([conflicts.TextConflict('hello', b'hello_id')],
457
self.assertEqual([conflicts.TextConflict('hello', 'hello_id')],
437
458
this.conflicts())
438
459
self.build_tree_contents([('this/hello', '<<<<<<<')])
439
self._auto_resolve(this)
440
self.assertEqual([conflicts.TextConflict('hello', b'hello_id')],
461
self.assertEqual([conflicts.TextConflict('hello', 'hello_id')],
441
462
this.conflicts())
442
463
self.build_tree_contents([('this/hello', '=======')])
443
self._auto_resolve(this)
444
self.assertEqual([conflicts.TextConflict('hello', b'hello_id')],
465
self.assertEqual([conflicts.TextConflict('hello', 'hello_id')],
445
466
this.conflicts())
446
467
self.build_tree_contents([('this/hello', '\n>>>>>>>')])
447
remaining, resolved = self._auto_resolve(this)
448
self.assertEqual([conflicts.TextConflict('hello', b'hello_id')],
468
remaining, resolved = this.auto_resolve()
469
self.assertEqual([conflicts.TextConflict('hello', 'hello_id')],
449
470
this.conflicts())
450
471
self.assertEqual([], resolved)
451
self.build_tree_contents([('this/hello', b'hELLO wORLD')])
452
remaining, resolved = self._auto_resolve(this)
472
self.build_tree_contents([('this/hello', 'hELLO wORLD')])
473
remaining, resolved = this.auto_resolve()
453
474
self.assertEqual([], this.conflicts())
454
self.assertEqual([conflicts.TextConflict('hello', b'hello_id')],
475
self.assertEqual([conflicts.TextConflict('hello', 'hello_id')],
456
477
self.assertPathDoesNotExist('this/hello.BASE')
458
def test_unsupported_symlink_auto_resolve(self):
459
self.requireFeature(SymlinkFeature)
460
base = self.make_branch_and_tree('base')
461
self.build_tree_contents([('base/hello', 'Hello')])
462
base.add('hello', b'hello_id')
463
base.commit('commit 0')
464
other = base.controldir.sprout('other').open_workingtree()
465
self.build_tree_contents([('other/hello', 'Hello')])
466
os.symlink('other/hello', 'other/foo')
467
other.add('foo', b'foo_id')
468
other.commit('commit symlink')
469
this = base.controldir.sprout('this').open_workingtree()
470
self.assertPathExists('this/hello')
471
self.build_tree_contents([('this/hello', 'Hello')])
472
this.commit('commit 2')
474
trace.push_log_file(log)
475
os_symlink = getattr(os, 'symlink', None)
478
this.merge_from_branch(other.branch)
481
os.symlink = os_symlink
482
self.assertContainsRe(
484
b'Unable to create symlink "foo" on this filesystem')
486
479
def test_auto_resolve_dir(self):
487
480
tree = self.make_branch_and_tree('tree')
488
481
self.build_tree(['tree/hello/'])
489
tree.add('hello', b'hello-id')
490
file_conflict = conflicts.TextConflict('hello', b'hello-id')
491
tree.set_conflicts(conflicts.ConflictList([file_conflict]))
492
remaining, resolved = self._auto_resolve(tree)
495
conflicts.ConflictList([conflicts.TextConflict(u'hello', 'hello-id')]))
496
self.assertEqual(resolved, [])
498
def test_auto_resolve_missing(self):
499
tree = self.make_branch_and_tree('tree')
500
file_conflict = conflicts.TextConflict('hello', b'hello-id')
501
tree.set_conflicts(conflicts.ConflictList([file_conflict]))
502
remaining, resolved = self._auto_resolve(tree)
503
self.assertEqual(remaining, [])
506
conflicts.ConflictList([conflicts.TextConflict(u'hello', 'hello-id')]))
482
tree.add('hello', 'hello-id')
483
file_conflict = conflicts.TextConflict('file', 'hello-id')
484
tree.set_conflicts(conflicts.ConflictList([file_conflict]))
488
class TestFindTrees(TestCaseWithTransport):
490
def test_find_trees(self):
491
self.make_branch_and_tree('foo')
492
self.make_branch_and_tree('foo/bar')
493
# Sticking a tree inside a control dir is heinous, so let's skip it
494
self.make_branch_and_tree('foo/.bzr/baz')
495
self.make_branch('qux')
496
trees = workingtree.WorkingTree.find_trees('.')
497
self.assertEqual(2, len(list(trees)))
509
500
class TestStoredUncommitted(TestCaseWithTransport):