~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_workingtree.py

  • Committer: Patch Queue Manager
  • Date: 2013-05-23 10:35:23 UTC
  • mfrom: (6574.1.1 integration)
  • Revision ID: pqm@pqm.ubuntu.com-20130523103523-2wt6jmauja1n1vdt
(jameinel) Merge bzr/2.5 into trunk. (John A Meinel)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006 Canonical Ltd
 
1
# Copyright (C) 2005-2011 Canonical Ltd
2
2
# Authors:  Robert Collins <robert.collins@canonical.com>
3
3
#
4
4
# This program is free software; you can redistribute it and/or modify
13
13
#
14
14
# You should have received a copy of the GNU General Public License
15
15
# along with this program; if not, write to the Free Software
16
 
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17
 
 
18
 
from cStringIO import StringIO
19
 
import os
20
 
 
21
 
import bzrlib
22
 
from bzrlib.branch import Branch
23
 
from bzrlib import bzrdir, conflicts, errors, workingtree
24
 
from bzrlib.bzrdir import BzrDir
25
 
from bzrlib.errors import NotBranchError, NotVersionedError
 
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
26
28
from bzrlib.lockdir import LockDir
27
 
from bzrlib.osutils import pathjoin, getcwd, has_symlinks
28
 
from bzrlib.tests import TestCaseWithTransport, TestSkipped
29
 
from bzrlib.trace import mutter
30
 
from bzrlib.transport import get_transport
31
 
from bzrlib.workingtree import (TreeEntry, TreeDirectory, TreeFile, TreeLink,
32
 
                                WorkingTree)
 
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
 
33
38
 
34
39
class TestTreeDirectory(TestCaseWithTransport):
35
40
 
58
63
class TestDefaultFormat(TestCaseWithTransport):
59
64
 
60
65
    def test_get_set_default_format(self):
61
 
        old_format = workingtree.WorkingTreeFormat.get_default_format()
62
 
        # default is 3
63
 
        self.assertTrue(isinstance(old_format, workingtree.WorkingTreeFormat3))
64
 
        workingtree.WorkingTreeFormat.set_default_format(SampleTreeFormat())
65
 
        try:
66
 
            # the default branch format is used by the meta dir format
67
 
            # which is not the default bzrdir format at this point
68
 
            dir = bzrdir.BzrDirMetaFormat1().initialize('.')
69
 
            dir.create_repository()
70
 
            dir.create_branch()
71
 
            result = dir.create_workingtree()
72
 
            self.assertEqual(result, 'A tree')
73
 
        finally:
74
 
            workingtree.WorkingTreeFormat.set_default_format(old_format)
75
 
        self.assertEqual(old_format, workingtree.WorkingTreeFormat.get_default_format())
76
 
 
77
 
 
78
 
class SampleTreeFormat(workingtree.WorkingTreeFormat):
 
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)
 
116
 
 
117
    def test_open_containing(self):
 
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):
79
131
    """A sample format
80
132
 
81
 
    this format is initializable, unsupported to aid in testing the 
 
133
    this format is initializable, unsupported to aid in testing the
82
134
    open and open_downlevel routines.
83
135
    """
84
136
 
85
 
    def get_format_string(self):
 
137
    @classmethod
 
138
    def get_format_string(cls):
86
139
        """See WorkingTreeFormat.get_format_string()."""
87
140
        return "Sample tree format."
88
141
 
89
 
    def initialize(self, a_bzrdir, revision_id=None):
 
142
    def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
 
143
                   accelerator_tree=None, hardlink=False):
90
144
        """Sample branches cannot be created."""
91
145
        t = a_bzrdir.get_workingtree_transport(self)
92
 
        t.put('format', StringIO(self.get_format_string()))
 
146
        t.put_bytes('format', self.get_format_string())
93
147
        return 'A tree'
94
148
 
95
149
    def is_supported(self):
99
153
        return "opened tree."
