/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_workingtree.py

  • Committer: Martin Pool
  • Date: 2011-02-09 08:03:35 UTC
  • mto: This revision was merged to the branch mainline in revision 5663.
  • Revision ID: mbp@sourcefrog.net-20110209080335-0gczvdsr6bzpwho8
Rename _fallback_vfs to _immediate_fallbacks

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
 
16
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
17
 
18
 
from cStringIO import StringIO
19
18
import os
20
19
 
21
 
import bzrlib
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
 
20
from bzrlib import (
 
21
    bzrdir,
 
22
    conflicts,
 
23
    errors,
 
24
    transport,
 
25
    workingtree,
 
26
    )
28
27
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,
35
 
                                WorkingTree)
 
28
from bzrlib.mutabletree import needs_tree_write_lock
 
29
from bzrlib.tests import TestCase, TestCaseWithTransport, TestSkipped
 
30
from bzrlib.workingtree import (
 
31
    TreeEntry,
 
32
    TreeDirectory,
 
33
    TreeFile,
 
34
    TreeLink,
 
35
    )
 
36
 
36
37
 
37
38
class TestTreeDirectory(TestCaseWithTransport):
38
39
 
77
78
            workingtree.WorkingTreeFormat.set_default_format(old_format)
78
79
        self.assertEqual(old_format, workingtree.WorkingTreeFormat.get_default_format())
79
80
 
 
81
    def test_open(self):
 
82
        tree = self.make_branch_and_tree('.')
 
83
        open_direct = workingtree.WorkingTree.open('.')
 
84
        self.assertEqual(tree.basedir, open_direct.basedir)
 
85
        open_no_args = workingtree.WorkingTree.open()
 
86
        self.assertEqual(tree.basedir, open_no_args.basedir)
 
87
 
 
88
    def test_open_containing(self):
 
89
        tree = self.make_branch_and_tree('.')
 
90
        open_direct, relpath = workingtree.WorkingTree.open_containing('.')
 
91
        self.assertEqual(tree.basedir, open_direct.basedir)
 
92
        self.assertEqual('', relpath)
 
93
        open_no_args, relpath = workingtree.WorkingTree.open_containing()
 
94
        self.assertEqual(tree.basedir, open_no_args.basedir)
 
95
        self.assertEqual('', relpath)
 
96
        open_subdir, relpath = workingtree.WorkingTree.open_containing('subdir')
 
97
        self.assertEqual(tree.basedir, open_subdir.basedir)
 
98
        self.assertEqual('subdir', relpath)
 
99
 
80
100
 
81
101
class SampleTreeFormat(workingtree.WorkingTreeFormat):
82
102
    """A sample format
83
103
 
84
 
    this format is initializable, unsupported to aid in testing the 
 
104
    this format is initializable, unsupported to aid in testing the
85
105
    open and open_downlevel routines.
86
106
    """
87
107
 
89
109
        """See WorkingTreeFormat.get_format_string()."""
90
110
        return "Sample tree format."
91
111
 
92
 
    def initialize(self, a_bzrdir, revision_id=None):
 
112
    def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
 
113
                   accelerator_tree=None, hardlink=False):
93
114
        """Sample branches cannot be created."""
94
115
        t = a_bzrdir.get_workingtree_transport(self)
95
 
        t.put('format', StringIO(self.get_format_string()))
 
116
        t.put_bytes('format', self.get_format_string())
96
117
        return 'A tree'
97
118
 
98
119
    def is_supported(self):
102
123
        return "opened tree."
103
124
 
104
125
 
 
126
class SampleExtraTreeFormat(workingtree.WorkingTreeFormat):
 
127
    """A sample format that does not support use in a metadir.
 
128
 
 
129
    """
 
130
 
 
131
    def get_format_string(self):
 
132
        # Not usable in a metadir, so no format string
 
133
        return None
 
134
 
 
135
    def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
 
136
                   accelerator_tree=None, hardlink=False):
 
137
        raise NotImplementedError(self.initialize)
 
138
 
 
139
    def is_supported(self):
 
140
        return False
 
141
 
 
142
    def open(self, transport, _found=False):
 
143
        raise NotImplementedError(self.open)
 
