~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_workingtree.py

(jelmer) Support upgrading between the 2a and development-colo formats.
 (Jelmer Vernooij)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006 Canonical Ltd
 
1
# Copyright (C) 2005-2011 Canonical Ltd
2
2
# Authors:  Robert Collins <robert.collins@canonical.com>
3
3
#
4
4
# This program is free software; you can redistribute it and/or modify
13
13
#
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
17
 
 
18
 
from cStringIO import StringIO
19
 
import os
 
16
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
17
 
21
18
from bzrlib import (
22
19
    bzrdir,
23
20
    conflicts,
24
21
    errors,
 
22
    symbol_versioning,
 
23
    transport,
25
24
    workingtree,
 
25
    workingtree_3,
 
26
    workingtree_4,
26
27
    )
27
 
from bzrlib.branch import Branch
28
 
from bzrlib.bzrdir import BzrDir
29
28
from bzrlib.lockdir import LockDir
30
29
from bzrlib.mutabletree import needs_tree_write_lock
31
 
from bzrlib.symbol_versioning import zero_thirteen
32
30
from bzrlib.tests import TestCase, TestCaseWithTransport, TestSkipped
33
 
from bzrlib.transport import get_transport
34
31
from bzrlib.workingtree import (
35
32
    TreeEntry,
36
33
    TreeDirectory,
66
63
class TestDefaultFormat(TestCaseWithTransport):
67
64
 
68
65
    def test_get_set_default_format(self):
69
 
        old_format = workingtree.WorkingTreeFormat.get_default_format()
70
 
        # default is 3
71
 
        self.assertTrue(isinstance(old_format, workingtree.WorkingTreeFormat3))
72
 
        workingtree.WorkingTreeFormat.set_default_format(SampleTreeFormat())
73
 
        try:
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()
78
 
            dir.create_branch()
79
 
            result = dir.create_workingtree()
80
 
            self.assertEqual(result, 'A tree')
81
 
        finally:
82
 
            workingtree.WorkingTreeFormat.set_default_format(old_format)
83
 
        self.assertEqual(old_format, workingtree.WorkingTreeFormat.get_default_format())
 
66
        old_format = workingtree.format_registry.get_default()
 
67
        # default is 6
 
68
        self.assertTrue(isinstance(old_format, workingtree_4.WorkingTreeFormat6))
 
69
        workingtree.format_registry.set_default(SampleTreeFormat())
 
70
        try:
 
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()
 
75
            dir.create_branch()
 
76
            result = dir.create_workingtree()
 
77
            self.assertEqual(result, 'A tree')
 
78
        finally:
 
79
            workingtree.format_registry.set_default(old_format)
 
80
        self.assertEqual(old_format, workingtree.format_registry.get_default())
 
81
 
 
82
    def test_get_set_default_format_by_key(self):
 
83
        old_format = workingtree.format_registry.get_default()
 
84
        # default is 6
 
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())
 
90
        try:
 
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()
 
95
            dir.create_branch()
 
96
            result = dir.create_workingtree()
 
97
            self.assertEqual(result, 'A tree')
 
98
        finally:
 
99
            workingtree.format_registry.set_default_key(
 
100
                old_format.get_format_string())
 
101
        self.assertEqual(old_format, workingtree.format_registry.get_default())
 
102
 
 
103
    def test_open(self):
 
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)
 
109
 
 
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)
84
121
 
85
122
 
86
123
class SampleTreeFormat(workingtree.WorkingTreeFormat):
87
124
    """A sample format
88
125
 
89
 
    this format is initializable, unsupported to aid in testing the 
 
126
    this format is initializable, unsupported to aid in testing the
90
127
    open and open_downlevel routines.
91
128
    """
92
129
 
108
145
        return "opened tree."
109
146
 
110
147
 
 
148
class SampleExtraTreeFormat(workingtree.WorkingTreeFormat):
 
149
    """A sample format that does not support use in a metadir.
 
150
 
 
151
    """
 