100
154
 
101
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
 
102
176
class TestWorkingTreeFormat(TestCaseWithTransport):
103
177
    """Tests for the WorkingTreeFormat facility."""
104
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
 
105
192
    def test_find_format(self):
106
193
        # is the right format object found for a working tree?
107
194
        # create a branch with a few known format objects.
111
198
            dir.create_repository()
112
199
            dir.create_branch()
113
200
            format.initialize(dir)
114
 
            t = get_transport(url)
115
 
            found_format = workingtree.WorkingTreeFormat.find_format(dir)
116
 
            self.failUnless(isinstance(found_format, format.__class__))
117
 
        check_format(workingtree.WorkingTreeFormat3(), "bar")
118
 
        
 
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
 
119
206
    def test_find_format_no_tree(self):
120
207
        dir = bzrdir.BzrDirMetaFormat1().initialize('.')
121
208
        self.assertRaises(errors.NoWorkingTree,
122
 
                          workingtree.WorkingTreeFormat.find_format,
 
209
                          workingtree.WorkingTreeFormatMetaDir.find_format,
123
210
                          dir)
124
211
 
125
212
    def test_find_format_unknown_format(self):
128
215
        dir.create_branch()
129
216
        SampleTreeFormat().initialize(dir)
130
217
        self.assertRaises(errors.UnknownFormatError,
131
 
                          workingtree.WorkingTreeFormat.find_format,
 
218
                          workingtree.WorkingTreeFormatMetaDir.find_format,
132
219
                          dir)
133
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
 
134
283
    def test_register_unregister_format(self):
135
284
        format = SampleTreeFormat()
136
 
        # make a control dir
137
 
        dir = bzrdir.BzrDirMetaFormat1().initialize('.')
138
 
        dir.create_repository()
139
 
        dir.create_branch()
140
 
        # make a branch
141
 
        format.initialize(dir)
142
 
        # register a format for it.
143
 
        workingtree.WorkingTreeFormat.register_format(format)
144
 
        # which branch.Open will refuse (not supported)
145
 
        self.assertRaises(errors.UnsupportedFormatError, workingtree.WorkingTree.open, '.')
146
 
        # but open_downlevel will work
147
 
        self.assertEqual(format.open(dir), workingtree.WorkingTree.open_downlevel('.'))
148
 
        # unregister the format
149
 
        workingtree.WorkingTreeFormat.unregister_format(format)
 
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)
150
309
 
151
310
 
152
311
class TestWorkingTreeFormat3(TestCaseWithTransport):
156
315
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
157
316
        control.create_repository()
158
317
        control.create_branch()
159
 
        tree = workingtree.WorkingTreeFormat3().initialize(control)
 
318
        tree = workingtree_3.WorkingTreeFormat3().initialize(control)
160
319
        # we want:
161
320
        # format 'Bazaar-NG Working Tree format 3'
162
321
        # inventory = blank inventory
166
325
        t = control.get_workingtree_transport(None)
167
326
        self.assertEqualDiff('Bazaar-NG Working Tree format 3',
168
327
                             t.get('format').read())
169
 
        self.assertEqualDiff('<inventory format="5">\n'
170
 
                             '</inventory>\n',
171
 
                             t.get('inventory').read())
 
328
        self.assertEqualDiff(t.get('inventory').read(),
 
329
                              '<inventory format="5">\n'
 
330
                              '</inventory>\n',
 
331
                             )
172
332
        self.assertEqualDiff('### bzr hashcache v5\n',
173
333
                             t.get('stat-cache').read())
174
334
        self.assertFalse(t.has('inventory.basis'))
175
335
        # no last-revision file means 'None' or 'NULLREVISION'
176
336
        self.assertFalse(t.has('last-revision'))
177
 
        # TODO RBC 20060210 do a commit, check the inventory.basis is created 
 
337
        # TODO RBC 20060210 do a commit, check the inventory.basis is created