144
 
 
145
 
105
146
class TestWorkingTreeFormat(TestCaseWithTransport):
106
147
    """Tests for the WorkingTreeFormat facility."""
107
148
 
114
155
            dir.create_repository()
115
156
            dir.create_branch()
116
157
            format.initialize(dir)
117
 
            t = get_transport(url)
 
158
            t = transport.get_transport(url)
118
159
            found_format = workingtree.WorkingTreeFormat.find_format(dir)
119
160
            self.failUnless(isinstance(found_format, format.__class__))
120
161
        check_format(workingtree.WorkingTreeFormat3(), "bar")
121
 
        
 
162
 
122
163
    def test_find_format_no_tree(self):
123
164
        dir = bzrdir.BzrDirMetaFormat1().initialize('.')
124
165
        self.assertRaises(errors.NoWorkingTree,
144
185
        format.initialize(dir)
145
186
        # register a format for it.
146
187
        workingtree.WorkingTreeFormat.register_format(format)
 
188
        self.assertTrue(format in workingtree.WorkingTreeFormat.get_formats())
147
189
        # which branch.Open will refuse (not supported)
148
190
        self.assertRaises(errors.UnsupportedFormatError, workingtree.WorkingTree.open, '.')
149
191
        # but open_downlevel will work
150
192
        self.assertEqual(format.open(dir), workingtree.WorkingTree.open_downlevel('.'))
151
193
        # unregister the format
152
194
        workingtree.WorkingTreeFormat.unregister_format(format)
 
195
        self.assertFalse(format in workingtree.WorkingTreeFormat.get_formats())
 
196
 
 
197
    def test_register_unregister_extra_format(self):
 
198
        format = SampleExtraTreeFormat()
 
199
        workingtree.WorkingTreeFormat.register_extra_format(format)
 
200
        self.assertTrue(format in workingtree.WorkingTreeFormat.get_formats())
 
201
        workingtree.WorkingTreeFormat.unregister_extra_format(format)
 
202
        self.assertFalse(format in workingtree.WorkingTreeFormat.get_formats())
153
203
 
154
204
 
155
205
class TestWorkingTreeFormat3(TestCaseWithTransport):
169
219
        t = control.get_workingtree_transport(None)
170
220
        self.assertEqualDiff('Bazaar-NG Working Tree format 3',
171
221
                             t.get('format').read())
172
 
        self.assertEqualDiff('<inventory format="5">\n'
173
 
                             '</inventory>\n',
174
 
                             t.get('inventory').read())
 
222
        self.assertEqualDiff(t.get('inventory').read(),
 
223
                              '<inventory format="5">\n'
 
224
                              '</inventory>\n',
 
225
                             )
175
226
        self.assertEqualDiff('### bzr hashcache v5\n',
176
227
                             t.get('stat-cache').read())
177
228
        self.assertFalse(t.has('inventory.basis'))
178
229
        # no last-revision file means 'None' or 'NULLREVISION'
179
230
        self.assertFalse(t.has('last-revision'))
180
 
        # TODO RBC 20060210 do a commit, check the inventory.basis is created 
 
231
        # TODO RBC 20060210 do a commit, check the inventory.basis is created
181
232
        # correctly and last-revision file becomes present.
182
233
 
183
234
    def test_uses_lockdir(self):
184
235
        """WorkingTreeFormat3 uses its own LockDir:
185
 
            
 
236
 
186
237
            - lock is a directory
187
238
            - when the WorkingTree is locked, LockDir can see that
188
239
        """
205
256
        tree.unlock()
206
257
        self.assertEquals(our_lock.peek(), None)
207
258
 
 
259
    def test_missing_pending_merges(self):
 
260
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
 
261
        control.create_repository()
 
262
        control.create_branch()
 
263
        tree = workingtree.WorkingTreeFormat3().initialize(control)
 
264
        tree._transport.delete("pending-merges")
 
265
        self.assertEqual([], tree.get_parent_ids())
 
266
 
 
267
 
 
268
class TestFormat2WorkingTree(TestCaseWithTransport):
 
269
    """Tests that are specific to format 2 trees."""
 
270
 
208
271
    def create_format2_tree(self, url):
209
 
        return BzrDir.create_standalone_workingtree(url)
 
272
        return self.make_branch_and_tree(
 
273
            url, format=bzrdir.BzrDirFormat6())
210
274
 
211
 
    def test_conflicts_format2(self):
 
275
    def test_conflicts(self):
212
276
        # test backwards compatability
213
277
        tree = self.create_format2_tree('.')
214
278
        self.assertRaises(errors.UnsupportedOperation, tree.set_conflicts,
215
279
                          None)
216
280
        file('lala.BASE', 'wb').write('labase')
217
 
        expected = ContentsConflict('lala')
 
281
        expected = conflicts.ContentsConflict('lala')
218
282
        self.assertEqual(list(tree.conflicts()), [expected])
219
283
        file('lala', 'wb').write('la')
220
284
        tree.add('lala', 'lala-id')
221
 
        expected = ContentsConflict('lala', file_id='lala-id')
 
285
        expected = conflicts.ContentsConflict('lala', file_id='lala-id')
222
286
        self.assertEqual(list(tree.conflicts()), [expected])
223
287
        file('lala.THIS', 'wb').write('lathis')
224
288
        file('lala.OTHER', 'wb').write('laother')
225
289
        # When "text conflict"s happen, stem, THIS and OTHER are text
226
 
        expected = TextConflict('lala', file_id='lala-id')
 
290
        expected = conflicts.TextConflict('lala', file_id='lala-id')
227
291
        self.assertEqual(list(tree.conflicts()), [expected])
228
292
        os.unlink('lala.OTHER')
229
293
        os.mkdir('lala.OTHER')
230
 
        expected = ContentsConflict('lala', file_id='lala-id')
 
294
        expected = conflicts.ContentsConflict('lala', file_id='lala-id')
231
295
        self.assertEqual(list(tree.conflicts()), [expected])
 
296
 
 
297
 
 
298
class InstrumentedTree(object):
 
299
    """A instrumented tree to check the needs_tree_write_lock decorator."""
 
300
 
 
301
    def __init__(self):
 
302
        self._locks = []
 
303
 
 
304
    def lock_tree_write(self):
 
305
        self._locks.append('t')
 
306
 
 
307
    @needs_tree_write_lock
 
308
    def method_with_tree_write_lock(self, *args, **kwargs):
 
309
        """A lock_tree_write decorated method that returns its arguments."""
 
310
        return args, kwargs
 
311
 
 
312
    @needs_tree_write_lock
 
313
    def method_that_raises(self):
 
314
        """This method causes an exception when called with parameters.
 
315
 
 
316
        This allows the decorator code to be checked - it should still call
 
317
        unlock.
 
318
        """
 
319
 
 
320
    def unlock(self):
 
321
        self._locks.append('u')
 
322
 
 
323
 
 
324
class TestInstrumentedTree(TestCase):
 
325
 
 
326
    def test_needs_tree_write_lock(self):
 
327
        """@needs_tree_write_lock should be semantically transparent."""
 
328
        tree = InstrumentedTree()
 
329
        self.assertEqual(
 
330
            'method_with_tree_write_lock',
 
331
            tree.method_with_tree_write_lock.__name__)
 
332
        self.assertDocstring(
 
333
            "A lock_tree_write decorated method that returns its arguments.",
 
334
            tree.method_with_tree_write_lock)
 
335
        args = (1, 2, 3)
 
336
        kwargs = {'a':'b'}
 
337
        result = tree.method_with_tree_write_lock(1,2,3, a='b')
 
338
        self.assertEqual((args, kwargs), result)
 
339
        self.assertEqual(['t', 'u'], tree._locks)
 
340
        self.assertRaises(TypeError, tree.method_that_raises, 'foo')
 
341
        self.assertEqual(['t', 'u', 't', 'u'], tree._locks)
 
342
 
 
343
 
 
344
class TestRevert(TestCaseWithTransport):
 
345
 
 
346
    def test_revert_conflicts_recursive(self):
 
347
        this_tree = self.make_branch_and_tree('this-tree')
 
348
        self.build_tree_contents([('this-tree/foo/',),
 
349
                                  ('this-tree/foo/bar', 'bar')])
 
350
        this_tree.add(['foo', 'foo/bar'])
 
351
        this_tree.commit('created foo/bar')
 
352
        other_tree = this_tree.bzrdir.sprout('other-tree').open_workingtree()
 
353
        self.build_tree_contents([('other-tree/foo/bar', 'baz')])
 
354
        other_tree.commit('changed bar')
 
355
        self.build_tree_contents([('this-tree/foo/bar', 'qux')])
 
356
        this_tree.commit('changed qux')
 
357
        this_tree.merge_from_branch(other_tree.branch)
 
358
        self.assertEqual(1, len(this_tree.conflicts()))
 
359
        this_tree.revert(['foo'])
 
360
        self.assertEqual(0, len(this_tree.conflicts()))
 
361
 
 
362
 
 
363
class TestAutoResolve(TestCaseWithTransport):
 
364
 
 
365
    def test_auto_resolve(self):
 
366
        base = self.make_branch_and_tree('base')
 
367
        self.build_tree_contents([('base/hello', 'Hello')])
 
368
        base.add('hello', 'hello_id')
 
369
        base.commit('Hello')
 
370
        other = base.bzrdir.sprout('other').open_workingtree()
 
371
        self.build_tree_contents([('other/hello', 'hELLO')])
 
372
        other.commit('Case switch')
 
373
        this = base.bzrdir.sprout('this').open_workingtree()
 
374
        self.failUnlessExists('this/hello')
 
375
        self.build_tree_contents([('this/hello', 'Hello World')])
 
376
        this.commit('Add World')
 
377
        this.merge_from_branch(other.branch)
 
378
        self.assertEqual([conflicts.TextConflict('hello', 'hello_id')],
 
379
                         this.conflicts())
 
380
        this.auto_resolve()
 
381
        self.assertEqual([conflicts.TextConflict('hello', 'hello_id')],
 
382
                         this.conflicts())
 
383
        self.build_tree_contents([('this/hello', '<<<<<<<')])
 
384
        this.auto_resolve()
 
385
        self.assertEqual([conflicts.TextConflict('hello', 'hello_id')],
 
386
                         this.conflicts())
 
387
        self.build_tree_contents([('this/hello', '=======')])
 
388
        this.auto_resolve()
 
389
        self.assertEqual([conflicts.TextConflict('hello', 'hello_id')],
 
390
                         this.conflicts())
 
391
        self.build_tree_contents([('this/hello', '\n>>>>>>>')])
 
392
        remaining, resolved = this.auto_resolve()
 
393
        self.assertEqual([conflicts.TextConflict('hello', 'hello_id')],
 
394
                         this.conflicts())
 
395
        self.assertEqual([], resolved)
 
396
        self.build_tree_contents([('this/hello', 'hELLO wORLD')])
 
397
        remaining, resolved = this.auto_resolve()
 
398
        self.assertEqual([], this.conflicts())
 
399
        self.assertEqual([conflicts.TextConflict('hello', 'hello_id')],
 
400
                         resolved)
 
401
        self.failIfExists('this/hello.BASE')
 
402
 
 
403
    def test_auto_resolve_dir(self):
 
404
        tree = self.make_branch_and_tree('tree')
 
405
        self.build_tree(['tree/hello/'])
 
406
        tree.add('hello', 'hello-id')
 
407
        file_conflict = conflicts.TextConflict('file', 'hello-id')
 
408
        tree.set_conflicts(conflicts.ConflictList([file_conflict]))
 
409
        tree.auto_resolve()
 
410
 
 
411
 
 
412
class TestFindTrees(TestCaseWithTransport):
 
413
 
 
414
    def test_find_trees(self):
 
415
        self.make_branch_and_tree('foo')
 
416
        self.make_branch_and_tree('foo/bar')
 
417
        # Sticking a tree inside a control dir is heinous, so let's skip it
 
418
        self.make_branch_and_tree('foo/.bzr/baz')
 
419
        self.make_branch('qux')
 
420
        trees = workingtree.WorkingTree.find_trees('.')
 
421
        self.assertEqual(2, len(list(trees)))