~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_workingtree.py

Various hopefully improvements, but wsgi is broken, handing over to spiv :).

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2011 Canonical Ltd
 
1
# Copyright (C) 2005, 2006 Canonical Ltd
2
2
# Authors:  Robert Collins <robert.collins@canonical.com>
3
3
#
4
4
# This program is free software; you can redistribute it and/or modify
13
13
#
14
14
# You should have received a copy of the GNU General Public License
15
15
# along with this program; if not, write to the Free Software
16
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
 
 
18
 
from bzrlib import (
19
 
    bzrdir,
20
 
    conflicts,
21
 
    errors,
22
 
    symbol_versioning,
23
 
    transport,
24
 
    workingtree,
25
 
    workingtree_3,
26
 
    workingtree_4,
27
 
    )
 
16
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
17
 
 
18
from cStringIO import StringIO
 
19
import os
 
20
 
 
21
from bzrlib import ignores
 
22
import bzrlib
 
23
from bzrlib.branch import Branch
 
24
from bzrlib import bzrdir, conflicts, errors, workingtree
 
25
from bzrlib.bzrdir import BzrDir
 
26
from bzrlib.errors import NotBranchError, NotVersionedError
28
27
from bzrlib.lockdir import LockDir
29
28
from bzrlib.mutabletree import needs_tree_write_lock
 
29
from bzrlib.osutils import pathjoin, getcwd, has_symlinks
 
30
from bzrlib.symbol_versioning import zero_thirteen
30
31
from bzrlib.tests import TestCase, TestCaseWithTransport, TestSkipped
 
32
from bzrlib.trace import mutter
 
33
from bzrlib.transport import get_transport
31
34
from bzrlib.workingtree import (
32
35
    TreeEntry,
33
36
    TreeDirectory,
34
37
    TreeFile,
35
38
    TreeLink,
 
39
    WorkingTree,
36
40
    )
37
41
 
38
 
 
39
42
class TestTreeDirectory(TestCaseWithTransport):
40
43
 
41
44
    def test_kind_character(self):
63
66
class TestDefaultFormat(TestCaseWithTransport):
64
67
 
65
68
    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_get_set_default_format_by_key(self):
83
 
        old_format = workingtree.format_registry.get_default()
84
 
        # default is 6
85
 
        format = SampleTreeFormat()
86
 
        workingtree.format_registry.register(format)
87
 
        self.addCleanup(workingtree.format_registry.remove, format)
88
 
        self.assertTrue(isinstance(old_format, workingtree_4.WorkingTreeFormat6))
89
 
        workingtree.format_registry.set_default_key(format.get_format_string())
90
 
        try:
91
 
            # the default branch format is used by the meta dir format
92
 
            # which is not the default bzrdir format at this point
93
 
            dir = bzrdir.BzrDirMetaFormat1().initialize('.')
94
 
            dir.create_repository()
95
 
            dir.create_branch()
96
 
            result = dir.create_workingtree()
97
 
            self.assertEqual(result, 'A tree')
98
 
        finally:
99
 
            workingtree.format_registry.set_default_key(
100
 
                old_format.get_format_string())
101
 
        self.assertEqual(old_format, workingtree.format_registry.get_default())
102
 
 
103
 
    def test_open(self):
104
 
        tree = self.make_branch_and_tree('.')
105
 
        open_direct = workingtree.WorkingTree.open('.')
106
 
        self.assertEqual(tree.basedir, open_direct.basedir)
107
 
        open_no_args = workingtree.WorkingTree.open()
108
 
        self.assertEqual(tree.basedir, open_no_args.basedir)
109
 
 
110
 
    def test_open_containing(self):
111
 
        tree = self.make_branch_and_tree('.')
112
 
        open_direct, relpath = workingtree.WorkingTree.open_containing('.')
113
 
        self.assertEqual(tree.basedir, open_direct.basedir)
114
 
        self.assertEqual('', relpath)