178
338
        # correctly and last-revision file becomes present.
179
339
 
180
340
    def test_uses_lockdir(self):
181
341
        """WorkingTreeFormat3 uses its own LockDir:
182
 
            
 
342
 
183
343
            - lock is a directory
184
344
            - when the WorkingTree is locked, LockDir can see that
185
345
        """
189
349
        repo = dir.create_repository()
190
350
        branch = dir.create_branch()
191
351
        try:
192
 
            tree = workingtree.WorkingTreeFormat3().initialize(dir)
 
352
            tree = workingtree_3.WorkingTreeFormat3().initialize(dir)
193
353
        except errors.NotLocalUrl:
194
354
            raise TestSkipped('Not a local URL')
195
355
        self.assertIsDirectory('.bzr', t)
206
366
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
207
367
        control.create_repository()
208
368
        control.create_branch()
209
 
        tree = workingtree.WorkingTreeFormat3().initialize(control)
210
 
        tree._control_files._transport.delete("pending-merges")
211
 
        self.assertEqual([], tree.pending_merges())
212
 
 
213
 
 
214
 
class TestFormat2WorkingTree(TestCaseWithTransport):
215
 
    """Tests that are specific to format 2 trees."""
216
 
 
217
 
    def create_format2_tree(self, url):
218
 
        return self.make_branch_and_tree(
219
 
            url, format=bzrlib.bzrdir.BzrDirFormat6())
220
 
 
221
 
    def test_conflicts(self):
222
 
        # test backwards compatability
223
 
        tree = self.create_format2_tree('.')
224
 
        self.assertRaises(errors.UnsupportedOperation, tree.set_conflicts,
225
 
                          None)
226
 
        file('lala.BASE', 'wb').write('labase')
227
 
        expected = conflicts.ContentsConflict('lala')
228
 
        self.assertEqual(list(tree.conflicts()), [expected])
229
 
        file('lala', 'wb').write('la')
230
 
        tree.add('lala', 'lala-id')
231
 
        expected = conflicts.ContentsConflict('lala', file_id='lala-id')
232
 
        self.assertEqual(list(tree.conflicts()), [expected])
233
 
        file('lala.THIS', 'wb').write('lathis')
234
 
        file('lala.OTHER', 'wb').write('laother')
235
 
        # When "text conflict"s happen, stem, THIS and OTHER are text
236
 
        expected = conflicts.TextConflict('lala', file_id='lala-id')
237
 
        self.assertEqual(list(tree.conflicts()), [expected])
238
 
        os.unlink('lala.OTHER')
239
 
        os.mkdir('lala.OTHER')
240
 
        expected = conflicts.ContentsConflict('lala', file_id='lala-id')
241
 
        self.assertEqual(list(tree.conflicts()), [expected])
242
 
 
243
 
 
244
 
class TestNonFormatSpecificCode(TestCaseWithTransport):
245
 
    """This class contains tests of workingtree that are not format specific."""
246
 
 
247
 
    
248
 
    def test_gen_file_id(self):
249
 
        self.assertStartsWith(bzrlib.workingtree.gen_file_id('bar'), 'bar-')
250
 
        self.assertStartsWith(bzrlib.workingtree.gen_file_id('Mwoo oof\t m'), 'Mwoooofm-')
251
 
        self.assertStartsWith(bzrlib.workingtree.gen_file_id('..gam.py'), 'gam.py-')
252
 
        self.assertStartsWith(bzrlib.workingtree.gen_file_id('..Mwoo oof\t m'), 'Mwoooofm-')
253
 
 
254
 
    def test_next_id_suffix(self):
255
 
        bzrlib.workingtree._gen_id_suffix = None
256
 
        bzrlib.workingtree._next_id_suffix()
257
 
        self.assertNotEqual(None, bzrlib.workingtree._gen_id_suffix)
