~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_workingtree.py

  • Committer: Robert Collins
  • Date: 2007-10-23 22:14:32 UTC
  • mto: (2592.6.3 repository)
  • mto: This revision was merged to the branch mainline in revision 2967.
  • Revision ID: robertc@robertcollins.net-20071023221432-j8zndh1oiegql3cu
* Commit updates the state of the working tree via a delta rather than
  supplying entirely new basis trees. For commit of a single specified file
  this reduces the wall clock time for commit by roughly a 30%.
  (Robert Collins, Martin Pool)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2011 Canonical Ltd
 
1
# Copyright (C) 2005, 2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
16
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
17
 
 
18
from cStringIO import StringIO
 
19
import os
17
20
 
18
21
from bzrlib import (
19
22
    bzrdir,
20
23
    conflicts,
21
24
    errors,
22
 
    symbol_versioning,
23
 
    transport,
24
25
    workingtree,
25
26
    )
 
27
from bzrlib.branch import Branch
 
28
from bzrlib.bzrdir import BzrDir
26
29
from bzrlib.lockdir import LockDir
27
30
from bzrlib.mutabletree import needs_tree_write_lock
 
31
from bzrlib.symbol_versioning import zero_thirteen
28
32
from bzrlib.tests import TestCase, TestCaseWithTransport, TestSkipped
 
33
from bzrlib.transport import get_transport
29
34
from bzrlib.workingtree import (
30
35
    TreeEntry,
31
36
    TreeDirectory,
61
66
class TestDefaultFormat(TestCaseWithTransport):
62
67
 
63
68
    def test_get_set_default_format(self):
64
 
        old_format = workingtree.format_registry.get_default()
 
69
        old_format = workingtree.WorkingTreeFormat.get_default_format()
65
70
        # default is 3
66
71
        self.assertTrue(isinstance(old_format, workingtree.WorkingTreeFormat3))
67
 
        workingtree.format_registry.set_default(SampleTreeFormat())
 
72
        workingtree.WorkingTreeFormat.set_default_format(SampleTreeFormat())
68
73
        try:
69
74
            # the default branch format is used by the meta dir format
70
75
            # which is not the default bzrdir format at this point
74
79
            result = dir.create_workingtree()
75
80
            self.assertEqual(result, 'A tree')
76
81
        finally:
77
 
            workingtree.format_registry.set_default(old_format)
78
 
        self.assertEqual(old_format, workingtree.format_registry.get_default())
79
 
 
80
 
    def test_open(self):
81
 
        tree = self.make_branch_and_tree('.')
82
 
        open_direct = workingtree.WorkingTree.open('.')
83
 
        self.assertEqual(tree.basedir, open_direct.basedir)
84
 
        open_no_args = workingtree.WorkingTree.open()
85
 
        self.assertEqual(tree.basedir, open_no_args.basedir)
86
 
 
87
 
    def test_open_containing(self):
88
 
        tree = self.make_branch_and_tree('.')
89
 
        open_direct, relpath = workingtree.WorkingTree.open_containing('.')
90
 
        self.assertEqual(tree.basedir, open_direct.basedir)
91
 
        self.assertEqual('', relpath)
92
 
        open_no_args, relpath = workingtree.WorkingTree.open_containing()
93
 
        self.assertEqual(tree.basedir, open_no_args.basedir)
94
 
        self.assertEqual('', relpath)
95
 
        open_subdir, relpath = workingtree.WorkingTree.open_containing('subdir')
96
 
        self.assertEqual(tree.basedir, open_subdir.basedir)
97
 
        self.assertEqual('subdir', relpath)
 
82
            workingtree.WorkingTreeFormat.set_default_format(old_format)
 
83
        self.assertEqual(old_format, workingtree.WorkingTreeFormat.get_default_format())
98
84
 
99
85
 
100
86
class SampleTreeFormat(workingtree.WorkingTreeFormat):
101
87
    """A sample format
102
88
 
103
 
    this format is initializable, unsupported to aid in testing the
 
89
    this format is initializable, unsupported to aid in testing the 
104
90
    open and open_downlevel routines.
105
91
    """
106
92
 
108
94
        """See WorkingTreeFormat.get_format_string()."""
109
95
        return "Sample tree format."
110
96
 
111
 
    def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
112
 
                   accelerator_tree=None, hardlink=False):
 
97
    def initialize(self, a_bzrdir, revision_id=None):
113
98
        """Sample branches cannot be created."""
