~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_workingtree.py

(vila) Fix test failures blocking package builds. (Vincent Ladeuil)

Show diffs side-by-side

added added

removed removed

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