258
 
        bzrlib.workingtree._gen_id_suffix = "foo-"
259
 
        bzrlib.workingtree._gen_id_serial = 1
260
 
        self.assertEqual("foo-2", bzrlib.workingtree._next_id_suffix())
261
 
        self.assertEqual("foo-3", bzrlib.workingtree._next_id_suffix())
262
 
        self.assertEqual("foo-4", bzrlib.workingtree._next_id_suffix())
263
 
        self.assertEqual("foo-5", bzrlib.workingtree._next_id_suffix())
264
 
        self.assertEqual("foo-6", bzrlib.workingtree._next_id_suffix())
265
 
        self.assertEqual("foo-7", bzrlib.workingtree._next_id_suffix())
266
 
        self.assertEqual("foo-8", bzrlib.workingtree._next_id_suffix())
267
 
        self.assertEqual("foo-9", bzrlib.workingtree._next_id_suffix())
268
 
        self.assertEqual("foo-10", bzrlib.workingtree._next_id_suffix())
269
 
 
270
 
    def test__translate_ignore_rule(self):
271
 
        tree = self.make_branch_and_tree('.')
272
 
        # translation should return the regex, the number of groups in it,
273
 
        # and the original rule in a tuple.
274
 
        # there are three sorts of ignore rules:
275
 
        # root only - regex is the rule itself without the leading ./
276
 
        self.assertEqual(
277
 
            "(rootdirrule$)", 
278
 
            tree._translate_ignore_rule("./rootdirrule"))
279
 
        # full path - regex is the rule itself
280
 
        self.assertEqual(
281
 
            "(path\\/to\\/file$)",
282
 
            tree._translate_ignore_rule("path/to/file"))
283
 
        # basename only rule - regex is a rule that ignores everything up
284
 
        # to the last / in the filename
285
 
        self.assertEqual(
286
 
            "((?:.*/)?(?!.*/)basenamerule$)",
287
 
            tree._translate_ignore_rule("basenamerule"))
288
 
 
289
 
    def test__combine_ignore_rules(self):
290
 
        tree = self.make_branch_and_tree('.')
291
 
        # the combined ignore regexs need the outer group indices
292
 
        # placed in a dictionary with the rules that were combined.
293
 
        # an empty set of rules
294
 
        # this is returned as a list of combined regex,rule sets, because
295
 
        # python has a limit of 100 combined regexes.
296
 
        compiled_rules = tree._combine_ignore_rules([])
297
 
        self.assertEqual([], compiled_rules)
298
 
        # one of each type of rule.
299
 
        compiled_rules = tree._combine_ignore_rules(
300
 
            ["rule1", "rule/two", "./three"])[0]
301
 
        # what type *is* the compiled regex to do an isinstance of ?
302
 
        self.assertEqual(3, compiled_rules[0].groups)
303
 
        self.assertEqual(
304
 
            {0:"rule1",1:"rule/two",2:"./three"},
305
 
            compiled_rules[1])
306
 
 
307
 
    def test__combine_ignore_rules_grouping(self):
308
 
        tree = self.make_branch_and_tree('.')
309
 
        # when there are too many rules, the output is split into groups of 100
310
 
        rules = []
311
 
        for index in range(198):
312
 
            rules.append('foo')
313
 
        self.assertEqual(2, len(tree._combine_ignore_rules(rules)))
314
 
 
315
 
    def test__get_ignore_rules_as_regex(self):
316
 
        tree = self.make_branch_and_tree('.')
317
 
        self.build_tree_contents([('.bzrignore', 'CVS\n.hg\n')])
318
 
        reference_output = tree._combine_ignore_rules(['CVS', '.hg'])[0]
319
 
        regex_rules = tree._get_ignore_rules_as_regex()[0]
320
 
        self.assertEqual(len(reference_output[1]), regex_rules[0].groups)
321
 
        self.assertEqual(reference_output[1], regex_rules[1])
 
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()