114
99
        t = a_bzrdir.get_workingtree_transport(self)
115
100
        t.put_bytes('format', self.get_format_string())
122
107
        return "opened tree."
123
108
 
124
109
 
125
 
class SampleExtraTreeFormat(workingtree.WorkingTreeFormat):
126
 
    """A sample format that does not support use in a metadir.
127
 
 
128
 
    """
129
 
 
130
 
    def get_format_string(self):
131
 
        # Not usable in a metadir, so no format string
132
 
        return None
133
 
 
134
 
    def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
135
 
                   accelerator_tree=None, hardlink=False):
136
 
        raise NotImplementedError(self.initialize)
137
 
 
138
 
    def is_supported(self):
139
 
        return False
140
 
 
141
 
    def open(self, transport, _found=False):
142
 
        raise NotImplementedError(self.open)
143
 
 
144
 
 
145
110
class TestWorkingTreeFormat(TestCaseWithTransport):
146
111
    """Tests for the WorkingTreeFormat facility."""
147
112
 
154
119
            dir.create_repository()
155
120
            dir.create_branch()
156
121
            format.initialize(dir)
157
 
            t = transport.get_transport(url)
 
122
            t = get_transport(url)
158
123
            found_format = workingtree.WorkingTreeFormat.find_format(dir)
159
 
            self.assertIsInstance(found_format, format.__class__)
 
124
            self.failUnless(isinstance(found_format, format.__class__))
160
125
        check_format(workingtree.WorkingTreeFormat3(), "bar")
161
 
 
 
126
        
162
127
    def test_find_format_no_tree(self):
163
128
        dir = bzrdir.BzrDirMetaFormat1().initialize('.')
164
129
        self.assertRaises(errors.NoWorkingTree,
183
148
        # make a branch
184
149
        format.initialize(dir)
185
150
        # register a format for it.
186
 
        self.applyDeprecated(symbol_versioning.deprecated_in((2, 4, 0)),
187
 
            workingtree.WorkingTreeFormat.register_format, format)
188
 
        self.assertTrue(format in 
189
 
            self.applyDeprecated(symbol_versioning.deprecated_in((2, 4, 0)),
190
 
                workingtree.WorkingTreeFormat.get_formats))
 
151
        workingtree.WorkingTreeFormat.register_format(format)
191
152
        # which branch.Open will refuse (not supported)
192
153
        self.assertRaises(errors.UnsupportedFormatError, workingtree.WorkingTree.open, '.')
193
154
        # but open_downlevel will work
194
155
        self.assertEqual(format.open(dir), workingtree.WorkingTree.open_downlevel('.'))
195
156
        # unregister the format
196
 
        self.applyDeprecated(symbol_versioning.deprecated_in((2, 4, 0)),
197
 
            workingtree.WorkingTreeFormat.unregister_format, format)
198
 
        self.assertFalse(format in
199
 
            self.applyDeprecated(symbol_versioning.deprecated_in((2, 4, 0)),
200
 
                workingtree.WorkingTreeFormat.get_formats))
201
 
 
202
 
 
203
 
class TestWorkingTreeFormatRegistry(TestCase):
204
 
 
205
 
    def setUp(self):
206
 
        super(TestWorkingTreeFormatRegistry, self).setUp()
207
 
        self.registry = workingtree.WorkingTreeFormatRegistry()
208
 
 
209
 
    def test_register_unregister_format(self):
210
 
        format = SampleTreeFormat()
211
 
        self.registry.register(format)
212
 
        self.assertEquals(format, self.registry.get("Sample tree format."))
213
 
        self.registry.remove(format)
214
 
        self.assertRaises(KeyError, self.registry.get, "Sample tree format.")
215
 
 
216
 
    def test_get_all(self):
217
 
        format = SampleTreeFormat()
218
 
        self.assertEquals([], self.registry._get_all())
219
 
        self.registry.register(format)
220
 
        self.assertEquals([format], self.registry._get_all())
221
 
 
222
 
    def test_register_extra(self):
223
 
        format = SampleExtraTreeFormat()
224
 
        self.assertEquals([], self.registry._get_all())
225
 
        self.registry.register_extra(format)
226
 
        self.assertEquals([format], self.registry._get_all())
227
 
 
228
 
    def test_register_extra_lazy(self):
229
 
        self.assertEquals([], self.registry._get_all())
230
 
        self.registry.register_extra_lazy("bzrlib.tests.test_workingtree",
231
 
            "SampleExtraTreeFormat")
232
 
        formats = self.registry._get_all()
233
 
        self.assertEquals(1, len(formats))
234
 
        self.assertIsInstance(formats[0], SampleExtraTreeFormat)
 
157
        workingtree.WorkingTreeFormat.unregister_format(format)
235
158
 
236
159
 
237
160
class TestWorkingTreeFormat3(TestCaseWithTransport):
251
174
        t = control.get_workingtree_transport(None)
252
175
        self.assertEqualDiff('Bazaar-NG Working Tree format 3',
253
176
                             t.get('format').read())
254
 
        self.assertEqualDiff(t.get('inventory').read(),
 
177
        self.assertEqualDiff(t.get('inventory').read(), 
255
178
                              '<inventory format="5">\n'
256
179
                              '</inventory>\n',
257
180
                             )
260
183
        self.assertFalse(t.has('inventory.basis'))
261
184
        # no last-revision file means 'None' or 'NULLREVISION'
262
185
        self.assertFalse(t.has('last-revision'))
263
 
        # 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 
264
187
        # correctly and last-revision file becomes present.
265
188
 
266
189
    def test_uses_lockdir(self):
267
190
        """WorkingTreeFormat3 uses its own LockDir:
268
 
 
 
191
            
269
192
            - lock is a directory
270
193
            - when the WorkingTree is locked, LockDir can see that
271
194
        """
293
216
        control.create_repository()
294
217
        control.create_branch()
295
218
        tree = workingtree.WorkingTreeFormat3().initialize(control)
296
 
        tree._transport.delete("pending-merges")
 
219
        tree._control_files._transport.delete("pending-merges")
297
220
        self.assertEqual([], tree.get_parent_ids())
298
221
 
299
222
 
 
223
class TestFormat2WorkingTree(TestCaseWithTransport):
 
224
    """Tests that are specific to format 2 trees."""
 
225
 
 
226
    def create_format2_tree(self, url):
 
227
        return self.make_branch_and_tree(
 
228
            url, format=bzrdir.BzrDirFormat6())
 
229
 
 
230
    def test_conflicts(self):
 
231
        # test backwards compatability
 
232
        tree = self.create_format2_tree('.')
 
233
        self.assertRaises(errors.UnsupportedOperation, tree.set_conflicts,
 
234
                          None)
 
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])
 
