/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: Robert Collins
  • Date: 2007-04-19 02:27:44 UTC
  • mto: This revision was merged to the branch mainline in revision 2426.
  • Revision ID: robertc@robertcollins.net-20070419022744-pfdqz42kp1wizh43
``make docs`` now creates a man page at ``man1/bzr.1`` fixing bug 107388.
(Robert Collins)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2012, 2016 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
17
 
18
 
from io import BytesIO
 
18
from cStringIO import StringIO
19
19
import os
20
20
 
21
 
from .. import (
 
21
from bzrlib import (
 
22
    bzrdir,
22
23
    conflicts,
23
24
    errors,
24
 
    symbol_versioning,
25
 
    trace,
26
 
    transport,
27
25
    workingtree,
28
26
    )
29
 
from ..bzr import (
30
 
    bzrdir,
31
 
    conflicts as _mod_bzr_conflicts,
32
 
    workingtree as bzrworkingtree,
33
 
    workingtree_3,
34
 
    workingtree_4,
35
 
    )
36
 
from ..lock import write_locked
37
 
from ..lockdir import LockDir
38
 
from . import TestCase, TestCaseWithTransport, TestSkipped
39
 
from ..tree import (
 
27
from bzrlib.branch import Branch
 
28
from bzrlib.bzrdir import BzrDir
 
29
from bzrlib.lockdir import LockDir
 
30
from bzrlib.mutabletree import needs_tree_write_lock
 
31
from bzrlib.symbol_versioning import zero_thirteen
 
32
from bzrlib.tests import TestCase, TestCaseWithTransport, TestSkipped
 
33
from bzrlib.transport import get_transport
 
34
from bzrlib.workingtree import (
40
35
    TreeEntry,
41
36
    TreeDirectory,
42
37
    TreeFile,
43
38
    TreeLink,
44
39
    )
45
40
 
46
 
from .features import SymlinkFeature
47
41
 
48
42
class TestTreeDirectory(TestCaseWithTransport):
49
43
 
72
66
class TestDefaultFormat(TestCaseWithTransport):
73
67
 
74
68
    def test_get_set_default_format(self):
75
 
        old_format = workingtree.format_registry.get_default()
76
 
        # default is 6
77
 
        self.assertTrue(isinstance(
78
 
            old_format, workingtree_4.WorkingTreeFormat6))
79
 
        workingtree.format_registry.set_default(SampleTreeFormat())
80
 
        try:
81
 
            # the default branch format is used by the meta dir format
82
 
            # which is not the default bzrdir format at this point
83
 
            dir = bzrdir.BzrDirMetaFormat1().initialize('.')
84
 
            dir.create_repository()
85
 
            dir.create_branch()
86
 
            result = dir.create_workingtree()
87
 
            self.assertEqual(result, 'A tree')
88
 
        finally:
89
 
            workingtree.format_registry.set_default(old_format)
90
 
        self.assertEqual(old_format, workingtree.format_registry.get_default())
91
 
 
92
 
    def test_from_string(self):
93
 
        self.assertIsInstance(
94
 
            SampleTreeFormat.from_string(b"Sample tree format."),
95
 
            SampleTreeFormat)
96
 
        self.assertRaises(
97
 
            AssertionError, SampleTreeFormat.from_string,
98
 
            b"Different format string.")
99
 
 
100
 
    def test_get_set_default_format_by_key(self):
101
 
        old_format = workingtree.format_registry.get_default()
102
 
        # default is 6
103
 
        format = SampleTreeFormat()
104
 
        workingtree.format_registry.register(format)
105
 
        self.addCleanup(workingtree.format_registry.remove, format)
106
 
        self.assertTrue(isinstance(
107
 
            old_format, workingtree_4.WorkingTreeFormat6))
108
 
        workingtree.format_registry.set_default_key(format.get_format_string())
109
 
        try:
110
 
            # the default branch format is used by the meta dir format
111
 
            # which is not the default bzrdir format at this point
112
 
            dir = bzrdir.BzrDirMetaFormat1().initialize('.')
113
 
            dir.create_repository()
114
 
            dir.create_branch()
115
 
            result = dir.create_workingtree()
116
 
            self.assertEqual(result, 'A tree')
117
 
        finally:
118
 
            workingtree.format_registry.set_default_key(
119
 
                old_format.get_format_string())
120
 
        self.assertEqual(old_format, workingtree.format_registry.get_default())
121
 
 
122
 
    def test_open(self):
123
 
        tree = self.make_branch_and_tree('.')
124
 
        open_direct = workingtree.WorkingTree.open('.')
125
 
        self.assertEqual(tree.basedir, open_direct.basedir)
126
 
        open_no_args = workingtree.WorkingTree.open()
127
 
        self.assertEqual(tree.basedir, open_no_args.basedir)
128
 
 
129
 
    def test_open_containing(self):
130
 
        tree = self.make_branch_and_tree('.')
131
 
        open_direct, relpath = workingtree.WorkingTree.open_containing('.')
132
 
        self.assertEqual(tree.basedir, open_direct.basedir)
133
 
        self.assertEqual('', relpath)
134
 
        open_no_args, relpath = workingtree.WorkingTree.open_containing()
135
 
        self.assertEqual(tree.basedir, open_no_args.basedir)
136
 
        self.assertEqual('', relpath)
137
 
        open_subdir, relpath = workingtree.WorkingTree.open_containing(
138
 
            'subdir')
139
 
        self.assertEqual(tree.basedir, open_subdir.basedir)
140
 
        self.assertEqual('subdir', relpath)
141
 
 
142
 
 
143
 
class SampleTreeFormat(bzrworkingtree.WorkingTreeFormatMetaDir):
 
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())
 
84
 
 
85
 
 
86
class SampleTreeFormat(workingtree.WorkingTreeFormat):
144
87
    """A sample format
145
88
 
146
 
    this format is initializable, unsupported to aid in testing the
 
89
    this format is initializable, unsupported to aid in testing the 
147
90
    open and open_downlevel routines.
148
91
    """
149
92
 
150
 
    @classmethod
151
 
    def get_format_string(cls):
 
93
    def get_format_string(self):
152
94
        """See WorkingTreeFormat.get_format_string()."""
153
 
        return b"Sample tree format."
 
95
        return "Sample tree format."
154
96
 
155
 
    def initialize(self, a_controldir, revision_id=None, from_branch=None,
156
 
                   accelerator_tree=None, hardlink=False):
 
97
    def initialize(self, a_bzrdir, revision_id=None):
157
98
        """Sample branches cannot be created."""
158
 
        t = a_controldir.get_workingtree_transport(self)
 
99
        t = a_bzrdir.get_workingtree_transport(self)
159
100
        t.put_bytes('format', self.get_format_string())
160
101
        return 'A tree'
161
102
 
166
107
        return "opened tree."
167
108
 
168
109
 
169
 
class SampleExtraTreeFormat(workingtree.WorkingTreeFormat):
170
 
    """A sample format that does not support use in a metadir.
171
 
 
172
 
    """
173
 
 
174
 
    def get_format_string(self):
175
 
        # Not usable in a metadir, so no format string
176
 
        return None
177
 
 
178
 
    def initialize(self, a_controldir, revision_id=None, from_branch=None,
179
 
                   accelerator_tree=None, hardlink=False):
180
 
        raise NotImplementedError(self.initialize)
181
 
 
182
 
    def is_supported(self):
183
 
        return False
184
 
 
185
 
    def open(self, transport, _found=False):
186
 
        raise NotImplementedError(self.open)
187
 
 
188
 
 
189
110
class TestWorkingTreeFormat(TestCaseWithTransport):
190
111
    """Tests for the WorkingTreeFormat facility."""
191
112
 
192
 
    def test_find_format_string(self):
193
 
        # is the right format object found for a working tree?
194
 
        branch = self.make_branch('branch')
195
 
        self.assertRaises(
196
 
            errors.NoWorkingTree,
197
 
            bzrworkingtree.WorkingTreeFormatMetaDir.find_format_string,
198
 
            branch.controldir)
199
 
        transport = branch.controldir.get_workingtree_transport(None)
200
 
        transport.mkdir('.')
201
 
        transport.put_bytes("format", b"some format name")
202
 
        # The format does not have to be known by Bazaar,
203
 
        # find_format_string just retrieves the name
204
 
        self.assertEqual(
205
 
            b"some format name",
206
 
            bzrworkingtree.WorkingTreeFormatMetaDir.find_format_string(
207
 
                branch.controldir))
208
 
 
209
113
    def test_find_format(self):
210
114
        # is the right format object found for a working tree?
211
115
        # create a branch with a few known format objects.
212
116
        self.build_tree(["foo/", "bar/"])
213
 
 
214
117
        def check_format(format, url):
215
 
            dir = format._matchingcontroldir.initialize(url)
 
118
            dir = format._matchingbzrdir.initialize(url)
216
119
            dir.create_repository()
217
120
            dir.create_branch()
218
121
            format.initialize(dir)
219
 
            found_format = bzrworkingtree.WorkingTreeFormatMetaDir.find_format(
220
 
                dir)
221
 
            self.assertIsInstance(found_format, format.__class__)
222
 
        check_format(workingtree_3.WorkingTreeFormat3(), "bar")
223
 
 
 
122
            t = get_transport(url)
 
123
            found_format = workingtree.WorkingTreeFormat.find_format(dir)
 
124
            self.failUnless(isinstance(found_format, format.__class__))
 
125
        check_format(workingtree.WorkingTreeFormat3(), "bar")
 
126
        
224
127
    def test_find_format_no_tree(self):
225
128
        dir = bzrdir.BzrDirMetaFormat1().initialize('.')
226
129
        self.assertRaises(errors.NoWorkingTree,
227
 
                          bzrworkingtree.WorkingTreeFormatMetaDir.find_format,
 
130
                          workingtree.WorkingTreeFormat.find_format,
228
131
                          dir)
229
132
 
230
133
    def test_find_format_unknown_format(self):
233
136
        dir.create_branch()
234
137
        SampleTreeFormat().initialize(dir)
235
138
        self.assertRaises(errors.UnknownFormatError,
236
 
                          bzrworkingtree.WorkingTreeFormatMetaDir.find_format,
 
139
                          workingtree.WorkingTreeFormat.find_format,
237
140
                          dir)
238
141
 
239
 
    def test_find_format_with_features(self):
240
 
        tree = self.make_branch_and_tree('.', format='2a')
241
 
        tree.update_feature_flags({b"name": b"necessity"})
242
 
        found_format = bzrworkingtree.WorkingTreeFormatMetaDir.find_format(
243
 
            tree.controldir)
244
 
        self.assertIsInstance(found_format, workingtree.WorkingTreeFormat)
245
 
        self.assertEqual(found_format.features.get(b"name"), b"necessity")
246
 
        self.assertRaises(
247
 
            bzrdir.MissingFeature, found_format.check_support_status, True)
248
 
        self.addCleanup(
249
 
            bzrworkingtree.WorkingTreeFormatMetaDir.unregister_feature,
250
 
            b"name")
251
 
        bzrworkingtree.WorkingTreeFormatMetaDir.register_feature(b"name")
252
 
        found_format.check_support_status(True)
253
 
 
254
 
 
255
 
class TestWorkingTreeIterEntriesByDir_wSubtrees(TestCaseWithTransport):
256
 
 
257
 
    def make_simple_tree(self):
258
 
        tree = self.make_branch_and_tree('tree', format='development-subtree')
259
 
        self.build_tree(['tree/a/', 'tree/a/b/', 'tree/a/b/c'])
260
 
        tree.set_root_id(b'root-id')
261
 
        tree.add(['a', 'a/b', 'a/b/c'], [b'a-id', b'b-id', b'c-id'])
262
 
        tree.commit('initial')
263
 
        return tree
264
 
 
265
 
    def test_just_directory(self):
266
 
        tree = self.make_simple_tree()
267
 
        self.assertEqual([('directory', b'root-id'),
268
 
                          ('directory', b'a-id'),
269
 
                          ('directory', b'b-id'),
270
 
                          ('file', b'c-id')],
271
 
                         [(ie.kind, ie.file_id)
272
 
                          for path, ie in tree.iter_entries_by_dir()])
273
 
        self.make_branch_and_tree('tree/a/b')
274
 
        self.assertEqual([('tree-reference', b'b-id')],
275
 
                         [(ie.kind, ie.file_id)
276
 
                          for path, ie in tree.iter_entries_by_dir(
277
 
                              specific_files=['a/b'])])
278
 
 
279
 
    def test_direct_subtree(self):
280
 
        tree = self.make_simple_tree()
281
 
        self.make_branch_and_tree('tree/a/b')
282
 
        self.assertEqual([('directory', b'root-id'),
283
 
                          ('directory', b'a-id'),
284
 
                          ('tree-reference', b'b-id')],
285
 
                         [(ie.kind, ie.file_id)
286
 
                          for path, ie in tree.iter_entries_by_dir()])
287
 
 
288
 
    def test_indirect_subtree(self):
289
 
        tree = self.make_simple_tree()
290
 
        self.make_branch_and_tree('tree/a')
291
 
        self.assertEqual([('directory', b'root-id'),
292
 
                          ('tree-reference', b'a-id')],
293
 
                         [(ie.kind, ie.file_id)
294
 
                          for path, ie in tree.iter_entries_by_dir()])
295
 
 
296
 
 
297
 
class TestWorkingTreeFormatRegistry(TestCase):
298
 
 
299
 
    def setUp(self):
300
 
        super(TestWorkingTreeFormatRegistry, self).setUp()
301
 
        self.registry = workingtree.WorkingTreeFormatRegistry()
302
 
 
303
142
    def test_register_unregister_format(self):
304
143
        format = SampleTreeFormat()
305
 
        self.registry.register(format)
306
 
        self.assertEqual(format, self.registry.get(b"Sample tree format."))
307
 
        self.registry.remove(format)
308
 
        self.assertRaises(KeyError, self.registry.get, b"Sample tree format.")
309
 
 
310
 
    def test_get_all(self):
311
 
        format = SampleTreeFormat()
312
 
        self.assertEqual([], self.registry._get_all())
313
 
        self.registry.register(format)
314
 
        self.assertEqual([format], self.registry._get_all())
315
 
 
316
 
    def test_register_extra(self):
317
 
        format = SampleExtraTreeFormat()
318
 
        self.assertEqual([], self.registry._get_all())
319
 
        self.registry.register_extra(format)
320
 
        self.assertEqual([format], self.registry._get_all())
321
 
 
322
 
    def test_register_extra_lazy(self):
323
 
        self.assertEqual([], self.registry._get_all())
324
 
        self.registry.register_extra_lazy("breezy.tests.test_workingtree",
325
 
                                          "SampleExtraTreeFormat")
326
 
        formats = self.registry._get_all()
327
 
        self.assertEqual(1, len(formats))
328
 
        self.assertIsInstance(formats[0], SampleExtraTreeFormat)
 
144
        # make a control dir
 
145
        dir = bzrdir.BzrDirMetaFormat1().initialize('.')
 
146
        dir.create_repository()
 
147
        dir.create_branch()
 
148
        # make a branch
 
149
        format.initialize(dir)
 
150
        # register a format for it.
 
151
        workingtree.WorkingTreeFormat.register_format(format)
 
152
        # which branch.Open will refuse (not supported)
 
153
        self.assertRaises(errors.UnsupportedFormatError, workingtree.WorkingTree.open, '.')
 
154
        # but open_downlevel will work
 
155
        self.assertEqual(format.open(dir), workingtree.WorkingTree.open_downlevel('.'))
 
156
        # unregister the format
 
157
        workingtree.WorkingTreeFormat.unregister_format(format)
329
158
 
330
159
 
331
160
class TestWorkingTreeFormat3(TestCaseWithTransport):
335
164
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
336
165
        control.create_repository()
337
166
        control.create_branch()
338
 
        workingtree_3.WorkingTreeFormat3().initialize(control)
 
167
        tree = workingtree.WorkingTreeFormat3().initialize(control)
339
168
        # we want:
340
169
        # format 'Bazaar-NG Working Tree format 3'
341
170
        # inventory = blank inventory
343
172
        # stat-cache = ??
344
173
        # no inventory.basis yet
345
174
        t = control.get_workingtree_transport(None)
346
 
        self.assertEqualDiff(b'Bazaar-NG Working Tree format 3',
 
175
        self.assertEqualDiff('Bazaar-NG Working Tree format 3',
347
176
                             t.get('format').read())
348
 
        self.assertEqualDiff(t.get('inventory').read(),
349
 
                             b'<inventory format="5">\n'
350
 
                             b'</inventory>\n',
 
177
        self.assertEqualDiff(t.get('inventory').read(), 
 
178
                              '<inventory format="5">\n'
 
179
                              '</inventory>\n',
351
180
                             )
352
 
        self.assertEqualDiff(b'### bzr hashcache v5\n',
 
181
        self.assertEqualDiff('### bzr hashcache v5\n',
353
182
                             t.get('stat-cache').read())
354
183
        self.assertFalse(t.has('inventory.basis'))
355
184
        # no last-revision file means 'None' or 'NULLREVISION'
356
185
        self.assertFalse(t.has('last-revision'))
357
 
        # 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 
358
187
        # correctly and last-revision file becomes present.
359
188
 
360
189
    def test_uses_lockdir(self):
361
190
        """WorkingTreeFormat3 uses its own LockDir:
362
 
 
 
191
            
363
192
            - lock is a directory
364
193
            - when the WorkingTree is locked, LockDir can see that
365
194
        """
366
195
        t = self.get_transport()
367
196
        url = self.get_url()
368
197
        dir = bzrdir.BzrDirMetaFormat1().initialize(url)
369
 
        dir.create_repository()
370
 
        dir.create_branch()
 
198
        repo = dir.create_repository()
 
199
        branch = dir.create_branch()
371
200
        try:
372
 
            tree = workingtree_3.WorkingTreeFormat3().initialize(dir)
 
201
            tree = workingtree.WorkingTreeFormat3().initialize(dir)
373
202
        except errors.NotLocalUrl:
374
203
            raise TestSkipped('Not a local URL')
375
204
        self.assertIsDirectory('.bzr', t)
376
205
        self.assertIsDirectory('.bzr/checkout', t)
377
206
        self.assertIsDirectory('.bzr/checkout/lock', t)
378
207
        our_lock = LockDir(t, '.bzr/checkout/lock')
379
 
        self.assertEqual(our_lock.peek(), None)
380
 
        with tree.lock_write():
381
 
            self.assertTrue(our_lock.peek())
382
 
        self.assertEqual(our_lock.peek(), None)
 
208
        self.assertEquals(our_lock.peek(), None)
 
209
        tree.lock_write()
 
210
        self.assertTrue(our_lock.peek())
 
211
        tree.unlock()
 
212
        self.assertEquals(our_lock.peek(), None)
383
213
 
384
214
    def test_missing_pending_merges(self):
385
215
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
386
216
        control.create_repository()
387
217
        control.create_branch()
388
 
        tree = workingtree_3.WorkingTreeFormat3().initialize(control)
389
 
        tree._transport.delete("pending-merges")
 
218
        tree = workingtree.WorkingTreeFormat3().initialize(control)
 
219
        tree._control_files._transport.delete("pending-merges")
390
220
        self.assertEqual([], tree.get_parent_ids())
391
221
 
392
222
 
393
 
class TestRevert(TestCaseWithTransport):
394
 
 
395
 
    def test_revert_conflicts_recursive(self):
396
 
        this_tree = self.make_branch_and_tree('this-tree')
397
 
        self.build_tree_contents([('this-tree/foo/',),
398
 
                                  ('this-tree/foo/bar', b'bar')])
399
 
        this_tree.add(['foo', 'foo/bar'])
400
 
        this_tree.commit('created foo/bar')
401
 
        other_tree = this_tree.controldir.sprout(
402
 
            'other-tree').open_workingtree()
403
 
        self.build_tree_contents([('other-tree/foo/bar', b'baz')])
404
 
        other_tree.commit('changed bar')
405
 
        self.build_tree_contents([('this-tree/foo/bar', b'qux')])
406
 
        this_tree.commit('changed qux')
407
 
        this_tree.merge_from_branch(other_tree.branch)
408
 
        self.assertEqual(1, len(this_tree.conflicts()))
409
 
        this_tree.revert(['foo'])
410
 
        self.assertEqual(0, len(this_tree.conflicts()))
 
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
 
 
266
class InstrumentedTree(object):
 
267
    """A instrumented tree to check the needs_tree_write_lock decorator."""
 
268
 
 
269
    def __init__(self):
 
270
        self._locks = []
 
271
 
 
272
    def lock_tree_write(self):
 
273
        self._locks.append('t')
 
274
 
 
275
    @needs_tree_write_lock
 
276
    def method_with_tree_write_lock(self, *args, **kwargs):
 
277
        """A lock_tree_write decorated method that returns its arguments."""
 
278
        return args, kwargs
 
279
 
 
280
    @needs_tree_write_lock
 
281
    def method_that_raises(self):
 
282
        """This method causes an exception when called with parameters.
 
283
        
 
284
        This allows the decorator code to be checked - it should still call
 
285
        unlock.
 
286
        """
 
287
 
 
288
    def unlock(self):
 
289
        self._locks.append('u')
 
290
 
 
291
 
 
292
class TestInstrumentedTree(TestCase):
 
293
 
 
294
    def test_needs_tree_write_lock(self):
 
295
        """@needs_tree_write_lock should be semantically transparent."""
 
296
        tree = InstrumentedTree()
 
297
        self.assertEqual(
 
298
            'method_with_tree_write_lock',
 
299
            tree.method_with_tree_write_lock.__name__)
 
300
        self.assertEqual(
 
301
            "A lock_tree_write decorated method that returns its arguments.",
 
302
            tree.method_with_tree_write_lock.__doc__)
 
303
        args = (1, 2, 3)
 
304
        kwargs = {'a':'b'}
 
305
        result = tree.method_with_tree_write_lock(1,2,3, a='b')
 
306
        self.assertEqual((args, kwargs), result)
 
307
        self.assertEqual(['t', 'u'], tree._locks)
 
308
        self.assertRaises(TypeError, tree.method_that_raises, 'foo')
 
309
        self.assertEqual(['t', 'u', 't', 'u'], tree._locks)
411
310
 
412
311
 
413
312
class TestAutoResolve(TestCaseWithTransport):
414
313
 
415
 
    def _auto_resolve(self, tree):
416
 
        """Call auto_resolve on tree expecting deprecation"""
417
 
        return self.applyDeprecated(
418
 
            symbol_versioning.deprecated_in((3, 0, 1)),
419
 
            tree.auto_resolve,)
420
 
 
421
314
    def test_auto_resolve(self):
422
315
        base = self.make_branch_and_tree('base')
423
 
        self.build_tree_contents([('base/hello', b'Hello')])
424
 
        base.add('hello', b'hello_id')
 
316
        self.build_tree_contents([('base/hello', 'Hello')])
 
317
        base.add('hello', 'hello_id')
425
318
        base.commit('Hello')
426
 
        other = base.controldir.sprout('other').open_workingtree()
427
 
        self.build_tree_contents([('other/hello', b'hELLO')])
 
319
        other = base.bzrdir.sprout('other').open_workingtree()
 
320
        self.build_tree_contents([('other/hello', 'hELLO')])
428
321
        other.commit('Case switch')
429
 
        this = base.controldir.sprout('this').open_workingtree()
430
 
        self.assertPathExists('this/hello')
431
 
        self.build_tree_contents([('this/hello', b'Hello World')])
 
322
        this = base.bzrdir.sprout('this').open_workingtree()
 
323
        self.failUnlessExists('this/hello')
 
324
        self.build_tree_contents([('this/hello', 'Hello World')])
432
325
        this.commit('Add World')
433
326
        this.merge_from_branch(other.branch)
434
 
        self.assertEqual([_mod_bzr_conflicts.TextConflict('hello', b'hello_id')],
 
327
        self.assertEqual([conflicts.TextConflict('hello', None, 'hello_id')],
435
328
                         this.conflicts())
436
 
        self._auto_resolve(this)
437
 
        self.assertEqual([_mod_bzr_conflicts.TextConflict('hello', b'hello_id')],
 
329
        this.auto_resolve()
 
330
        self.assertEqual([conflicts.TextConflict('hello', None, 'hello_id')],
438
331
                         this.conflicts())
439
332
        self.build_tree_contents([('this/hello', '<<<<<<<')])
440
 
        self._auto_resolve(this)
441
 
        self.assertEqual([_mod_bzr_conflicts.TextConflict('hello', b'hello_id')],
 
333
        this.auto_resolve()
 
334
        self.assertEqual([conflicts.TextConflict('hello', None, 'hello_id')],
442
335
                         this.conflicts())
443
336
        self.build_tree_contents([('this/hello', '=======')])
444
 
        self._auto_resolve(this)
445
 
        self.assertEqual([_mod_bzr_conflicts.TextConflict('hello', b'hello_id')],
 
337
        this.auto_resolve()
 
338
        self.assertEqual([conflicts.TextConflict('hello', None, 'hello_id')],
446
339
                         this.conflicts())
447
340
        self.build_tree_contents([('this/hello', '\n>>>>>>>')])
448
 
        remaining, resolved = self._auto_resolve(this)
449
 
        self.assertEqual([_mod_bzr_conflicts.TextConflict('hello', b'hello_id')],
 
341
        remaining, resolved = this.auto_resolve()
 
342
        self.assertEqual([conflicts.TextConflict('hello', None, 'hello_id')],
450
343
                         this.conflicts())
451
344
        self.assertEqual([], resolved)
452
 
        self.build_tree_contents([('this/hello', b'hELLO wORLD')])
453
 
        remaining, resolved = self._auto_resolve(this)
 
345
        self.build_tree_contents([('this/hello', 'hELLO wORLD')])
 
346
        remaining, resolved = this.auto_resolve()
454
347
        self.assertEqual([], this.conflicts())
455
 
        self.assertEqual([_mod_bzr_conflicts.TextConflict('hello', b'hello_id')],
 
348
        self.assertEqual([conflicts.TextConflict('hello', None, 'hello_id')],
456
349
                         resolved)
457
 
        self.assertPathDoesNotExist('this/hello.BASE')
458
 
 
459
 
    def test_unsupported_symlink_auto_resolve(self):
460
 
        self.requireFeature(SymlinkFeature)
461
 
        base = self.make_branch_and_tree('base')
462
 
        self.build_tree_contents([('base/hello', 'Hello')])
463
 
        base.add('hello', b'hello_id')
464
 
        base.commit('commit 0')
465
 
        other = base.controldir.sprout('other').open_workingtree()
466
 
        self.build_tree_contents([('other/hello', 'Hello')])
467
 
        os.symlink('other/hello', 'other/foo')
468
 
        other.add('foo', b'foo_id')
469
 
        other.commit('commit symlink')
470
 
        this = base.controldir.sprout('this').open_workingtree()
471
 
        self.assertPathExists('this/hello')
472
 
        self.build_tree_contents([('this/hello', 'Hello')])
473
 
        this.commit('commit 2')
474
 
        log = BytesIO()
475
 
        trace.push_log_file(log)
476
 
        os_symlink = getattr(os, 'symlink', None)
477
 
        os.symlink = None
478
 
        try:
479
 
            this.merge_from_branch(other.branch)
480
 
        finally:
481
 
            if os_symlink:
482
 
                os.symlink = os_symlink
483
 
        self.assertContainsRe(
484
 
            log.getvalue(),
485
 
            b'Unable to create symlink "foo" on this filesystem')
 
350
        self.failIfExists('this/hello.BASE')
486
351
 
487
352
    def test_auto_resolve_dir(self):
488
353
        tree = self.make_branch_and_tree('tree')
489
354
        self.build_tree(['tree/hello/'])
490
 
        tree.add('hello', b'hello-id')
491
 
        file_conflict = _mod_bzr_conflicts.TextConflict('hello', b'hello-id')
492
 
        tree.set_conflicts([file_conflict])
493
 
        remaining, resolved = self._auto_resolve(tree)
494
 
        self.assertEqual(
495
 
            remaining,
496
 
            conflicts.ConflictList([_mod_bzr_conflicts.TextConflict(u'hello', 'hello-id')]))
497
 
        self.assertEqual(resolved, [])
498
 
 
499
 
    def test_auto_resolve_missing(self):
500
 
        tree = self.make_branch_and_tree('tree')
501
 
        file_conflict = _mod_bzr_conflicts.TextConflict('hello', b'hello-id')
502
 
        tree.set_conflicts([file_conflict])
503
 
        remaining, resolved = self._auto_resolve(tree)
504
 
        self.assertEqual(remaining, [])
505
 
        self.assertEqual(
506
 
            resolved,
507
 
            conflicts.ConflictList([_mod_bzr_conflicts.TextConflict(u'hello', 'hello-id')]))
508
 
 
509
 
 
510
 
class TestStoredUncommitted(TestCaseWithTransport):
511
 
 
512
 
    def store_uncommitted(self):
513
 
        tree = self.make_branch_and_tree('tree')
514
 
        tree.commit('get root in there')
515
 
        self.build_tree_contents([('tree/file', b'content')])
516
 
        tree.add('file', b'file-id')
517
 
        tree.store_uncommitted()
518
 
        return tree
519
 
 
520
 
    def test_store_uncommitted(self):
521
 
        self.store_uncommitted()
522
 
        self.assertPathDoesNotExist('tree/file')
523
 
 
524
 
    def test_store_uncommitted_no_change(self):
525
 
        tree = self.make_branch_and_tree('tree')
526
 
        tree.commit('get root in there')
527
 
        tree.store_uncommitted()
528
 
        self.assertIs(None, tree.branch.get_unshelver(tree))
529
 
 
530
 
    def test_restore_uncommitted(self):
531
 
        with write_locked(self.store_uncommitted()) as tree:
532
 
            tree.restore_uncommitted()
533
 
            self.assertPathExists('tree/file')
534
 
            self.assertIs(None, tree.branch.get_unshelver(tree))
535
 
 
536
 
    def test_restore_uncommitted_none(self):
537
 
        tree = self.make_branch_and_tree('tree')
538
 
        tree.restore_uncommitted()
 
355
        tree.add('hello', 'hello-id')
 
356
        file_conflict = conflicts.TextConflict('file', None, 'hello-id')
 
357
        tree.set_conflicts(conflicts.ConflictList([file_conflict]))
 
358
        tree.auto_resolve()