152
 
 
153
    def get_format_string(self):
 
154
        # Not usable in a metadir, so no format string
 
155
        return None
 
156
 
 
157
    def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
 
158
                   accelerator_tree=None, hardlink=False):
 
159
        raise NotImplementedError(self.initialize)
 
160
 
 
161
    def is_supported(self):
 
162
        return False
 
163
 
 
164
    def open(self, transport, _found=False):
 
165
        raise NotImplementedError(self.open)
 
166
 
 
167
 
111
168
class TestWorkingTreeFormat(TestCaseWithTransport):
112
169
    """Tests for the WorkingTreeFormat facility."""
113
170
 
 
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)
 
177
        transport.mkdir('.')
 
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))
 
183
 
114
184
    def test_find_format(self):
115
185
        # is the right format object found for a working tree?
116
186
        # create a branch with a few known format objects.
120
190
            dir.create_repository()
121
191
            dir.create_branch()
122
192
            format.initialize(dir)
123
 
            t = get_transport(url)
 
193
            t = transport.get_transport(url)
124
194
            found_format = workingtree.WorkingTreeFormat.find_format(dir)
125
 
            self.failUnless(isinstance(found_format, format.__class__))
126
 
        check_format(workingtree.WorkingTreeFormat3(), "bar")
127
 
        
 
195
            self.assertIsInstance(found_format, format.__class__)
 
196
        check_format(workingtree_3.WorkingTreeFormat3(), "bar")
 
197
 
128
198
    def test_find_format_no_tree(self):
129
199
        dir = bzrdir.BzrDirMetaFormat1().initialize('.')
130
200
        self.assertRaises(errors.NoWorkingTree,
149
219
        # make a branch
150
220
        format.initialize(dir)
151
221
        # register a format for it.
152
 
        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))
153
227
        # which branch.Open will refuse (not supported)
154
228
        self.assertRaises(errors.UnsupportedFormatError, workingtree.WorkingTree.open, '.')
155
229
        # but open_downlevel will work
156
230
        self.assertEqual(format.open(dir), workingtree.WorkingTree.open_downlevel('.'))
157
231
        # unregister the format
158
 
        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))
 
237
 
 
238
 
 
239
class TestWorkingTreeIterEntriesByDir_wSubtrees(TestCaseWithTransport):
 
240
 
 
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')
 
247
        return tree
 
248
 
 
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'),
 
254
                          ('file', 'c-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'])])
 
261
 
 
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()])
 
270
 
 
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()])
 
278
 
 
279
 
 
280
class TestWorkingTreeFormatRegistry(TestCase):
 
281
 
 
282
    def setUp(self):
 
283
        super(TestWorkingTreeFormatRegistry, self).setUp()
 
284
        self.registry = workingtree.WorkingTreeFormatRegistry()
 
285
 
 
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.")
 
292
 
 
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())
 
298
 
 
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())
 
304
 
 
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)
159
312
 
160
313
 
161
314
class TestWorkingTreeFormat3(TestCaseWithTransport):
165
318
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
166
319
        control.create_repository()
167
320
        control.create_branch()
168
 
        tree = workingtree.WorkingTreeFormat3().initialize(control)
 
321
        tree = workingtree_3.WorkingTreeFormat3().initialize(control)
169
322
        # we want:
170
323
        # format 'Bazaar-NG Working Tree format 3'
171
324
        # inventory = blank inventory
175
328
        t = control.get_workingtree_transport(None)
176
329
        self.assertEqualDiff('Bazaar-NG Working Tree format 3',
177
330
                             t.get('format').read())