251
 
 
252
 
 
253
class TestNonFormatSpecificCode(TestCaseWithTransport):
 
254
    """This class contains tests of workingtree that are not format specific."""
 
255
 
 
256
    def test_gen_file_id(self):
 
257
        file_id = self.applyDeprecated(zero_thirteen, workingtree.gen_file_id,
 
258
                                      'filename')
 
259
        self.assertStartsWith(file_id, 'filename-')
 
260
 
 
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-')
 
264
        
 
265
 
300
266
class InstrumentedTree(object):
301
267
    """A instrumented tree to check the needs_tree_write_lock decorator."""
302
268
 
314
280
    @needs_tree_write_lock
315
281
    def method_that_raises(self):
316
282
        """This method causes an exception when called with parameters.
317
 
 
 
283
        
318
284
        This allows the decorator code to be checked - it should still call
319
285
        unlock.
320
286
        """
331
297
        self.assertEqual(
332
298
            'method_with_tree_write_lock',
333
299
            tree.method_with_tree_write_lock.__name__)
334
 
        self.assertDocstring(
 
300
        self.assertEqual(
335
301
            "A lock_tree_write decorated method that returns its arguments.",
336
 
            tree.method_with_tree_write_lock)
 
302
            tree.method_with_tree_write_lock.__doc__)
337
303
        args = (1, 2, 3)
338
304
        kwargs = {'a':'b'}
339
305
        result = tree.method_with_tree_write_lock(1,2,3, a='b')
343
309
        self.assertEqual(['t', 'u', 't', 'u'], tree._locks)
344
310
 
345
311
 
346
 
class TestRevert(TestCaseWithTransport):
347
 
 
348
 
    def test_revert_conflicts_recursive(self):
349
 
        this_tree = self.make_branch_and_tree('this-tree')
350
 
        self.build_tree_contents([('this-tree/foo/',),
351
 
                                  ('this-tree/foo/bar', 'bar')])
352
 
        this_tree.add(['foo', 'foo/bar'])
353
 
        this_tree.commit('created foo/bar')
