72
66
class TestDefaultFormat(TestCaseWithTransport):
74
68
def test_get_set_default_format(self):
75
old_format = workingtree.format_registry.get_default()
77
self.assertTrue(isinstance(
78
old_format, workingtree_4.WorkingTreeFormat6))
79
workingtree.format_registry.set_default(SampleTreeFormat())
81
# the default branch format is used by the meta dir format
82
# which is not the default bzrdir format at this point
83
dir = bzrdir.BzrDirMetaFormat1().initialize('.')
84
dir.create_repository()
86
result = dir.create_workingtree()
87
self.assertEqual(result, 'A tree')
89
workingtree.format_registry.set_default(old_format)
90
self.assertEqual(old_format, workingtree.format_registry.get_default())
92
def test_from_string(self):
93
self.assertIsInstance(
94
SampleTreeFormat.from_string(b"Sample tree format."),
97
AssertionError, SampleTreeFormat.from_string,
98
b"Different format string.")
100
def test_get_set_default_format_by_key(self):
101
old_format = workingtree.format_registry.get_default()
103
format = SampleTreeFormat()
104
workingtree.format_registry.register(format)
105
self.addCleanup(workingtree.format_registry.remove, format)
106
self.assertTrue(isinstance(
107
old_format, workingtree_4.WorkingTreeFormat6))
108
workingtree.format_registry.set_default_key(format.get_format_string())
110
# the default branch format is used by the meta dir format
111
# which is not the default bzrdir format at this point
112
dir = bzrdir.BzrDirMetaFormat1().initialize('.')
113
dir.create_repository()
115
result = dir.create_workingtree()
116
self.assertEqual(result, 'A tree')
118
workingtree.format_registry.set_default_key(
119
old_format.get_format_string())
120
self.assertEqual(old_format, workingtree.format_registry.get_default())
123
tree = self.make_branch_and_tree('.')
124
open_direct = workingtree.WorkingTree.open('.')
125
self.assertEqual(tree.basedir, open_direct.basedir)
126
open_no_args = workingtree.WorkingTree.open()
127
self.assertEqual(tree.basedir, open_no_args.basedir)
129
def test_open_containing(self):
130
tree = self.make_branch_and_tree('.')
131
open_direct, relpath = workingtree.WorkingTree.open_containing('.')
132
self.assertEqual(tree.basedir, open_direct.basedir)
133
self.assertEqual('', relpath)
134
open_no_args, relpath = workingtree.WorkingTree.open_containing()
135
self.assertEqual(tree.basedir, open_no_args.basedir)
136
self.assertEqual('', relpath)
137
open_subdir, relpath = workingtree.WorkingTree.open_containing(
139
self.assertEqual(tree.basedir, open_subdir.basedir)
140
self.assertEqual('subdir', relpath)
143
class SampleTreeFormat(bzrworkingtree.WorkingTreeFormatMetaDir):
69
old_format = workingtree.WorkingTreeFormat.get_default_format()
71
self.assertTrue(isinstance(old_format, workingtree.WorkingTreeFormat3))
72
workingtree.WorkingTreeFormat.set_default_format(SampleTreeFormat())
74
# the default branch format is used by the meta dir format
75
# which is not the default bzrdir format at this point
76
dir = bzrdir.BzrDirMetaFormat1().initialize('.')
77
dir.create_repository()
79
result = dir.create_workingtree()
80
self.assertEqual(result, 'A tree')
82
workingtree.WorkingTreeFormat.set_default_format(old_format)
83
self.assertEqual(old_format, workingtree.WorkingTreeFormat.get_default_format())
86
class SampleTreeFormat(workingtree.WorkingTreeFormat):
144
87
"""A sample format
146
this format is initializable, unsupported to aid in testing the
89
this format is initializable, unsupported to aid in testing the
147
90
open and open_downlevel routines.
151
def get_format_string(cls):
93
def get_format_string(self):
152
94
"""See WorkingTreeFormat.get_format_string()."""
153
return b"Sample tree format."
95
return "Sample tree format."
155
def initialize(self, a_controldir, revision_id=None, from_branch=None,
156
accelerator_tree=None, hardlink=False):
97
def initialize(self, a_bzrdir, revision_id=None):
157
98
"""Sample branches cannot be created."""
158
t = a_controldir.get_workingtree_transport(self)
99
t = a_bzrdir.get_workingtree_transport(self)
159
100
t.put_bytes('format', self.get_format_string())
233
136
dir.create_branch()
234
137
SampleTreeFormat().initialize(dir)
235
138
self.assertRaises(errors.UnknownFormatError,
236
bzrworkingtree.WorkingTreeFormatMetaDir.find_format,
139
workingtree.WorkingTreeFormat.find_format,
239
def test_find_format_with_features(self):
240
tree = self.make_branch_and_tree('.', format='2a')
241
tree.update_feature_flags({b"name": b"necessity"})
242
found_format = bzrworkingtree.WorkingTreeFormatMetaDir.find_format(
244
self.assertIsInstance(found_format, workingtree.WorkingTreeFormat)
245
self.assertEqual(found_format.features.get(b"name"), b"necessity")
247
bzrdir.MissingFeature, found_format.check_support_status, True)
249
bzrworkingtree.WorkingTreeFormatMetaDir.unregister_feature,
251
bzrworkingtree.WorkingTreeFormatMetaDir.register_feature(b"name")
252
found_format.check_support_status(True)
255
class TestWorkingTreeIterEntriesByDir_wSubtrees(TestCaseWithTransport):
257
def make_simple_tree(self):
258
tree = self.make_branch_and_tree('tree', format='development-subtree')
259
self.build_tree(['tree/a/', 'tree/a/b/', 'tree/a/b/c'])
260
tree.set_root_id(b'root-id')
261
tree.add(['a', 'a/b', 'a/b/c'], [b'a-id', b'b-id', b'c-id'])
262
tree.commit('initial')
265
def test_just_directory(self):
266
tree = self.make_simple_tree()
267
self.assertEqual([('directory', b'root-id'),
268
('directory', b'a-id'),
269
('directory', b'b-id'),
271
[(ie.kind, ie.file_id)
272
for path, ie in tree.iter_entries_by_dir()])
273
self.make_branch_and_tree('tree/a/b')
274
self.assertEqual([('tree-reference', b'b-id')],
275
[(ie.kind, ie.file_id)
276
for path, ie in tree.iter_entries_by_dir(
277
specific_files=['a/b'])])
279
def test_direct_subtree(self):
280
tree = self.make_simple_tree()
281
self.make_branch_and_tree('tree/a/b')
282
self.assertEqual([('directory', b'root-id'),
283
('directory', b'a-id'),
284
('tree-reference', b'b-id')],
285
[(ie.kind, ie.file_id)
286
for path, ie in tree.iter_entries_by_dir()])
288
def test_indirect_subtree(self):
289
tree = self.make_simple_tree()
290
self.make_branch_and_tree('tree/a')
291
self.assertEqual([('directory', b'root-id'),
292
('tree-reference', b'a-id')],
293
[(ie.kind, ie.file_id)
294
for path, ie in tree.iter_entries_by_dir()])
297
class TestWorkingTreeFormatRegistry(TestCase):
300
super(TestWorkingTreeFormatRegistry, self).setUp()
301
self.registry = workingtree.WorkingTreeFormatRegistry()
303
142
def test_register_unregister_format(self):
304
143
format = SampleTreeFormat()
305
self.registry.register(format)
306
self.assertEqual(format, self.registry.get(b"Sample tree format."))
307
self.registry.remove(format)
308
self.assertRaises(KeyError, self.registry.get, b"Sample tree format.")
310
def test_get_all(self):
311
format = SampleTreeFormat()
312
self.assertEqual([], self.registry._get_all())
313
self.registry.register(format)
314
self.assertEqual([format], self.registry._get_all())
316
def test_register_extra(self):
317
format = SampleExtraTreeFormat()
318
self.assertEqual([], self.registry._get_all())
319
self.registry.register_extra(format)
320
self.assertEqual([format], self.registry._get_all())
322
def test_register_extra_lazy(self):
323
self.assertEqual([], self.registry._get_all())
324
self.registry.register_extra_lazy("breezy.tests.test_workingtree",
325
"SampleExtraTreeFormat")
326
formats = self.registry._get_all()
327
self.assertEqual(1, len(formats))
328
self.assertIsInstance(formats[0], SampleExtraTreeFormat)
145
dir = bzrdir.BzrDirMetaFormat1().initialize('.')
146
dir.create_repository()
149
format.initialize(dir)
150
# register a format for it.
151
workingtree.WorkingTreeFormat.register_format(format)
152
# which branch.Open will refuse (not supported)
153
self.assertRaises(errors.UnsupportedFormatError, workingtree.WorkingTree.open, '.')
154
# but open_downlevel will work
155
self.assertEqual(format.open(dir), workingtree.WorkingTree.open_downlevel('.'))
156
# unregister the format
157
workingtree.WorkingTreeFormat.unregister_format(format)
331
160
class TestWorkingTreeFormat3(TestCaseWithTransport):
343
172
# stat-cache = ??
344
173
# no inventory.basis yet
345
174
t = control.get_workingtree_transport(None)
346
self.assertEqualDiff(b'Bazaar-NG Working Tree format 3',
175
self.assertEqualDiff('Bazaar-NG Working Tree format 3',
347
176
t.get('format').read())
348
self.assertEqualDiff(t.get('inventory').read(),
349
b'<inventory format="5">\n'
177
self.assertEqualDiff(t.get('inventory').read(),
178
'<inventory format="5">\n'
352
self.assertEqualDiff(b'### bzr hashcache v5\n',
181
self.assertEqualDiff('### bzr hashcache v5\n',
353
182
t.get('stat-cache').read())
354
183
self.assertFalse(t.has('inventory.basis'))
355
184
# no last-revision file means 'None' or 'NULLREVISION'
356
185
self.assertFalse(t.has('last-revision'))
357
# TODO RBC 20060210 do a commit, check the inventory.basis is created
186
# TODO RBC 20060210 do a commit, check the inventory.basis is created
358
187
# correctly and last-revision file becomes present.
360
189
def test_uses_lockdir(self):
361
190
"""WorkingTreeFormat3 uses its own LockDir:
363
192
- lock is a directory
364
193
- when the WorkingTree is locked, LockDir can see that
366
195
t = self.get_transport()
367
196
url = self.get_url()
368
197
dir = bzrdir.BzrDirMetaFormat1().initialize(url)
369
dir.create_repository()
198
repo = dir.create_repository()
199
branch = dir.create_branch()
372
tree = workingtree_3.WorkingTreeFormat3().initialize(dir)
201
tree = workingtree.WorkingTreeFormat3().initialize(dir)
373
202
except errors.NotLocalUrl:
374
203
raise TestSkipped('Not a local URL')
375
204
self.assertIsDirectory('.bzr', t)
376
205
self.assertIsDirectory('.bzr/checkout', t)
377
206
self.assertIsDirectory('.bzr/checkout/lock', t)
378
207
our_lock = LockDir(t, '.bzr/checkout/lock')
379
self.assertEqual(our_lock.peek(), None)
380
with tree.lock_write():
381
self.assertTrue(our_lock.peek())
382
self.assertEqual(our_lock.peek(), None)
208
self.assertEquals(our_lock.peek(), None)
210
self.assertTrue(our_lock.peek())
212
self.assertEquals(our_lock.peek(), None)
384
214
def test_missing_pending_merges(self):
385
215
control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
386
216
control.create_repository()
387
217
control.create_branch()
388
tree = workingtree_3.WorkingTreeFormat3().initialize(control)
389
tree._transport.delete("pending-merges")
218
tree = workingtree.WorkingTreeFormat3().initialize(control)
219
tree._control_files._transport.delete("pending-merges")
390
220
self.assertEqual([], tree.get_parent_ids())
393
class TestRevert(TestCaseWithTransport):
395
def test_revert_conflicts_recursive(self):
396
this_tree = self.make_branch_and_tree('this-tree')
397
self.build_tree_contents([('this-tree/foo/',),
398
('this-tree/foo/bar', b'bar')])
399
this_tree.add(['foo', 'foo/bar'])
400
this_tree.commit('created foo/bar')
401
other_tree = this_tree.controldir.sprout(
402
'other-tree').open_workingtree()
403
self.build_tree_contents([('other-tree/foo/bar', b'baz')])
404
other_tree.commit('changed bar')
405
self.build_tree_contents([('this-tree/foo/bar', b'qux')])
406
this_tree.commit('changed qux')
407
this_tree.merge_from_branch(other_tree.branch)
408
self.assertEqual(1, len(this_tree.conflicts()))
409
this_tree.revert(['foo'])
410
self.assertEqual(0, len(this_tree.conflicts()))
223
class TestFormat2WorkingTree(TestCaseWithTransport):
224
"""Tests that are specific to format 2 trees."""
226
def create_format2_tree(self, url):
227
return self.make_branch_and_tree(
228
url, format=bzrdir.BzrDirFormat6())
230
def test_conflicts(self):
231
# test backwards compatability
232
tree = self.create_format2_tree('.')
233
self.assertRaises(errors.UnsupportedOperation, tree.set_conflicts,
235
file('lala.BASE', 'wb').write('labase')
236
expected = conflicts.ContentsConflict('lala')
237
self.assertEqual(list(tree.conflicts()), [expected])
238
file('lala', 'wb').write('la')
239
tree.add('lala', 'lala-id')
240
expected = conflicts.ContentsConflict('lala', file_id='lala-id')
241
self.assertEqual(list(tree.conflicts()), [expected])
242
file('lala.THIS', 'wb').write('lathis')
243
file('lala.OTHER', 'wb').write('laother')
244
# When "text conflict"s happen, stem, THIS and OTHER are text
245
expected = conflicts.TextConflict('lala', file_id='lala-id')
246
self.assertEqual(list(tree.conflicts()), [expected])
247
os.unlink('lala.OTHER')
248
os.mkdir('lala.OTHER')
249
expected = conflicts.ContentsConflict('lala', file_id='lala-id')
250
self.assertEqual(list(tree.conflicts()), [expected])
253
class TestNonFormatSpecificCode(TestCaseWithTransport):
254
"""This class contains tests of workingtree that are not format specific."""
256
def test_gen_file_id(self):
257
file_id = self.applyDeprecated(zero_thirteen, workingtree.gen_file_id,
259
self.assertStartsWith(file_id, 'filename-')
261
def test_gen_root_id(self):
262
file_id = self.applyDeprecated(zero_thirteen, workingtree.gen_root_id)
263
self.assertStartsWith(file_id, 'tree_root-')
266
class InstrumentedTree(object):
267
"""A instrumented tree to check the needs_tree_write_lock decorator."""
272
def lock_tree_write(self):
273
self._locks.append('t')
275
@needs_tree_write_lock
276
def method_with_tree_write_lock(self, *args, **kwargs):
277
"""A lock_tree_write decorated method that returns its arguments."""
280
@needs_tree_write_lock
281
def method_that_raises(self):
282
"""This method causes an exception when called with parameters.
284
This allows the decorator code to be checked - it should still call
289
self._locks.append('u')
292
class TestInstrumentedTree(TestCase):
294
def test_needs_tree_write_lock(self):
295
"""@needs_tree_write_lock should be semantically transparent."""
296
tree = InstrumentedTree()
298
'method_with_tree_write_lock',
299
tree.method_with_tree_write_lock.__name__)
301
"A lock_tree_write decorated method that returns its arguments.",
302
tree.method_with_tree_write_lock.__doc__)
305
result = tree.method_with_tree_write_lock(1,2,3, a='b')
306
self.assertEqual((args, kwargs), result)
307
self.assertEqual(['t', 'u'], tree._locks)
308
self.assertRaises(TypeError, tree.method_that_raises, 'foo')
309
self.assertEqual(['t', 'u', 't', 'u'], tree._locks)
413
312
class TestAutoResolve(TestCaseWithTransport):
415
def _auto_resolve(self, tree):
416
"""Call auto_resolve on tree expecting deprecation"""
417
return self.applyDeprecated(
418
symbol_versioning.deprecated_in((3, 0, 1)),
421
314
def test_auto_resolve(self):
422
315
base = self.make_branch_and_tree('base')
423
self.build_tree_contents([('base/hello', b'Hello')])
424
base.add('hello', b'hello_id')
316
self.build_tree_contents([('base/hello', 'Hello')])
317
base.add('hello', 'hello_id')
425
318
base.commit('Hello')
426
other = base.controldir.sprout('other').open_workingtree()
427
self.build_tree_contents([('other/hello', b'hELLO')])
319
other = base.bzrdir.sprout('other').open_workingtree()
320
self.build_tree_contents([('other/hello', 'hELLO')])
428
321
other.commit('Case switch')
429
this = base.controldir.sprout('this').open_workingtree()
430
self.assertPathExists('this/hello')
431
self.build_tree_contents([('this/hello', b'Hello World')])
322
this = base.bzrdir.sprout('this').open_workingtree()
323
self.failUnlessExists('this/hello')
324
self.build_tree_contents([('this/hello', 'Hello World')])
432
325
this.commit('Add World')
433
326
this.merge_from_branch(other.branch)
434
self.assertEqual([_mod_bzr_conflicts.TextConflict('hello', b'hello_id')],
327
self.assertEqual([conflicts.TextConflict('hello', None, 'hello_id')],
435
328
this.conflicts())
436
self._auto_resolve(this)
437
self.assertEqual([_mod_bzr_conflicts.TextConflict('hello', b'hello_id')],
330
self.assertEqual([conflicts.TextConflict('hello', None, 'hello_id')],
438
331
this.conflicts())
439
332
self.build_tree_contents([('this/hello', '<<<<<<<')])
440
self._auto_resolve(this)
441
self.assertEqual([_mod_bzr_conflicts.TextConflict('hello', b'hello_id')],
334
self.assertEqual([conflicts.TextConflict('hello', None, 'hello_id')],
442
335
this.conflicts())
443
336
self.build_tree_contents([('this/hello', '=======')])
444
self._auto_resolve(this)
445
self.assertEqual([_mod_bzr_conflicts.TextConflict('hello', b'hello_id')],
338
self.assertEqual([conflicts.TextConflict('hello', None, 'hello_id')],
446
339
this.conflicts())
447
340
self.build_tree_contents([('this/hello', '\n>>>>>>>')])
448
remaining, resolved = self._auto_resolve(this)
449
self.assertEqual([_mod_bzr_conflicts.TextConflict('hello', b'hello_id')],
341
remaining, resolved = this.auto_resolve()
342
self.assertEqual([conflicts.TextConflict('hello', None, 'hello_id')],
450
343
this.conflicts())
451
344
self.assertEqual([], resolved)
452
self.build_tree_contents([('this/hello', b'hELLO wORLD')])
453
remaining, resolved = self._auto_resolve(this)
345
self.build_tree_contents([('this/hello', 'hELLO wORLD')])
346
remaining, resolved = this.auto_resolve()
454
347
self.assertEqual([], this.conflicts())
455
self.assertEqual([_mod_bzr_conflicts.TextConflict('hello', b'hello_id')],
348
self.assertEqual([conflicts.TextConflict('hello', None, 'hello_id')],
457
self.assertPathDoesNotExist('this/hello.BASE')
459
def test_unsupported_symlink_auto_resolve(self):
460
self.requireFeature(SymlinkFeature)
461
base = self.make_branch_and_tree('base')
462
self.build_tree_contents([('base/hello', 'Hello')])
463
base.add('hello', b'hello_id')
464
base.commit('commit 0')
465
other = base.controldir.sprout('other').open_workingtree()
466
self.build_tree_contents([('other/hello', 'Hello')])
467
os.symlink('other/hello', 'other/foo')
468
other.add('foo', b'foo_id')
469
other.commit('commit symlink')
470
this = base.controldir.sprout('this').open_workingtree()
471
self.assertPathExists('this/hello')
472
self.build_tree_contents([('this/hello', 'Hello')])
473
this.commit('commit 2')
475
trace.push_log_file(log)
476
os_symlink = getattr(os, 'symlink', None)
479
this.merge_from_branch(other.branch)
482
os.symlink = os_symlink
483
self.assertContainsRe(
485
b'Unable to create symlink "foo" on this filesystem')
350
self.failIfExists('this/hello.BASE')
487
352
def test_auto_resolve_dir(self):
488
353
tree = self.make_branch_and_tree('tree')
489
354
self.build_tree(['tree/hello/'])
490
tree.add('hello', b'hello-id')
491
file_conflict = _mod_bzr_conflicts.TextConflict('hello', b'hello-id')
492
tree.set_conflicts([file_conflict])
493
remaining, resolved = self._auto_resolve(tree)
496
conflicts.ConflictList([_mod_bzr_conflicts.TextConflict(u'hello', 'hello-id')]))
497
self.assertEqual(resolved, [])
499
def test_auto_resolve_missing(self):
500
tree = self.make_branch_and_tree('tree')
501
file_conflict = _mod_bzr_conflicts.TextConflict('hello', b'hello-id')
502
tree.set_conflicts([file_conflict])
503
remaining, resolved = self._auto_resolve(tree)
504
self.assertEqual(remaining, [])
507
conflicts.ConflictList([_mod_bzr_conflicts.TextConflict(u'hello', 'hello-id')]))
510
class TestStoredUncommitted(TestCaseWithTransport):
512
def store_uncommitted(self):
513
tree = self.make_branch_and_tree('tree')
514
tree.commit('get root in there')
515
self.build_tree_contents([('tree/file', b'content')])
516
tree.add('file', b'file-id')
517
tree.store_uncommitted()
520
def test_store_uncommitted(self):
521
self.store_uncommitted()
522
self.assertPathDoesNotExist('tree/file')
524
def test_store_uncommitted_no_change(self):
525
tree = self.make_branch_and_tree('tree')
526
tree.commit('get root in there')
527
tree.store_uncommitted()
528
self.assertIs(None, tree.branch.get_unshelver(tree))
530
def test_restore_uncommitted(self):
531
with write_locked(self.store_uncommitted()) as tree:
532
tree.restore_uncommitted()
533
self.assertPathExists('tree/file')
534
self.assertIs(None, tree.branch.get_unshelver(tree))
536
def test_restore_uncommitted_none(self):
537
tree = self.make_branch_and_tree('tree')
538
tree.restore_uncommitted()
355
tree.add('hello', 'hello-id')
356
file_conflict = conflicts.TextConflict('file', None, 'hello-id')
357
tree.set_conflicts(conflicts.ConflictList([file_conflict]))