115
 
        open_no_args, relpath = workingtree.WorkingTree.open_containing()
116
 
        self.assertEqual(tree.basedir, open_no_args.basedir)
117
 
        self.assertEqual('', relpath)
118
 
        open_subdir, relpath = workingtree.WorkingTree.open_containing('subdir')
119
 
        self.assertEqual(tree.basedir, open_subdir.basedir)
120
 
        self.assertEqual('subdir', relpath)
 
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())
121
84
 
122
85
 
123
86
class SampleTreeFormat(workingtree.WorkingTreeFormat):
124
87
    """A sample format
125
88
 
126
 
    this format is initializable, unsupported to aid in testing the
 
89
    this format is initializable, unsupported to aid in testing the 
127
90
    open and open_downlevel routines.
128
91
    """
129
92
 
131
94
        """See WorkingTreeFormat.get_format_string()."""
132
95
        return "Sample tree format."
133
96
 
134
 
    def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
135
 
                   accelerator_tree=None, hardlink=False):
 
97
    def initialize(self, a_bzrdir, revision_id=None):
136
98
        """Sample branches cannot be created."""
137
99
        t = a_bzrdir.get_workingtree_transport(self)
138
100
        t.put_bytes('format', self.get_format_string())
145
107
        return "opened tree."
146
108
 
147
109
 
148
 
class SampleExtraTreeFormat(workingtree.WorkingTreeFormat):
149
 
    """A sample format that does not support use in a metadir.
150
 
 
151
 
    """
152
 
 
153
 
    def get_format_string(self):
154
 
        # Not usable in a metadir, so no format string
155
 
        return None
156
 
 
157
 
    def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
158
 
                   accelerator_tree=None, hardlink=False):
159
 
        raise NotImplementedError(self.initialize)
160
 
 
161
 
    def is_supported(self):
162
 
        return False
163
 
 
164
 
    def open(self, transport, _found=False):
165
 
        raise NotImplementedError(self.open)
166
 
 
167
 
 
168
110
class TestWorkingTreeFormat(TestCaseWithTransport):
169
111
    """Tests for the WorkingTreeFormat facility."""
170
112
 
171
 
    def test_find_format_string(self):
172
 
        # is the right format object found for a working tree?
173
 
        branch = self.make_branch('branch')
174
 
        self.assertRaises(errors.NoWorkingTree,
175
 
            workingtree.WorkingTreeFormat.find_format_string, branch.bzrdir)
176
 
        transport = branch.bzrdir.get_workingtree_transport(None)
177
 
        transport.mkdir('.')
178
 
        transport.put_bytes("format", "some format name")
179
 
        # The format does not have to be known by Bazaar,
180
 
        # find_format_string just retrieves the name
181
 
        self.assertEquals("some format name",
182
 
            workingtree.WorkingTreeFormat.find_format_string(branch.bzrdir))
183
 
 
184
113
    def test_find_format(self):
185
114
        # is the right format object found for a working tree?
186
115
        # create a branch with a few known format objects.
190
119
            dir.create_repository()
191
120
            dir.create_branch()
192
121
            format.initialize(dir)
193
 
            t = transport.get_transport(url)
 
122
            t = get_transport(url)
194
123
            found_format = workingtree.WorkingTreeFormat.find_format(dir)
195
 
            self.assertIsInstance(found_format, format.__class__)
196
 
        check_format(workingtree_3.WorkingTreeFormat3(), "bar")
197
 
 
 
124
            self.failUnless(isinstance(found_format, format.__class__))
 
125
        check_format(workingtree.WorkingTreeFormat3(), "bar")
 
126
        
198
127
    def test_find_format_no_tree(self):
199
128
        dir = bzrdir.BzrDirMetaFormat1().initialize('.')