354
 
        other_tree = this_tree.bzrdir.sprout('other-tree').open_workingtree()
355
 
        self.build_tree_contents([('other-tree/foo/bar', 'baz')])
356
 
        other_tree.commit('changed bar')
357
 
        self.build_tree_contents([('this-tree/foo/bar', 'qux')])
358
 
        this_tree.commit('changed qux')
359
 
        this_tree.merge_from_branch(other_tree.branch)
360
 
        self.assertEqual(1, len(this_tree.conflicts()))
361
 
        this_tree.revert(['foo'])
362
 
        self.assertEqual(0, len(this_tree.conflicts()))
363
 
 
364
 
 
365
312
class TestAutoResolve(TestCaseWithTransport):
366
313
 
367
314
    def test_auto_resolve(self):
373
320
        self.build_tree_contents([('other/hello', 'hELLO')])
374
321
        other.commit('Case switch')
375
322
        this = base.bzrdir.sprout('this').open_workingtree()
376
 
        self.assertPathExists('this/hello')
 
323
        self.failUnlessExists('this/hello')
377
324
        self.build_tree_contents([('this/hello', 'Hello World')])
378
325
        this.commit('Add World')
379
326
        this.merge_from_branch(other.branch)
380
 
        self.assertEqual([conflicts.TextConflict('hello', 'hello_id')],
 
327
        self.assertEqual([conflicts.TextConflict('hello', None, 'hello_id')],
381
328
                         this.conflicts())
382
329
        this.auto_resolve()
383
 
        self.assertEqual([conflicts.TextConflict('hello', 'hello_id')],
 
330
        self.assertEqual([conflicts.TextConflict('hello', None, 'hello_id')],
384
331
                         this.conflicts())
385
332
        self.build_tree_contents([('this/hello', '<<<<<<<')])
386
333
        this.auto_resolve()
387
 
        self.assertEqual([conflicts.TextConflict('hello', 'hello_id')],
 
334
        self.assertEqual([conflicts.TextConflict('hello', None, 'hello_id')],
388
335
                         this.conflicts())
389
336
        self.build_tree_contents([('this/hello', '=======')])
390
337
        this.auto_resolve()
391
 
        self.assertEqual([conflicts.TextConflict('hello', 'hello_id')],
 
338
        self.assertEqual([conflicts.TextConflict('hello', None, 'hello_id')],
392
339
                         this.conflicts())
393
340
        self.build_tree_contents([('this/hello', '\n>>>>>>>')])
394
341
        remaining, resolved = this.auto_resolve()
395
 
        self.assertEqual([conflicts.TextConflict('hello', 'hello_id')],
 
342
        self.assertEqual([conflicts.TextConflict('hello', None, 'hello_id')],
396
343
                         this.conflicts())
397
344
        self.assertEqual([], resolved)
398
345
        self.build_tree_contents([('this/hello', 'hELLO wORLD')])
399
346
        remaining, resolved = this.auto_resolve()
400
347
        self.assertEqual([], this.conflicts())
401
 
        self.assertEqual([conflicts.TextConflict('hello', 'hello_id')],
 
348
        self.assertEqual([conflicts.TextConflict('hello', None, 'hello_id')],
402
349
                         resolved)
403
 
        self.assertPathDoesNotExist('this/hello.BASE')
 
350
        self.failIfExists('this/hello.BASE')
404
351
 
405
352
    def test_auto_resolve_dir(self):
406
353
        tree = self.make_branch_and_tree('tree')
407
354
        self.build_tree(['tree/hello/'])
408
355
        tree.add('hello', 'hello-id')
409
 
        file_conflict = conflicts.TextConflict('file', 'hello-id')
 
356
        file_conflict = conflicts.TextConflict('file', None, 'hello-id')
410
357
        tree.set_conflicts(conflicts.ConflictList([file_conflict]))
411
358
        tree.auto_resolve()
412
 
 
413
 
 
414
 
class TestFindTrees(TestCaseWithTransport):
415
 
 
416
 
    def test_find_trees(self):
417
 
        self.make_branch_and_tree('foo')
418
 
        self.make_branch_and_tree('foo/bar')
419
 
        # Sticking a tree inside a control dir is heinous, so let's skip it
420
 
        self.make_branch_and_tree('foo/.bzr/baz')
421
 
        self.make_branch('qux')
422
 
        trees = workingtree.WorkingTree.find_trees('.')
423
 
        self.assertEqual(2, len(list(trees)))