14
14
# You should have received a copy of the GNU General Public License
15
15
# along with this program; if not, write to the Free Software
16
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
from cStringIO import StringIO
22
from bzrlib.branch import Branch
23
import bzrlib.bzrdir as bzrdir
24
from bzrlib.bzrdir import BzrDir
25
from bzrlib.conflicts import *
26
import bzrlib.errors as errors
27
from bzrlib.errors import NotBranchError, NotVersionedError
16
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
28
28
from bzrlib.lockdir import LockDir
29
from bzrlib.osutils import pathjoin, getcwd, has_symlinks
30
from bzrlib.tests import TestCaseWithTransport, TestSkipped
31
from bzrlib.trace import mutter
32
from bzrlib.transport import get_transport
33
import bzrlib.workingtree as workingtree
34
from bzrlib.workingtree import (TreeEntry, TreeDirectory, TreeFile, TreeLink,
29
from bzrlib.mutabletree import needs_tree_write_lock
30
from bzrlib.tests import TestCase, TestCaseWithTransport, TestSkipped
31
from bzrlib.workingtree import (
37
39
class TestTreeDirectory(TestCaseWithTransport):
61
63
class TestDefaultFormat(TestCaseWithTransport):
63
65
def test_get_set_default_format(self):
64
old_format = workingtree.WorkingTreeFormat.get_default_format()
66
self.assertTrue(isinstance(old_format, workingtree.WorkingTreeFormat3))
67
workingtree.WorkingTreeFormat.set_default_format(SampleTreeFormat())
69
# the default branch format is used by the meta dir format
70
# which is not the default bzrdir format at this point
71
dir = bzrdir.BzrDirMetaFormat1().initialize('.')
72
dir.create_repository()
74
result = dir.create_workingtree()
75
self.assertEqual(result, 'A tree')
77
workingtree.WorkingTreeFormat.set_default_format(old_format)
78
self.assertEqual(old_format, workingtree.WorkingTreeFormat.get_default_format())
66
old_format = workingtree.format_registry.get_default()
68
self.assertTrue(isinstance(old_format, workingtree_4.WorkingTreeFormat6))
69
workingtree.format_registry.set_default(SampleTreeFormat())
71
# the default branch format is used by the meta dir format
72
# which is not the default bzrdir format at this point
73
dir = bzrdir.BzrDirMetaFormat1().initialize('.')
74
dir.create_repository()
76
result = dir.create_workingtree()
77
self.assertEqual(result, 'A tree')
79
workingtree.format_registry.set_default(old_format)
80
self.assertEqual(old_format, workingtree.format_registry.get_default())
82
def test_get_set_default_format_by_key(self):
83
old_format = workingtree.format_registry.get_default()
85
format = SampleTreeFormat()
86
workingtree.format_registry.register(format)
87
self.addCleanup(workingtree.format_registry.remove, format)
88
self.assertTrue(isinstance(old_format, workingtree_4.WorkingTreeFormat6))
89
workingtree.format_registry.set_default_key(format.get_format_string())
91
# the default branch format is used by the meta dir format
92
# which is not the default bzrdir format at this point
93
dir = bzrdir.BzrDirMetaFormat1().initialize('.')
94
dir.create_repository()
96
result = dir.create_workingtree()
97
self.assertEqual(result, 'A tree')
99
workingtree.format_registry.set_default_key(
100
old_format.get_format_string())
101
self.assertEqual(old_format, workingtree.format_registry.get_default())
104
tree = self.make_branch_and_tree('.')
105
open_direct = workingtree.WorkingTree.open('.')
106
self.assertEqual(tree.basedir, open_direct.basedir)
107
open_no_args = workingtree.WorkingTree.open()
108
self.assertEqual(tree.basedir, open_no_args.basedir)
110
def test_open_containing(self):
111
tree = self.make_branch_and_tree('.')
112
open_direct, relpath = workingtree.WorkingTree.open_containing('.')
113
self.assertEqual(tree.basedir, open_direct.basedir)
114
self.assertEqual('', relpath)
115
open_no_args, relpath = workingtree.WorkingTree.open_containing()
116
self.assertEqual(tree.basedir, open_no_args.basedir)
117
self.assertEqual('', relpath)
118
open_subdir, relpath = workingtree.WorkingTree.open_containing('subdir')
119
self.assertEqual(tree.basedir, open_subdir.basedir)
120
self.assertEqual('subdir', relpath)
81
123
class SampleTreeFormat(workingtree.WorkingTreeFormat):
82
124
"""A sample format
84
this format is initializable, unsupported to aid in testing the
126
this format is initializable, unsupported to aid in testing the
85
127
open and open_downlevel routines.
102
145
return "opened tree."
148
class SampleExtraTreeFormat(workingtree.WorkingTreeFormat):
149
"""A sample format that does not support use in a metadir.
153
def get_format_string(self):
154
# Not usable in a metadir, so no format string
157
def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
158
accelerator_tree=None, hardlink=False):
159
raise NotImplementedError(self.initialize)
161
def is_supported(self):
164
def open(self, transport, _found=False):
165
raise NotImplementedError(self.open)
105
168
class TestWorkingTreeFormat(TestCaseWithTransport):
106
169
"""Tests for the WorkingTreeFormat facility."""
171
def test_find_format_string(self):
172
# is the right format object found for a working tree?
173
branch = self.make_branch('branch')
174
self.assertRaises(errors.NoWorkingTree,
175
workingtree.WorkingTreeFormat.find_format_string, branch.bzrdir)
176
transport = branch.bzrdir.get_workingtree_transport(None)
178
transport.put_bytes("format", "some format name")
179
# The format does not have to be known by Bazaar,
180
# find_format_string just retrieves the name
181
self.assertEquals("some format name",
182
workingtree.WorkingTreeFormat.find_format_string(branch.bzrdir))
108
184
def test_find_format(self):
109
185
# is the right format object found for a working tree?
110
186
# create a branch with a few known format objects.
144
220
format.initialize(dir)
145
221
# register a format for it.
146
workingtree.WorkingTreeFormat.register_format(format)
222
self.applyDeprecated(symbol_versioning.deprecated_in((2, 4, 0)),
223
workingtree.WorkingTreeFormat.register_format, format)
224
self.assertTrue(format in
225
self.applyDeprecated(symbol_versioning.deprecated_in((2, 4, 0)),
226
workingtree.WorkingTreeFormat.get_formats))
147
227
# which branch.Open will refuse (not supported)
148
228
self.assertRaises(errors.UnsupportedFormatError, workingtree.WorkingTree.open, '.')
149
229
# but open_downlevel will work
150
230
self.assertEqual(format.open(dir), workingtree.WorkingTree.open_downlevel('.'))
151
231
# unregister the format
152
workingtree.WorkingTreeFormat.unregister_format(format)
232
self.applyDeprecated(symbol_versioning.deprecated_in((2, 4, 0)),
233
workingtree.WorkingTreeFormat.unregister_format, format)
234
self.assertFalse(format in
235
self.applyDeprecated(symbol_versioning.deprecated_in((2, 4, 0)),
236
workingtree.WorkingTreeFormat.get_formats))
239
class TestWorkingTreeIterEntriesByDir_wSubtrees(TestCaseWithTransport):
241
def make_simple_tree(self):
242
tree = self.make_branch_and_tree('tree', format='development-subtree')
243
self.build_tree(['tree/a/', 'tree/a/b/', 'tree/a/b/c'])
244
tree.set_root_id('root-id')
245
tree.add(['a', 'a/b', 'a/b/c'], ['a-id', 'b-id', 'c-id'])
246
tree.commit('initial')
249
def test_just_directory(self):
250
tree = self.make_simple_tree()
251
self.assertEqual([('directory', 'root-id'),
252
('directory', 'a-id'),
253
('directory', 'b-id'),
255
[(ie.kind, ie.file_id)
256
for path, ie in tree.iter_entries_by_dir()])
257
subtree = self.make_branch_and_tree('tree/a/b')
258
self.assertEqual([('tree-reference', 'b-id')],
259
[(ie.kind, ie.file_id)
260
for path, ie in tree.iter_entries_by_dir(['b-id'])])
262
def test_direct_subtree(self):
263
tree = self.make_simple_tree()
264
subtree = self.make_branch_and_tree('tree/a/b')
265
self.assertEqual([('directory', 'root-id'),
266
('directory', 'a-id'),
267
('tree-reference', 'b-id')],
268
[(ie.kind, ie.file_id)
269
for path, ie in tree.iter_entries_by_dir()])
271
def test_indirect_subtree(self):
272
tree = self.make_simple_tree()
273
subtree = self.make_branch_and_tree('tree/a')
274
self.assertEqual([('directory', 'root-id'),
275
('tree-reference', 'a-id')],
276
[(ie.kind, ie.file_id)
277
for path, ie in tree.iter_entries_by_dir()])
280
class TestWorkingTreeFormatRegistry(TestCase):
283
super(TestWorkingTreeFormatRegistry, self).setUp()
284
self.registry = workingtree.WorkingTreeFormatRegistry()
286
def test_register_unregister_format(self):
287
format = SampleTreeFormat()
288
self.registry.register(format)
289
self.assertEquals(format, self.registry.get("Sample tree format."))
290
self.registry.remove(format)
291
self.assertRaises(KeyError, self.registry.get, "Sample tree format.")
293
def test_get_all(self):
294
format = SampleTreeFormat()
295
self.assertEquals([], self.registry._get_all())
296
self.registry.register(format)
297
self.assertEquals([format], self.registry._get_all())
299
def test_register_extra(self):
300
format = SampleExtraTreeFormat()
301
self.assertEquals([], self.registry._get_all())
302
self.registry.register_extra(format)
303
self.assertEquals([format], self.registry._get_all())
305
def test_register_extra_lazy(self):
306
self.assertEquals([], self.registry._get_all())
307
self.registry.register_extra_lazy("bzrlib.tests.test_workingtree",
308
"SampleExtraTreeFormat")
309
formats = self.registry._get_all()
310
self.assertEquals(1, len(formats))
311
self.assertIsInstance(formats[0], SampleExtraTreeFormat)
155
314
class TestWorkingTreeFormat3(TestCaseWithTransport):
206
366
self.assertEquals(our_lock.peek(), None)
209
class TestFormat2WorkingTree(TestCaseWithTransport):
210
"""Tests that are specific to format 2 trees."""
212
def create_format2_tree(self, url):
213
return self.make_branch_and_tree(
214
url, format=bzrlib.bzrdir.BzrDirFormat6())
216
def test_conflicts(self):
217
# test backwards compatability
218
tree = self.create_format2_tree('.')
219
self.assertRaises(errors.UnsupportedOperation, tree.set_conflicts,
221
file('lala.BASE', 'wb').write('labase')
222
expected = ContentsConflict('lala')
223
self.assertEqual(list(tree.conflicts()), [expected])
224
file('lala', 'wb').write('la')
225
tree.add('lala', 'lala-id')
226
expected = ContentsConflict('lala', file_id='lala-id')
227
self.assertEqual(list(tree.conflicts()), [expected])
228
file('lala.THIS', 'wb').write('lathis')
229
file('lala.OTHER', 'wb').write('laother')
230
# When "text conflict"s happen, stem, THIS and OTHER are text
231
expected = TextConflict('lala', file_id='lala-id')
232
self.assertEqual(list(tree.conflicts()), [expected])
233
os.unlink('lala.OTHER')
234
os.mkdir('lala.OTHER')
235
expected = ContentsConflict('lala', file_id='lala-id')
236
self.assertEqual(list(tree.conflicts()), [expected])
368
def test_missing_pending_merges(self):
369
control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
370
control.create_repository()
371
control.create_branch()
372
tree = workingtree_3.WorkingTreeFormat3().initialize(control)
373
tree._transport.delete("pending-merges")
374
self.assertEqual([], tree.get_parent_ids())
377
class InstrumentedTree(object):
378
"""A instrumented tree to check the needs_tree_write_lock decorator."""
383
def lock_tree_write(self):
384
self._locks.append('t')
386
@needs_tree_write_lock
387
def method_with_tree_write_lock(self, *args, **kwargs):
388
"""A lock_tree_write decorated method that returns its arguments."""
391
@needs_tree_write_lock
392
def method_that_raises(self):
393
"""This method causes an exception when called with parameters.
395
This allows the decorator code to be checked - it should still call
400
self._locks.append('u')
403
class TestInstrumentedTree(TestCase):
405
def test_needs_tree_write_lock(self):
406
"""@needs_tree_write_lock should be semantically transparent."""
407
tree = InstrumentedTree()
409
'method_with_tree_write_lock',
410
tree.method_with_tree_write_lock.__name__)
411
self.assertDocstring(
412
"A lock_tree_write decorated method that returns its arguments.",
413
tree.method_with_tree_write_lock)
416
result = tree.method_with_tree_write_lock(1,2,3, a='b')
417
self.assertEqual((args, kwargs), result)
418
self.assertEqual(['t', 'u'], tree._locks)
419
self.assertRaises(TypeError, tree.method_that_raises, 'foo')
420
self.assertEqual(['t', 'u', 't', 'u'], tree._locks)
423
class TestRevert(TestCaseWithTransport):
425
def test_revert_conflicts_recursive(self):
426
this_tree = self.make_branch_and_tree('this-tree')
427
self.build_tree_contents([('this-tree/foo/',),
428
('this-tree/foo/bar', 'bar')])
429
this_tree.add(['foo', 'foo/bar'])
430
this_tree.commit('created foo/bar')
431
other_tree = this_tree.bzrdir.sprout('other-tree').open_workingtree()
432
self.build_tree_contents([('other-tree/foo/bar', 'baz')])
433
other_tree.commit('changed bar')
434
self.build_tree_contents([('this-tree/foo/bar', 'qux')])
435
this_tree.commit('changed qux')
436
this_tree.merge_from_branch(other_tree.branch)
437
self.assertEqual(1, len(this_tree.conflicts()))
438
this_tree.revert(['foo'])
439
self.assertEqual(0, len(this_tree.conflicts()))
442
class TestAutoResolve(TestCaseWithTransport):
444
def test_auto_resolve(self):
445
base = self.make_branch_and_tree('base')
446
self.build_tree_contents([('base/hello', 'Hello')])
447
base.add('hello', 'hello_id')
449
other = base.bzrdir.sprout('other').open_workingtree()
450
self.build_tree_contents([('other/hello', 'hELLO')])
451
other.commit('Case switch')
452
this = base.bzrdir.sprout('this').open_workingtree()
453
self.assertPathExists('this/hello')
454
self.build_tree_contents([('this/hello', 'Hello World')])
455
this.commit('Add World')
456
this.merge_from_branch(other.branch)
457
self.assertEqual([conflicts.TextConflict('hello', 'hello_id')],
460
self.assertEqual([conflicts.TextConflict('hello', 'hello_id')],
462
self.build_tree_contents([('this/hello', '<<<<<<<')])
464
self.assertEqual([conflicts.TextConflict('hello', 'hello_id')],
466
self.build_tree_contents([('this/hello', '=======')])
468
self.assertEqual([conflicts.TextConflict('hello', 'hello_id')],
470
self.build_tree_contents([('this/hello', '\n>>>>>>>')])
471
remaining, resolved = this.auto_resolve()
472
self.assertEqual([conflicts.TextConflict('hello', 'hello_id')],
474
self.assertEqual([], resolved)
475
self.build_tree_contents([('this/hello', 'hELLO wORLD')])
476
remaining, resolved = this.auto_resolve()
477
self.assertEqual([], this.conflicts())
478
self.assertEqual([conflicts.TextConflict('hello', 'hello_id')],
480
self.assertPathDoesNotExist('this/hello.BASE')
482
def test_auto_resolve_dir(self):
483
tree = self.make_branch_and_tree('tree')
484
self.build_tree(['tree/hello/'])
485
tree.add('hello', 'hello-id')
486
file_conflict = conflicts.TextConflict('file', 'hello-id')
487
tree.set_conflicts(conflicts.ConflictList([file_conflict]))
491
class TestFindTrees(TestCaseWithTransport):
493
def test_find_trees(self):
494
self.make_branch_and_tree('foo')
495
self.make_branch_and_tree('foo/bar')
496
# Sticking a tree inside a control dir is heinous, so let's skip it
497
self.make_branch_and_tree('foo/.bzr/baz')
498
self.make_branch('qux')
499
trees = workingtree.WorkingTree.find_trees('.')
500
self.assertEqual(2, len(list(trees)))