200
129
        self.assertRaises(errors.NoWorkingTree,
219
148
        # make a branch
220
149
        format.initialize(dir)
221
150
        # register a format for it.
222
 
        self.applyDeprecated(symbol_versioning.deprecated_in((2, 4, 0)),
223
 
            workingtree.WorkingTreeFormat.register_format, format)
224
 
        self.assertTrue(format in 
225
 
            self.applyDeprecated(symbol_versioning.deprecated_in((2, 4, 0)),
226
 
                workingtree.WorkingTreeFormat.get_formats))
 
151
        workingtree.WorkingTreeFormat.register_format(format)
227
152
        # which branch.Open will refuse (not supported)
228
153
        self.assertRaises(errors.UnsupportedFormatError, workingtree.WorkingTree.open, '.')
229
154
        # but open_downlevel will work
230
155
        self.assertEqual(format.open(dir), workingtree.WorkingTree.open_downlevel('.'))
231
156
        # unregister the format
232
 
        self.applyDeprecated(symbol_versioning.deprecated_in((2, 4, 0)),
233
 
            workingtree.WorkingTreeFormat.unregister_format, format)
234
 
        self.assertFalse(format in
235
 
            self.applyDeprecated(symbol_versioning.deprecated_in((2, 4, 0)),
236
 
                workingtree.WorkingTreeFormat.get_formats))
237
 
 
238
 
 
239
 
class TestWorkingTreeIterEntriesByDir_wSubtrees(TestCaseWithTransport):
240
 
 
241
 
    def make_simple_tree(self):
242
 
        tree = self.make_branch_and_tree('tree', format='development-subtree')
243
 
        self.build_tree(['tree/a/', 'tree/a/b/', 'tree/a/b/c'])
244
 
        tree.set_root_id('root-id')
245
 
        tree.add(['a', 'a/b', 'a/b/c'], ['a-id', 'b-id', 'c-id'])
246
 
        tree.commit('initial')
247
 
        return tree
248
 
 
249
 
    def test_just_directory(self):
250
 
        tree = self.make_simple_tree()
251
 
        self.assertEqual([('directory', 'root-id'),
252
 
                          ('directory', 'a-id'),
253
 
                          ('directory', 'b-id'),
254
 
                          ('file', 'c-id')],
255
 
                         [(ie.kind, ie.file_id)
256
 
                          for path, ie in tree.iter_entries_by_dir()])
257
 
        subtree = self.make_branch_and_tree('tree/a/b')
258
 
        self.assertEqual([('tree-reference', 'b-id')],
259
 
                         [(ie.kind, ie.file_id)
260
 
                          for path, ie in tree.iter_entries_by_dir(['b-id'])])
261
 
 
262
 
    def test_direct_subtree(self):
263
 
        tree = self.make_simple_tree()
264
 
        subtree = self.make_branch_and_tree('tree/a/b')
265
 
        self.assertEqual([('directory', 'root-id'),
266
 
                          ('directory', 'a-id'),
267
 
                          ('tree-reference', 'b-id')],
268
 
                         [(ie.kind, ie.file_id)
269
 
                          for path, ie in tree.iter_entries_by_dir()])
270
 
 
271
 
    def test_indirect_subtree(self):
272
 
        tree = self.make_simple_tree()
273
 
        subtree = self.make_branch_and_tree('tree/a')
274
 
        self.assertEqual([('directory', 'root-id'),
275
 
                          ('tree-reference', 'a-id')],
276
 
                         [(ie.kind, ie.file_id)
277
 
                          for path, ie in tree.iter_entries_by_dir()])
278
 
 
279
 
 
280
 
class TestWorkingTreeFormatRegistry(TestCase):
281
 
 
282
 
    def setUp(self):
283
 
        super(TestWorkingTreeFormatRegistry, self).setUp()
284
 
        self.registry = workingtree.WorkingTreeFormatRegistry()
285
 
 
286
 
    def test_register_unregister_format(self):
287
 
        format = SampleTreeFormat()
288
 
        self.registry.register(format)
289
 
        self.assertEquals(format, self.registry.get("Sample tree format."))
290
 
        self.registry.remove(format)
291
 
        self.assertRaises(KeyError, self.registry.get, "Sample tree format.")
292
 
 
293
 
    def test_get_all(self):
294
 
        format = SampleTreeFormat()
295
 
        self.assertEquals([], self.registry._get_all())
296
 
        self.registry.register(format)
297
 
        self.assertEquals([format], self.registry._get_all())
298
 
 
299
 
    def test_register_extra(self):
300
 
        format = SampleExtraTreeFormat()
301
 
        self.assertEquals([], self.registry._get_all())
302
 
        self.registry.register_extra(format)
303
 
        self.assertEquals([format], self.registry._get_all())
304
 
 
305
 
    def test_register_extra_lazy(self):
306
 
        self.assertEquals([], self.registry._get_all())
307
 
        self.registry.register_extra_lazy("bzrlib.tests.test_workingtree",
308
 
            "SampleExtraTreeFormat")
309
 
        formats = self.registry._get_all()
310
 
        self.assertEquals(1, len(formats))
311
 
        self.assertIsInstance(formats[0], SampleExtraTreeFormat)
 
157
        workingtree.WorkingTreeFormat.unregister_format(format)
312
158
 
313
159
 
314
160
class TestWorkingTreeFormat3(TestCaseWithTransport):
318
164
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
319
165
        control.create_repository()
320
166
        control.create_branch()
321
 
        tree = workingtree_3.WorkingTreeFormat3().initialize(control)
 
167
        tree = workingtree.WorkingTreeFormat3().initialize(control)
322
168
        # we want:
323
169
        # format 'Bazaar-NG Working Tree format 3'
324
170
        # inventory = blank inventory
328
174
        t = control.get_workingtree_transport(None)
329
175
        self.assertEqualDiff('Bazaar-NG Working Tree format 3',
330
176
                             t.get('format').read())
331
 
        self.assertEqualDiff(t.get('inventory').read(),
 
177
        # self.assertContainsRe(t.get('inventory').read(), 
 
178
        #                       '<inventory file_id="[^"]*" format="5">\n'
 
179
        #                       '</inventory>\n',
 
180
        #                      )
 
181
        # WorkingTreeFormat3 doesn't default to creating a unique root id,
 
182
        # because it is incompatible with older bzr versions
 
183
        self.assertContainsRe(t.get('inventory').read(),
332
184
                              '<inventory format="5">\n'
333
185
                              '</inventory>\n',
334
186
                             )
337
189
        self.assertFalse(t.has('inventory.basis'))
338
190
        # no last-revision file means 'None' or 'NULLREVISION'
339
191
        self.assertFalse(t.has('last-revision'))
340
 
        # TODO RBC 20060210 do a commit, check the inventory.basis is created
 
192
        # TODO RBC 20060210 do a commit, check the inventory.basis is created 
341
193
        # correctly and last-revision file becomes present.
342
194
 
343
195
    def test_uses_lockdir(self):
344
196
        """WorkingTreeFormat3 uses its own LockDir:
345
 
 
 
197
            
346
198
            - lock is a directory
347
199
            - when the WorkingTree is locked, LockDir can see that
348
200
        """
352
204
        repo = dir.create_repository()
353
205
        branch = dir.create_branch()
354
206
        try:
355
 
            tree = workingtree_3.WorkingTreeFormat3().initialize(dir)
 
207
            tree = workingtree.WorkingTreeFormat3().initialize(dir)
356
208
        except errors.NotLocalUrl:
357
209
            raise TestSkipped('Not a local URL')
358
210
        self.assertIsDirectory('.bzr', t)
369
221
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
370
222
        control.create_repository()
371
223
        control.create_branch()
372
 
        tree = workingtree_3.WorkingTreeFormat3().initialize(control)
373
 
        tree._transport.delete("pending-merges")
 
224
        tree = workingtree.WorkingTreeFormat3().initialize(control)
 
225
        tree._control_files._transport.delete("pending-merges")
374
226
        self.assertEqual([], tree.get_parent_ids())
375
227
 
376
228
 
 
229
class TestFormat2WorkingTree(TestCaseWithTransport):
 
230
    """Tests that are specific to format 2 trees."""
 
231
 
 
232
    def create_format2_tree(self, url):
 
233
        return self.make_branch_and_tree(
 
234
            url, format=bzrlib.bzrdir.BzrDirFormat6())
 
235
 
 
236
    def test_conflicts(self):
 
237
        # test backwards compatability
 
238
        tree = self.create_format2_tree('.')
 
239
        self.assertRaises(errors.UnsupportedOperation, tree.set_conflicts,
 
240
                          None)
 
241
        file('lala.BASE', 'wb').write('labase')
 
242
        expected = conflicts.ContentsConflict('lala')
 
243
        self.assertEqual(list(tree.conflicts()), [expected])
 
244
        file('lala', 'wb').write('la')
 
245
        tree.add('lala', 'lala-id')
 
246
        expected = conflicts.ContentsConflict('lala', file_id='lala-id')
 
247
        self.assertEqual(list(tree.conflicts()), [expected])
 
248
        file('lala.THIS', 'wb').write('lathis')
 
249
        file('lala.OTHER', 'wb').write('laother')
 
250
        # When "text conflict"s happen, stem, THIS and OTHER are text
 
251
        expected = conflicts.TextConflict('lala', file_id='lala-id')
 
252
        self.assertEqual(list(tree.conflicts()), [expected])
 
253
        os.unlink('lala.OTHER')
 
254
        os.mkdir('lala.OTHER')
 
255
        expected = conflicts.ContentsConflict('lala', file_id='lala-id')
 
256
        self.assertEqual(list(tree.conflicts()), [expected])
 
257
 
 
258
 
 
259
class TestNonFormatSpecificCode(TestCaseWithTransport):
 
260
    """This class contains tests of workingtree that are not format specific."""
 
261
 
 
262
    def test_gen_file_id(self):
 
263
        file_id = self.applyDeprecated(zero_thirteen, workingtree.gen_file_id,
 
264
                                      'filename')
 
265
        self.assertStartsWith(file_id, 'filename-')
 
266
 
 
267
    def test_gen_root_id(self):
 
268
        file_id = self.applyDeprecated(zero_thirteen, workingtree.gen_root_id)
 
269
        self.assertStartsWith(file_id, 'tree_root-')
 
270
        
 
271
    def test__translate_ignore_rule(self):
 
272
        tree = self.make_branch_and_tree('.')
 
273
        # translation should return the regex, the number of groups in it,
 
274
        # and the original rule in a tuple.
 
275
        # there are three sorts of ignore rules:
 
276
        # root only - regex is the rule itself without the leading ./
 
277
        self.assertEqual(
 
278
            "(rootdirrule$)", 
 
279
            tree._translate_ignore_rule("./rootdirrule"))
 
280
        # full path - regex is the rule itself
 
281
        self.assertEqual(
 
282
            "(path\\/to\\/file$)",
 
283
            tree._translate_ignore_rule("path/to/file"))
 
284
        # basename only rule - regex is a rule that ignores everything up
 
285
        # to the last / in the filename
 
286
        self.assertEqual(
 
287
            "((?:.*/)?(?!.*/)basenamerule$)",
 
288
            tree._translate_ignore_rule("basenamerule"))
 
289
 
 
290
    def test__combine_ignore_rules(self):
 
291
        tree = self.make_branch_and_tree('.')
 
292
        # the combined ignore regexs need the outer group indices
 
293
        # placed in a dictionary with the rules that were combined.
 
294
        # an empty set of rules
 
295
        # this is returned as a list of combined regex,rule sets, because
 
296
        # python has a limit of 100 combined regexes.
 
297
        compiled_rules = tree._combine_ignore_rules([])
 
298
        self.assertEqual([], compiled_rules)
 
299
        # one of each type of rule.
 
300
        compiled_rules = tree._combine_ignore_rules(
 
301
            ["rule1", "rule/two", "./three"])[0]
 
302
        # what type *is* the compiled regex to do an isinstance of ?
 
303
        self.assertEqual(3, compiled_rules[0].groups)
 
304
        self.assertEqual(
 
305
            {0:"rule1",1:"rule/two",2:"./three"},
 
306
            compiled_rules[1])
 
307
 
 
308
    def test__combine_ignore_rules_grouping(self):
 
309
        tree = self.make_branch_and_tree('.')
 
310
        # when there are too many rules, the output is split into groups of 100
 
311
        rules = []
 
312
        for index in range(198):
 
313
            rules.append('foo')
 
314
        self.assertEqual(2, len(tree._combine_ignore_rules(rules)))
 
315
 
 
316
    def test__get_ignore_rules_as_regex(self):
 
317
        tree = self.make_branch_and_tree('.')
 
318
        # Setup the default ignore list to be empty
 
319
        ignores._set_user_ignores([])
 
320
 
 
321
        # some plugins (shelf) modifies the DEFAULT_IGNORE list in memory
 
322
        # which causes this test to fail so force the DEFAULT_IGNORE
 
323
        # list to be empty
 
324
        orig_default = bzrlib.DEFAULT_IGNORE
 
325
        # Also make sure the runtime ignore list is empty
 
326
        orig_runtime = ignores._runtime_ignores
 
327
        try:
 
328
            bzrlib.DEFAULT_IGNORE = []
 
329
            ignores._runtime_ignores = set()
 
330
 
 
331
            self.build_tree_contents([('.bzrignore', 'CVS\n.hg\n')])
 
332
            reference_output = tree._combine_ignore_rules(
 
333
                                    set(['CVS', '.hg']))[0]
 
334
            regex_rules = tree._get_ignore_rules_as_regex()[0]
 
335
            self.assertEqual(len(reference_output[1]), regex_rules[0].groups)
 
336
            self.assertEqual(reference_output[1], regex_rules[1])
 
337
        finally:
 
338
            bzrlib.DEFAULT_IGNORE = orig_default
 
339
            ignores._runtime_ignores = orig_runtime
 
340
 
 
341
 
377
342
class InstrumentedTree(object):
378
343
    """A instrumented tree to check the needs_tree_write_lock decorator."""
379
344
 
391
356
    @needs_tree_write_lock
392
357
    def method_that_raises(self):
393
358
        """This method causes an exception when called with parameters.
394
 
 
 
359
        
395
360
        This allows the decorator code to be checked - it should still call
396
361
        unlock.
397
362
        """
408
373
        self.assertEqual(
409
374
            'method_with_tree_write_lock',
410
375
            tree.method_with_tree_write_lock.__name__)
411
 
        self.assertDocstring(
 
376
        self.assertEqual(
412
377
            "A lock_tree_write decorated method that returns its arguments.",
413
 
            tree.method_with_tree_write_lock)
 
378
            tree.method_with_tree_write_lock.__doc__)
414
379
        args = (1, 2, 3)
415
380
        kwargs = {'a':'b'}
416
381
        result = tree.method_with_tree_write_lock(1,2,3, a='b')
418
383
        self.assertEqual(['t', 'u'], tree._locks)
419
384
        self.assertRaises(TypeError, tree.method_that_raises, 'foo')
420
385
        self.assertEqual(['t', 'u', 't', 'u'], tree._locks)
421
 
 
422
 
 
423
 
class TestRevert(TestCaseWithTransport):
424
 
 
425
 
    def test_revert_conflicts_recursive(self):
426
 
        this_tree = self.make_branch_and_tree('this-tree')
427
 
        self.build_tree_contents([('this-tree/foo/',),
428
 
                                  ('this-tree/foo/bar', 'bar')])
429
 
        this_tree.add(['foo', 'foo/bar'])
430
 
        this_tree.commit('created foo/bar')
431
 
        other_tree = this_tree.bzrdir.sprout('other-tree').open_workingtree()
432
 
        self.build_tree_contents([('other-tree/foo/bar', 'baz')])
433
 
        other_tree.commit('changed bar')
434
 
        self.build_tree_contents([('this-tree/foo/bar', 'qux')])
435
 
        this_tree.commit('changed qux')
436
 
        this_tree.merge_from_branch(other_tree.branch)
437
 
        self.assertEqual(1, len(this_tree.conflicts()))
438
 
        this_tree.revert(['foo'])
439
 
        self.assertEqual(0, len(this_tree.conflicts()))
440
 
 
441
 
 
442
 
class TestAutoResolve(TestCaseWithTransport):
443
 
 
444
 
    def test_auto_resolve(self):
445
 
        base = self.make_branch_and_tree('base')
446
 
        self.build_tree_contents([('base/hello', 'Hello')])
447
 
        base.add('hello', 'hello_id')
448
 
        base.commit('Hello')
449
 
        other = base.bzrdir.sprout('other').open_workingtree()
450
 
        self.build_tree_contents([('other/hello', 'hELLO')])
451
 
        other.commit('Case switch')
452
 
        this = base.bzrdir.sprout('this').open_workingtree()
453
 
        self.assertPathExists('this/hello')
454
 
        self.build_tree_contents([('this/hello', 'Hello World')])
455
 
        this.commit('Add World')
456
 
        this.merge_from_branch(other.branch)
457
 
        self.assertEqual([conflicts.TextConflict('hello', 'hello_id')],
458
 
                         this.conflicts())
459
 
        this.auto_resolve()
460
 
        self.assertEqual([conflicts.TextConflict('hello', 'hello_id')],
461
 
                         this.conflicts())
462
 
        self.build_tree_contents([('this/hello', '<<<<<<<')])
463
 
        this.auto_resolve()
464
 
        self.assertEqual([conflicts.TextConflict('hello', 'hello_id')],
465
 
                         this.conflicts())
466
 
        self.build_tree_contents([('this/hello', '=======')])
467
 
        this.auto_resolve()
468
 
        self.assertEqual([conflicts.TextConflict('hello', 'hello_id')],
469
 
                         this.conflicts())
470
 
        self.build_tree_contents([('this/hello', '\n>>>>>>>')])
471
 
        remaining, resolved = this.auto_resolve()
472
 
        self.assertEqual([conflicts.TextConflict('hello', 'hello_id')],
473
 
                         this.conflicts())
474
 
        self.assertEqual([], resolved)
475
 
        self.build_tree_contents([('this/hello', 'hELLO wORLD')])
476
 
        remaining, resolved = this.auto_resolve()
477
 
        self.assertEqual([], this.conflicts())
478
 
        self.assertEqual([conflicts.TextConflict('hello', 'hello_id')],
479
 
                         resolved)
480
 
        self.assertPathDoesNotExist('this/hello.BASE')
481
 
 
482
 
    def test_auto_resolve_dir(self):
483
 
        tree = self.make_branch_and_tree('tree')
484
 
        self.build_tree(['tree/hello/'])
485
 
        tree.add('hello', 'hello-id')
486
 
        file_conflict = conflicts.TextConflict('file', 'hello-id')
487
 
        tree.set_conflicts(conflicts.ConflictList([file_conflict]))
488
 
        tree.auto_resolve()
489
 
 
490
 
 
491
 
class TestFindTrees(TestCaseWithTransport):
492
 
 
493
 
    def test_find_trees(self):
494
 
        self.make_branch_and_tree('foo')
495
 
        self.make_branch_and_tree('foo/bar')
496
 
        # Sticking a tree inside a control dir is heinous, so let's skip it
497
 
        self.make_branch_and_tree('foo/.bzr/baz')
498
 
        self.make_branch('qux')
499
 
        trees = workingtree.WorkingTree.find_trees('.')
500
 
        self.assertEqual(2, len(list(trees)))