71
58
class TestDefaultFormat(TestCaseWithTransport):
73
60
def test_get_set_default_format(self):
74
old_format = workingtree.format_registry.get_default()
76
self.assertTrue(isinstance(
77
old_format, workingtree_4.WorkingTreeFormat6))
78
workingtree.format_registry.set_default(SampleTreeFormat())
80
# the default branch format is used by the meta dir format
81
# which is not the default bzrdir format at this point
82
dir = bzrdir.BzrDirMetaFormat1().initialize('.')
83
dir.create_repository()
85
result = dir.create_workingtree()
86
self.assertEqual(result, 'A tree')
88
workingtree.format_registry.set_default(old_format)
89
self.assertEqual(old_format, workingtree.format_registry.get_default())
91
def test_from_string(self):
92
self.assertIsInstance(
93
SampleTreeFormat.from_string(b"Sample tree format."),
96
AssertionError, SampleTreeFormat.from_string,
97
b"Different format string.")
99
def test_get_set_default_format_by_key(self):
100
old_format = workingtree.format_registry.get_default()
102
format = SampleTreeFormat()
103
workingtree.format_registry.register(format)
104
self.addCleanup(workingtree.format_registry.remove, format)
105
self.assertTrue(isinstance(
106
old_format, workingtree_4.WorkingTreeFormat6))
107
workingtree.format_registry.set_default_key(format.get_format_string())
109
# the default branch format is used by the meta dir format
110
# which is not the default bzrdir format at this point
111
dir = bzrdir.BzrDirMetaFormat1().initialize('.')
112
dir.create_repository()
114
result = dir.create_workingtree()
115
self.assertEqual(result, 'A tree')
117
workingtree.format_registry.set_default_key(
118
old_format.get_format_string())
119
self.assertEqual(old_format, workingtree.format_registry.get_default())
122
tree = self.make_branch_and_tree('.')
123
open_direct = workingtree.WorkingTree.open('.')
124
self.assertEqual(tree.basedir, open_direct.basedir)
125
open_no_args = workingtree.WorkingTree.open()
126
self.assertEqual(tree.basedir, open_no_args.basedir)
128
def test_open_containing(self):
129
tree = self.make_branch_and_tree('.')
130
open_direct, relpath = workingtree.WorkingTree.open_containing('.')
131
self.assertEqual(tree.basedir, open_direct.basedir)
132
self.assertEqual('', relpath)
133
open_no_args, relpath = workingtree.WorkingTree.open_containing()
134
self.assertEqual(tree.basedir, open_no_args.basedir)
135
self.assertEqual('', relpath)
136
open_subdir, relpath = workingtree.WorkingTree.open_containing(
138
self.assertEqual(tree.basedir, open_subdir.basedir)
139
self.assertEqual('subdir', relpath)
142
class SampleTreeFormat(bzrworkingtree.WorkingTreeFormatMetaDir):
61
old_format = workingtree.WorkingTreeFormat.get_default_format()
63
self.assertTrue(isinstance(old_format, workingtree.WorkingTreeFormat3))
64
workingtree.WorkingTreeFormat.set_default_format(SampleTreeFormat())
66
# the default branch format is used by the meta dir format
67
# which is not the default bzrdir format at this point
68
dir = bzrdir.BzrDirMetaFormat1().initialize('.')
69
dir.create_repository()
71
result = dir.create_workingtree()
72
self.assertEqual(result, 'A tree')
74
workingtree.WorkingTreeFormat.set_default_format(old_format)
75
self.assertEqual(old_format, workingtree.WorkingTreeFormat.get_default_format())
78
class SampleTreeFormat(workingtree.WorkingTreeFormat):
143
79
"""A sample format
145
this format is initializable, unsupported to aid in testing the
81
this format is initializable, unsupported to aid in testing the
146
82
open and open_downlevel routines.
150
def get_format_string(cls):
85
def get_format_string(self):
151
86
"""See WorkingTreeFormat.get_format_string()."""
152
return b"Sample tree format."
87
return "Sample tree format."
154
def initialize(self, a_controldir, revision_id=None, from_branch=None,
155
accelerator_tree=None, hardlink=False):
89
def initialize(self, a_bzrdir, revision_id=None):
156
90
"""Sample branches cannot be created."""
157
t = a_controldir.get_workingtree_transport(self)
158
t.put_bytes('format', self.get_format_string())
91
t = a_bzrdir.get_workingtree_transport(self)
92
t.put('format', StringIO(self.get_format_string()))
161
95
def is_supported(self):
232
128
dir.create_branch()
233
129
SampleTreeFormat().initialize(dir)
234
130
self.assertRaises(errors.UnknownFormatError,
235
bzrworkingtree.WorkingTreeFormatMetaDir.find_format,
131
workingtree.WorkingTreeFormat.find_format,
238
def test_find_format_with_features(self):
239
tree = self.make_branch_and_tree('.', format='2a')
240
tree.update_feature_flags({b"name": b"necessity"})
241
found_format = bzrworkingtree.WorkingTreeFormatMetaDir.find_format(
243
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")
251
found_format.check_support_status(True)
254
class TestWorkingTreeIterEntriesByDir_wSubtrees(TestCaseWithTransport):
256
def make_simple_tree(self):
257
tree = self.make_branch_and_tree('tree', format='development-subtree')
258
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'])
261
tree.commit('initial')
264
def test_just_directory(self):
265
tree = self.make_simple_tree()
266
self.assertEqual([('directory', b'root-id'),
267
('directory', b'a-id'),
268
('directory', b'b-id'),
270
[(ie.kind, ie.file_id)
271
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')],
274
[(ie.kind, ie.file_id)
275
for path, ie in tree.iter_entries_by_dir(
276
specific_files=['a/b'])])
278
def test_direct_subtree(self):
279
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')],
284
[(ie.kind, ie.file_id)
285
for path, ie in tree.iter_entries_by_dir()])
287
def test_indirect_subtree(self):
288
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')],
292
[(ie.kind, ie.file_id)
293
for path, ie in tree.iter_entries_by_dir()])
296
class TestWorkingTreeFormatRegistry(TestCase):
299
super(TestWorkingTreeFormatRegistry, self).setUp()
300
self.registry = workingtree.WorkingTreeFormatRegistry()
302
134
def test_register_unregister_format(self):
303
135
format = SampleTreeFormat()
304
self.registry.register(format)
305
self.assertEqual(format, self.registry.get(b"Sample tree format."))
306
self.registry.remove(format)
307
self.assertRaises(KeyError, self.registry.get, b"Sample tree format.")
309
def test_get_all(self):
310
format = SampleTreeFormat()
311
self.assertEqual([], self.registry._get_all())
312
self.registry.register(format)
313
self.assertEqual([format], self.registry._get_all())
315
def test_register_extra(self):
316
format = SampleExtraTreeFormat()
317
self.assertEqual([], self.registry._get_all())
318
self.registry.register_extra(format)
319
self.assertEqual([format], self.registry._get_all())
321
def test_register_extra_lazy(self):
322
self.assertEqual([], self.registry._get_all())
323
self.registry.register_extra_lazy("breezy.tests.test_workingtree",
324
"SampleExtraTreeFormat")
325
formats = self.registry._get_all()
326
self.assertEqual(1, len(formats))
327
self.assertIsInstance(formats[0], SampleExtraTreeFormat)
137
dir = bzrdir.BzrDirMetaFormat1().initialize('.')
138
dir.create_repository()
141
format.initialize(dir)
142
# register a format for it.
143
workingtree.WorkingTreeFormat.register_format(format)
144
# which branch.Open will refuse (not supported)
145
self.assertRaises(errors.UnsupportedFormatError, workingtree.WorkingTree.open, '.')
146
# but open_downlevel will work
147
self.assertEqual(format.open(dir), workingtree.WorkingTree.open_downlevel('.'))
148
# unregister the format
149
workingtree.WorkingTreeFormat.unregister_format(format)
330
152
class TestWorkingTreeFormat3(TestCaseWithTransport):
342
164
# stat-cache = ??
343
165
# no inventory.basis yet
344
166
t = control.get_workingtree_transport(None)
345
self.assertEqualDiff(b'Bazaar-NG Working Tree format 3',
167
self.assertEqualDiff('Bazaar-NG Working Tree format 3',
346
168
t.get('format').read())
347
self.assertEqualDiff(t.get('inventory').read(),
348
b'<inventory format="5">\n'
351
self.assertEqualDiff(b'### bzr hashcache v5\n',
169
self.assertEqualDiff('<inventory format="5">\n'
171
t.get('inventory').read())
172
self.assertEqualDiff('### bzr hashcache v5\n',
352
173
t.get('stat-cache').read())
353
174
self.assertFalse(t.has('inventory.basis'))
354
175
# no last-revision file means 'None' or 'NULLREVISION'
355
176
self.assertFalse(t.has('last-revision'))
356
# TODO RBC 20060210 do a commit, check the inventory.basis is created
177
# TODO RBC 20060210 do a commit, check the inventory.basis is created
357
178
# correctly and last-revision file becomes present.
359
180
def test_uses_lockdir(self):
360
181
"""WorkingTreeFormat3 uses its own LockDir:
362
183
- lock is a directory
363
184
- when the WorkingTree is locked, LockDir can see that
365
186
t = self.get_transport()
366
187
url = self.get_url()
367
188
dir = bzrdir.BzrDirMetaFormat1().initialize(url)
368
dir.create_repository()
189
repo = dir.create_repository()
190
branch = dir.create_branch()
371
tree = workingtree_3.WorkingTreeFormat3().initialize(dir)
192
tree = workingtree.WorkingTreeFormat3().initialize(dir)
372
193
except errors.NotLocalUrl:
373
194
raise TestSkipped('Not a local URL')
374
195
self.assertIsDirectory('.bzr', t)
375
196
self.assertIsDirectory('.bzr/checkout', t)
376
197
self.assertIsDirectory('.bzr/checkout/lock', t)
377
198
our_lock = LockDir(t, '.bzr/checkout/lock')
378
self.assertEqual(our_lock.peek(), None)
379
with tree.lock_write():
380
self.assertTrue(our_lock.peek())
381
self.assertEqual(our_lock.peek(), None)
199
self.assertEquals(our_lock.peek(), None)
201
self.assertTrue(our_lock.peek())
203
self.assertEquals(our_lock.peek(), None)
383
205
def test_missing_pending_merges(self):
384
206
control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
385
207
control.create_repository()
386
208
control.create_branch()
387
tree = workingtree_3.WorkingTreeFormat3().initialize(control)
388
tree._transport.delete("pending-merges")
389
self.assertEqual([], tree.get_parent_ids())
392
class TestRevert(TestCaseWithTransport):
394
def test_revert_conflicts_recursive(self):
395
this_tree = self.make_branch_and_tree('this-tree')
396
self.build_tree_contents([('this-tree/foo/',),
397
('this-tree/foo/bar', b'bar')])
398
this_tree.add(['foo', 'foo/bar'])
399
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')])
403
other_tree.commit('changed bar')
404
self.build_tree_contents([('this-tree/foo/bar', b'qux')])
405
this_tree.commit('changed qux')
406
this_tree.merge_from_branch(other_tree.branch)
407
self.assertEqual(1, len(this_tree.conflicts()))
408
this_tree.revert(['foo'])
409
self.assertEqual(0, len(this_tree.conflicts()))
412
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
def test_auto_resolve(self):
421
base = self.make_branch_and_tree('base')
422
self.build_tree_contents([('base/hello', b'Hello')])
423
base.add('hello', b'hello_id')
425
other = base.controldir.sprout('other').open_workingtree()
426
self.build_tree_contents([('other/hello', b'hELLO')])
427
other.commit('Case switch')
428
this = base.controldir.sprout('this').open_workingtree()
429
self.assertPathExists('this/hello')
430
self.build_tree_contents([('this/hello', b'Hello World')])
431
this.commit('Add World')
432
this.merge_from_branch(other.branch)
433
self.assertEqual([conflicts.TextConflict('hello', b'hello_id')],
435
self._auto_resolve(this)
436
self.assertEqual([conflicts.TextConflict('hello', b'hello_id')],
438
self.build_tree_contents([('this/hello', '<<<<<<<')])
439
self._auto_resolve(this)
440
self.assertEqual([conflicts.TextConflict('hello', b'hello_id')],
442
self.build_tree_contents([('this/hello', '=======')])
443
self._auto_resolve(this)
444
self.assertEqual([conflicts.TextConflict('hello', b'hello_id')],
446
self.build_tree_contents([('this/hello', '\n>>>>>>>')])
447
remaining, resolved = self._auto_resolve(this)
448
self.assertEqual([conflicts.TextConflict('hello', b'hello_id')],
450
self.assertEqual([], resolved)
451
self.build_tree_contents([('this/hello', b'hELLO wORLD')])
452
remaining, resolved = self._auto_resolve(this)
453
self.assertEqual([], this.conflicts())
454
self.assertEqual([conflicts.TextConflict('hello', b'hello_id')],
456
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
def test_auto_resolve_dir(self):
487
tree = self.make_branch_and_tree('tree')
488
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')]))
509
class TestStoredUncommitted(TestCaseWithTransport):
511
def store_uncommitted(self):
512
tree = self.make_branch_and_tree('tree')
513
tree.commit('get root in there')
514
self.build_tree_contents([('tree/file', b'content')])
515
tree.add('file', b'file-id')
516
tree.store_uncommitted()
519
def test_store_uncommitted(self):
520
self.store_uncommitted()
521
self.assertPathDoesNotExist('tree/file')
523
def test_store_uncommitted_no_change(self):
524
tree = self.make_branch_and_tree('tree')
525
tree.commit('get root in there')
526
tree.store_uncommitted()
527
self.assertIs(None, tree.branch.get_unshelver(tree))
529
def test_restore_uncommitted(self):
530
with write_locked(self.store_uncommitted()) as tree:
531
tree.restore_uncommitted()
532
self.assertPathExists('tree/file')
533
self.assertIs(None, tree.branch.get_unshelver(tree))
535
def test_restore_uncommitted_none(self):
536
tree = self.make_branch_and_tree('tree')
537
tree.restore_uncommitted()
209
tree = workingtree.WorkingTreeFormat3().initialize(control)
210
tree._control_files._transport.delete("pending-merges")
211
self.assertEqual([], tree.pending_merges())
214
class TestFormat2WorkingTree(TestCaseWithTransport):
215
"""Tests that are specific to format 2 trees."""
217
def create_format2_tree(self, url):
218
return self.make_branch_and_tree(
219
url, format=bzrlib.bzrdir.BzrDirFormat6())
221
def test_conflicts(self):
222
# test backwards compatability
223
tree = self.create_format2_tree('.')
224
self.assertRaises(errors.UnsupportedOperation, tree.set_conflicts,
226
file('lala.BASE', 'wb').write('labase')
227
expected = conflicts.ContentsConflict('lala')
228
self.assertEqual(list(tree.conflicts()), [expected])
229
file('lala', 'wb').write('la')
230
tree.add('lala', 'lala-id')
231
expected = conflicts.ContentsConflict('lala', file_id='lala-id')
232
self.assertEqual(list(tree.conflicts()), [expected])
233
file('lala.THIS', 'wb').write('lathis')
234
file('lala.OTHER', 'wb').write('laother')
235
# When "text conflict"s happen, stem, THIS and OTHER are text
236
expected = conflicts.TextConflict('lala', file_id='lala-id')
237
self.assertEqual(list(tree.conflicts()), [expected])
238
os.unlink('lala.OTHER')
239
os.mkdir('lala.OTHER')
240
expected = conflicts.ContentsConflict('lala', file_id='lala-id')
241
self.assertEqual(list(tree.conflicts()), [expected])
244
class TestNonFormatSpecificCode(TestCaseWithTransport):
245
"""This class contains tests of workingtree that are not format specific."""
248
def test_gen_file_id(self):
249
self.assertStartsWith(bzrlib.workingtree.gen_file_id('bar'), 'bar-')
250
self.assertStartsWith(bzrlib.workingtree.gen_file_id('Mwoo oof\t m'), 'Mwoooofm-')
251
self.assertStartsWith(bzrlib.workingtree.gen_file_id('..gam.py'), 'gam.py-')
252
self.assertStartsWith(bzrlib.workingtree.gen_file_id('..Mwoo oof\t m'), 'Mwoooofm-')
254
def test_next_id_suffix(self):
255
bzrlib.workingtree._gen_id_suffix = None
256
bzrlib.workingtree._next_id_suffix()
257
self.assertNotEqual(None, bzrlib.workingtree._gen_id_suffix)
258
bzrlib.workingtree._gen_id_suffix = "foo-"
259
bzrlib.workingtree._gen_id_serial = 1
260
self.assertEqual("foo-2", bzrlib.workingtree._next_id_suffix())
261
self.assertEqual("foo-3", bzrlib.workingtree._next_id_suffix())
262
self.assertEqual("foo-4", bzrlib.workingtree._next_id_suffix())
263
self.assertEqual("foo-5", bzrlib.workingtree._next_id_suffix())
264
self.assertEqual("foo-6", bzrlib.workingtree._next_id_suffix())
265
self.assertEqual("foo-7", bzrlib.workingtree._next_id_suffix())
266
self.assertEqual("foo-8", bzrlib.workingtree._next_id_suffix())
267
self.assertEqual("foo-9", bzrlib.workingtree._next_id_suffix())
268
self.assertEqual("foo-10", bzrlib.workingtree._next_id_suffix())
270
def test__translate_ignore_rule(self):
271
tree = self.make_branch_and_tree('.')
272
# translation should return the regex, the number of groups in it,
273
# and the original rule in a tuple.
274
# there are three sorts of ignore rules:
275
# root only - regex is the rule itself without the leading ./
278
tree._translate_ignore_rule("./rootdirrule"))
279
# full path - regex is the rule itself
281
"(path\\/to\\/file$)",
282
tree._translate_ignore_rule("path/to/file"))
283
# basename only rule - regex is a rule that ignores everything up
284
# to the last / in the filename
286
"((?:.*/)?(?!.*/)basenamerule$)",
287
tree._translate_ignore_rule("basenamerule"))
289
def test__combine_ignore_rules(self):
290
tree = self.make_branch_and_tree('.')
291
# the combined ignore regexs need the outer group indices
292
# placed in a dictionary with the rules that were combined.
293
# an empty set of rules
294
# this is returned as a list of combined regex,rule sets, because
295
# python has a limit of 100 combined regexes.
296
compiled_rules = tree._combine_ignore_rules([])
297
self.assertEqual([], compiled_rules)
298
# one of each type of rule.
299
compiled_rules = tree._combine_ignore_rules(
300
["rule1", "rule/two", "./three"])[0]
301
# what type *is* the compiled regex to do an isinstance of ?
302
self.assertEqual(3, compiled_rules[0].groups)
304
{0:"rule1",1:"rule/two",2:"./three"},
307
def test__combine_ignore_rules_grouping(self):
308
tree = self.make_branch_and_tree('.')
309
# when there are too many rules, the output is split into groups of 100
311
for index in range(198):
313
self.assertEqual(2, len(tree._combine_ignore_rules(rules)))
315
def test__get_ignore_rules_as_regex(self):
316
tree = self.make_branch_and_tree('.')
317
# test against the default rules.
318
reference_output = tree._combine_ignore_rules(bzrlib.DEFAULT_IGNORE)[0]
319
regex_rules = tree._get_ignore_rules_as_regex()[0]
320
self.assertEqual(len(reference_output[1]), regex_rules[0].groups)
321
self.assertEqual(reference_output[1], regex_rules[1])