178
 
        self.assertEqualDiff(t.get('inventory').read(), 
 
331
        self.assertEqualDiff(t.get('inventory').read(),
179
332
                              '<inventory format="5">\n'
180
333
                              '</inventory>\n',
181
334
                             )
184
337
        self.assertFalse(t.has('inventory.basis'))
185
338
        # no last-revision file means 'None' or 'NULLREVISION'
186
339
        self.assertFalse(t.has('last-revision'))
187
 
        # TODO RBC 20060210 do a commit, check the inventory.basis is created 
 
340
        # TODO RBC 20060210 do a commit, check the inventory.basis is created
188
341
        # correctly and last-revision file becomes present.
189
342
 
190
343
    def test_uses_lockdir(self):
191
344
        """WorkingTreeFormat3 uses its own LockDir:
192
 
            
 
345
 
193
346
            - lock is a directory
194
347
            - when the WorkingTree is locked, LockDir can see that
195
348
        """
199
352
        repo = dir.create_repository()
200
353
        branch = dir.create_branch()
201
354
        try:
202
 
            tree = workingtree.WorkingTreeFormat3().initialize(dir)
 
355
            tree = workingtree_3.WorkingTreeFormat3().initialize(dir)
203
356
        except errors.NotLocalUrl:
204
357
            raise TestSkipped('Not a local URL')
205
358
        self.assertIsDirectory('.bzr', t)
216
369
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
217
370
        control.create_repository()
218
371
        control.create_branch()
219
 
        tree = workingtree.WorkingTreeFormat3().initialize(control)
220
 
        tree._control_files._transport.delete("pending-merges")
 
372
        tree = workingtree_3.WorkingTreeFormat3().initialize(control)
 
373
        tree._transport.delete("pending-merges")
221
374
        self.assertEqual([], tree.get_parent_ids())
222
375
 
223
376
 
224
 
class TestFormat2WorkingTree(TestCaseWithTransport):
225
 
    """Tests that are specific to format 2 trees."""
226
 
 
227
 
    def create_format2_tree(self, url):
228
 
        return self.make_branch_and_tree(
229
 
            url, format=bzrdir.BzrDirFormat6())
230
 
 
231
 
    def test_conflicts(self):
232
 
        # test backwards compatability
233
 
        tree = self.create_format2_tree('.')
234
 
        self.assertRaises(errors.UnsupportedOperation, tree.set_conflicts,
235
 
                          None)
236
 
        file('lala.BASE', 'wb').write('labase')
237
 
        expected = conflicts.ContentsConflict('lala')
238
 
        self.assertEqual(list(tree.conflicts()), [expected])
239
 
        file('lala', 'wb').write('la')
240
 
        tree.add('lala', 'lala-id')
241
 
        expected = conflicts.ContentsConflict('lala', file_id='lala-id')
242
 
        self.assertEqual(list(tree.conflicts()), [expected])
243
 
        file('lala.THIS', 'wb').write('lathis')
244
 
        file('lala.OTHER', 'wb').write('laother')
245
 
        # When "text conflict"s happen, stem, THIS and OTHER are text
246
 
        expected = conflicts.TextConflict('lala', file_id='lala-id')
247
 
        self.assertEqual(list(tree.conflicts()), [expected])
248
 
        os.unlink('lala.OTHER')
249
 
        os.mkdir('lala.OTHER')
250
 
        expected = conflicts.ContentsConflict('lala', file_id='lala-id')
251
 
        self.assertEqual(list(tree.conflicts()), [expected])
252
 
 
253
 
 
254
 
class TestNonFormatSpecificCode(TestCaseWithTransport):
255
 
    """This class contains tests of workingtree that are not format specific."""
256
 
 
257
 
    def test_gen_file_id(self):
258
 
        file_id = self.applyDeprecated(zero_thirteen, workingtree.gen_file_id,
259
 
                                      'filename')
260
 
        self.assertStartsWith(file_id, 'filename-')
261
 
 
262
 
    def test_gen_root_id(self):
263
 
        file_id = self.applyDeprecated(zero_thirteen, workingtree.gen_root_id)
264
 
        self.assertStartsWith(file_id, 'tree_root-')
265
 
        
266
 
 
267
377
class InstrumentedTree(object):
268
378
    """A instrumented tree to check the needs_tree_write_lock decorator."""
269
379
 
281
391
    @needs_tree_write_lock
282
392
    def method_that_raises(self):
283
393
        """This method causes an exception when called with parameters.
284
 
        
 
394
 
285
395
        This allows the decorator code to be checked - it should still call
286
396
        unlock.
287
397
        """
298
408
        self.assertEqual(
299
409
            'method_with_tree_write_lock',
300
410
            tree.method_with_tree_write_lock.__name__)
301
 
        self.assertEqual(
 
411
        self.assertDocstring(
302
412
            "A lock_tree_write decorated method that returns its arguments.",
303
 
            tree.method_with_tree_write_lock.__doc__)
 
413
            tree.method_with_tree_write_lock)
304
414
        args = (1, 2, 3)
305
415
        kwargs = {'a':'b'}
306
416
        result = tree.method_with_tree_write_lock(1,2,3, a='b')
340
450
        self.build_tree_contents([('other/hello', 'hELLO')])
341
451
        other.commit('Case switch')
342
452
        this = base.bzrdir.sprout('this').open_workingtree()
343
 
        self.failUnlessExists('this/hello')
 
453
        self.assertPathExists('this/hello')
344
454
        self.build_tree_contents([('this/hello', 'Hello World')])
345
455
        this.commit('Add World')
346
456
        this.merge_from_branch(other.branch)
347
 
        self.assertEqual([conflicts.TextConflict('hello', None, 'hello_id')],
 
457
        self.assertEqual([conflicts.TextConflict('hello', 'hello_id')],
348
458
                         this.conflicts())
349
459
        this.auto_resolve()
350
 
        self.assertEqual([conflicts.TextConflict('hello', None, 'hello_id')],
 
460
        self.assertEqual([conflicts.TextConflict('hello', 'hello_id')],
351
461
                         this.conflicts())
352
462
        self.build_tree_contents([('this/hello', '<<<<<<<')])
353
463
        this.auto_resolve()
354
 
        self.assertEqual([conflicts.TextConflict('hello', None, 'hello_id')],
 
464
        self.assertEqual([conflicts.TextConflict('hello', 'hello_id')],
355
465
                         this.conflicts())
356
466
        self.build_tree_contents([('this/hello', '=======')])
357
467
        this.auto_resolve()
358
 
        self.assertEqual([conflicts.TextConflict('hello', None, 'hello_id')],
 
468
        self.assertEqual([conflicts.TextConflict('hello', 'hello_id')],
359
469
                         this.conflicts())
360
470
        self.build_tree_contents([('this/hello', '\n>>>>>>>')])
361
471
        remaining, resolved = this.auto_resolve()
362
 
        self.assertEqual([conflicts.TextConflict('hello', None, 'hello_id')],
 
472
        self.assertEqual([conflicts.TextConflict('hello', 'hello_id')],
363
473
                         this.conflicts())
364
474
        self.assertEqual([], resolved)
365
475
        self.build_tree_contents([('this/hello', 'hELLO wORLD')])
366
476
        remaining, resolved = this.auto_resolve()
367
477
        self.assertEqual([], this.conflicts())
368
 
        self.assertEqual([conflicts.TextConflict('hello', None, 'hello_id')],
 
478
        self.assertEqual([conflicts.TextConflict('hello', 'hello_id')],
369
479
                         resolved)
370
 
        self.failIfExists('this/hello.BASE')
 
480
        self.assertPathDoesNotExist('this/hello.BASE')
371
481
 
372
482
    def test_auto_resolve_dir(self):
373
483
        tree = self.make_branch_and_tree('tree')
374
484
        self.build_tree(['tree/hello/'])
375
485
        tree.add('hello', 'hello-id')
376
 
        file_conflict = conflicts.TextConflict('file', None, 'hello-id')
 
486
        file_conflict = conflicts.TextConflict('file', 'hello-id')
377
487
        tree.set_conflicts(conflicts.ConflictList([file_conflict]))
378
488
        tree.auto_resolve()
379
489