~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_workingtree.py

  • Committer: John Arbash Meinel
  • Date: 2006-06-10 14:53:51 UTC
  • mto: (1711.7.2 win32)
  • mto: This revision was merged to the branch mainline in revision 1796.
  • Revision ID: john@arbash-meinel.com-20060610145351-9da0c1f8ba8a57e0
the _posix_* routines should use posixpath not os.path, so tests pass on win32

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
import bzrlib
 
22
from bzrlib.branch import Branch
 
23
import bzrlib.bzrdir as bzrdir
 
24
from bzrlib.bzrdir import BzrDir
 
25
from bzrlib.conflicts import *
 
26
import bzrlib.errors as errors
 
27
from bzrlib.errors import NotBranchError, NotVersionedError
28
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
 
 
 
29
from bzrlib.osutils import pathjoin, getcwd, has_symlinks
 
30
from bzrlib.tests import TestCaseWithTransport, TestSkipped
 
31
from bzrlib.trace import mutter
 
32
from bzrlib.transport import get_transport
 
33
import bzrlib.workingtree as workingtree
 
34
from bzrlib.workingtree import (TreeEntry, TreeDirectory, TreeFile, TreeLink,
 
35
                                WorkingTree)
38
36
 
39
37
class TestTreeDirectory(TestCaseWithTransport):
40
38
 
63
61
class TestDefaultFormat(TestCaseWithTransport):
64
62
 
65
63
    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)
 
64
        old_format = workingtree.WorkingTreeFormat.get_default_format()
 
65
        # default is 3
 
66
        self.assertTrue(isinstance(old_format, workingtree.WorkingTreeFormat3))
 
67
        workingtree.WorkingTreeFormat.set_default_format(SampleTreeFormat())
 
68
        try:
 
69
            # the default branch format is used by the meta dir format
 
70
            # which is not the default bzrdir format at this point
 
71
            dir = bzrdir.BzrDirMetaFormat1().initialize('.')
 
72
            dir.create_repository()
 
73
            dir.create_branch()
 
74
            result = dir.create_workingtree()
 
75
            self.assertEqual(result, 'A tree')
 
76
        finally:
 
77
            workingtree.WorkingTreeFormat.set_default_format(old_format)
 
78
        self.assertEqual(old_format, workingtree.WorkingTreeFormat.get_default_format())
121
79
 
122
80
 
123
81
class SampleTreeFormat(workingtree.WorkingTreeFormat):
124
82
    """A sample format
125
83
 
126
 
    this format is initializable, unsupported to aid in testing the
 
84
    this format is initializable, unsupported to aid in testing the 
127
85
    open and open_downlevel routines.
128
86
    """
129
87
 
131
89
        """See WorkingTreeFormat.get_format_string()."""
132
90
        return "Sample tree format."
133
91
 
134
 
    def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
135
 
                   accelerator_tree=None, hardlink=False):
 
92
    def initialize(self, a_bzrdir, revision_id=None):
136
93
        """Sample branches cannot be created."""
137
94
        t = a_bzrdir.get_workingtree_transport(self)
138
 
        t.put_bytes('format', self.get_format_string())
 
95
        t.put('format', StringIO(self.get_format_string()))
139
96
        return 'A tree'
140
97
 
141
98
    def is_supported(self):
145
102
        return "opened tree."
146
103
 
147
104
 
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
105
class TestWorkingTreeFormat(TestCaseWithTransport):
169
106
    """Tests for the WorkingTreeFormat facility."""
170
107
 
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
108
    def test_find_format(self):
185
109
        # is the right format object found for a working tree?
186
110
        # create a branch with a few known format objects.
190
114
            dir.create_repository()
191
115
            dir.create_branch()
192
116
            format.initialize(dir)
193
 
            t = transport.get_transport(url)
 
117
            t = get_transport(url)
194
118
            found_format = workingtree.WorkingTreeFormat.find_format(dir)
195
 
            self.assertIsInstance(found_format, format.__class__)
196
 
        check_format(workingtree_3.WorkingTreeFormat3(), "bar")
197
 
 
 
119
            self.failUnless(isinstance(found_format, format.__class__))
 
120
        check_format(workingtree.WorkingTreeFormat3(), "bar")
 
121
        
198
122
    def test_find_format_no_tree(self):
199
123
        dir = bzrdir.BzrDirMetaFormat1().initialize('.')
200
124
        self.assertRaises(errors.NoWorkingTree,
219
143
        # make a branch
220
144
        format.initialize(dir)
221
145
        # 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))
 
146
        workingtree.WorkingTreeFormat.register_format(format)
227
147
        # which branch.Open will refuse (not supported)
228
148
        self.assertRaises(errors.UnsupportedFormatError, workingtree.WorkingTree.open, '.')
229
149
        # but open_downlevel will work
230
150
        self.assertEqual(format.open(dir), workingtree.WorkingTree.open_downlevel('.'))
231
151
        # 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)
 
152
        workingtree.WorkingTreeFormat.unregister_format(format)
312
153
 
313
154
 
314
155
class TestWorkingTreeFormat3(TestCaseWithTransport):
318
159
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
319
160
        control.create_repository()
320
161
        control.create_branch()
321
 
        tree = workingtree_3.WorkingTreeFormat3().initialize(control)
 
162
        tree = workingtree.WorkingTreeFormat3().initialize(control)
322
163
        # we want:
323
164
        # format 'Bazaar-NG Working Tree format 3'
324
165
        # inventory = blank inventory
328
169
        t = control.get_workingtree_transport(None)
329
170
        self.assertEqualDiff('Bazaar-NG Working Tree format 3',
330
171
                             t.get('format').read())
331
 
        self.assertEqualDiff(t.get('inventory').read(),
332
 
                              '<inventory format="5">\n'
333
 
                              '</inventory>\n',
334
 
                             )
 
172
        self.assertEqualDiff('<inventory format="5">\n'
 
173
                             '</inventory>\n',
 
174
                             t.get('inventory').read())
335
175
        self.assertEqualDiff('### bzr hashcache v5\n',
336
176
                             t.get('stat-cache').read())
337
177
        self.assertFalse(t.has('inventory.basis'))
338
178
        # no last-revision file means 'None' or 'NULLREVISION'
339
179
        self.assertFalse(t.has('last-revision'))
340
 
        # TODO RBC 20060210 do a commit, check the inventory.basis is created
 
180
        # TODO RBC 20060210 do a commit, check the inventory.basis is created 
341
181
        # correctly and last-revision file becomes present.
342
182
 
343
183
    def test_uses_lockdir(self):
344
184
        """WorkingTreeFormat3 uses its own LockDir:
345
 
 
 
185
            
346
186
            - lock is a directory
347
187
            - when the WorkingTree is locked, LockDir can see that
348
188
        """
352
192
        repo = dir.create_repository()
353
193
        branch = dir.create_branch()
354
194
        try:
355
 
            tree = workingtree_3.WorkingTreeFormat3().initialize(dir)
 
195
            tree = workingtree.WorkingTreeFormat3().initialize(dir)
356
196
        except errors.NotLocalUrl:
357
197
            raise TestSkipped('Not a local URL')
358
198
        self.assertIsDirectory('.bzr', t)
365
205
        tree.unlock()
366
206
        self.assertEquals(our_lock.peek(), None)
367
207
 
368
 
    def test_missing_pending_merges(self):
369
 
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
370
 
        control.create_repository()
371
 
        control.create_branch()
372
 
        tree = workingtree_3.WorkingTreeFormat3().initialize(control)
373
 
        tree._transport.delete("pending-merges")
374
 
        self.assertEqual([], tree.get_parent_ids())
375
 
 
376
 
 
377
 
class InstrumentedTree(object):
378
 
    """A instrumented tree to check the needs_tree_write_lock decorator."""
379
 
 
380
 
    def __init__(self):
381
 
        self._locks = []
382
 
 
383
 
    def lock_tree_write(self):
384
 
        self._locks.append('t')
385
 
 
386
 
    @needs_tree_write_lock
387
 
    def method_with_tree_write_lock(self, *args, **kwargs):
388
 
        """A lock_tree_write decorated method that returns its arguments."""
389
 
        return args, kwargs
390
 
 
391
 
    @needs_tree_write_lock
392
 
    def method_that_raises(self):
393
 
        """This method causes an exception when called with parameters.
394
 
 
395
 
        This allows the decorator code to be checked - it should still call
396
 
        unlock.
397
 
        """
398
 
 
399
 
    def unlock(self):
400
 
        self._locks.append('u')
401
 
 
402
 
 
403
 
class TestInstrumentedTree(TestCase):
404
 
 
405
 
    def test_needs_tree_write_lock(self):
406
 
        """@needs_tree_write_lock should be semantically transparent."""
407
 
        tree = InstrumentedTree()
408
 
        self.assertEqual(
409
 
            'method_with_tree_write_lock',
410
 
            tree.method_with_tree_write_lock.__name__)
411
 
        self.assertDocstring(
412
 
            "A lock_tree_write decorated method that returns its arguments.",
413
 
            tree.method_with_tree_write_lock)
414
 
        args = (1, 2, 3)
415
 
        kwargs = {'a':'b'}
416
 
        result = tree.method_with_tree_write_lock(1,2,3, a='b')
417
 
        self.assertEqual((args, kwargs), result)
418
 
        self.assertEqual(['t', 'u'], tree._locks)
419
 
        self.assertRaises(TypeError, tree.method_that_raises, 'foo')
420
 
        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)))
 
208
 
 
209
class TestFormat2WorkingTree(TestCaseWithTransport):
 
210
    """Tests that are specific to format 2 trees."""
 
211
 
 
212
    def create_format2_tree(self, url):
 
213
        return self.make_branch_and_tree(
 
214
            url, format=bzrlib.bzrdir.BzrDirFormat6())
 
215
 
 
216
    def test_conflicts(self):
 
217
        # test backwards compatability
 
218
        tree = self.create_format2_tree('.')
 
219
        self.assertRaises(errors.UnsupportedOperation, tree.set_conflicts,
 
220
                          None)
 
221
        file('lala.BASE', 'wb').write('labase')
 
222
        expected = ContentsConflict('lala')
 
223
        self.assertEqual(list(tree.conflicts()), [expected])
 
224
        file('lala', 'wb').write('la')
 
225
        tree.add('lala', 'lala-id')
 
226
        expected = ContentsConflict('lala', file_id='lala-id')
 
227
        self.assertEqual(list(tree.conflicts()), [expected])
 
228
        file('lala.THIS', 'wb').write('lathis')
 
229
        file('lala.OTHER', 'wb').write('laother')
 
230
        # When "text conflict"s happen, stem, THIS and OTHER are text
 
231
        expected = TextConflict('lala', file_id='lala-id')
 
232
        self.assertEqual(list(tree.conflicts()), [expected])
 
233
        os.unlink('lala.OTHER')
 
234
        os.mkdir('lala.OTHER')
 
235
        expected = ContentsConflict('lala', file_id='lala-id')
 
236
        self.assertEqual(list(tree.conflicts()), [expected])
 
237
 
 
238
 
 
239
class TestNonFormatSpecificCode(TestCaseWithTransport):
 
240
    """This class contains tests of workingtree that are not format specific."""
 
241
 
 
242
    
 
243
    def test_gen_file_id(self):
 
244
        self.assertStartsWith(bzrlib.workingtree.gen_file_id('bar'), 'bar-')
 
245
        self.assertStartsWith(bzrlib.workingtree.gen_file_id('Mwoo oof\t m'), 'Mwoooofm-')
 
246
        self.assertStartsWith(bzrlib.workingtree.gen_file_id('..gam.py'), 'gam.py-')
 
247
        self.assertStartsWith(bzrlib.workingtree.gen_file_id('..Mwoo oof\t m'), 'Mwoooofm-')
 
248
 
 
249
    def test_next_id_suffix(self):
 
250
        bzrlib.workingtree._gen_id_suffix = None
 
251
        bzrlib.workingtree._next_id_suffix()
 
252
        self.assertNotEqual(None, bzrlib.workingtree._gen_id_suffix)
 
253
        bzrlib.workingtree._gen_id_suffix = "foo-"
 
254
        bzrlib.workingtree._gen_id_serial = 1
 
255
        self.assertEqual("foo-2", bzrlib.workingtree._next_id_suffix())
 
256
        self.assertEqual("foo-3", bzrlib.workingtree._next_id_suffix())
 
257
        self.assertEqual("foo-4", bzrlib.workingtree._next_id_suffix())
 
258
        self.assertEqual("foo-5", bzrlib.workingtree._next_id_suffix())
 
259
        self.assertEqual("foo-6", bzrlib.workingtree._next_id_suffix())
 
260
        self.assertEqual("foo-7", bzrlib.workingtree._next_id_suffix())
 
261
        self.assertEqual("foo-8", bzrlib.workingtree._next_id_suffix())
 
262
        self.assertEqual("foo-9", bzrlib.workingtree._next_id_suffix())
 
263
        self.assertEqual("foo-10", bzrlib.workingtree._next_id_suffix())
 
264
 
 
265
    def test__translate_ignore_rule(self):
 
266
        tree = self.make_branch_and_tree('.')
 
267
        # translation should return the regex, the number of groups in it,
 
268
        # and the original rule in a tuple.
 
269
        # there are three sorts of ignore rules:
 
270
        # root only - regex is the rule itself without the leading ./
 
271
        self.assertEqual(
 
272
            "(rootdirrule$)", 
 
273
            tree._translate_ignore_rule("./rootdirrule"))
 
274
        # full path - regex is the rule itself
 
275
        self.assertEqual(
 
276
            "(path\\/to\\/file$)",
 
277
            tree._translate_ignore_rule("path/to/file"))
 
278
        # basename only rule - regex is a rule that ignores everything up
 
279
        # to the last / in the filename
 
280
        self.assertEqual(
 
281
            "((?:.*/)?(?!.*/)basenamerule$)",
 
282
            tree._translate_ignore_rule("basenamerule"))
 
283
 
 
284
    def test__combine_ignore_rules(self):
 
285
        tree = self.make_branch_and_tree('.')
 
286
        # the combined ignore regexs need the outer group indices
 
287
        # placed in a dictionary with the rules that were combined.
 
288
        # an empty set of rules
 
289
        # this is returned as a list of combined regex,rule sets, because
 
290
        # python has a limit of 100 combined regexes.
 
291
        compiled_rules = tree._combine_ignore_rules([])
 
292
        self.assertEqual([], compiled_rules)
 
293
        # one of each type of rule.
 
294
        compiled_rules = tree._combine_ignore_rules(
 
295
            ["rule1", "rule/two", "./three"])[0]
 
296
        # what type *is* the compiled regex to do an isinstance of ?
 
297
        self.assertEqual(3, compiled_rules[0].groups)
 
298
        self.assertEqual(
 
299
            {0:"rule1",1:"rule/two",2:"./three"},
 
300
            compiled_rules[1])
 
301
 
 
302
    def test__combine_ignore_rules_grouping(self):
 
303
        tree = self.make_branch_and_tree('.')
 
304
        # when there are too many rules, the output is split into groups of 100
 
305
        rules = []
 
306
        for index in range(198):
 
307
            rules.append('foo')
 
308
        self.assertEqual(2, len(tree._combine_ignore_rules(rules)))
 
309
 
 
310
    def test__get_ignore_rules_as_regex(self):
 
311
        tree = self.make_branch_and_tree('.')
 
312
        # test against the default rules.
 
313
        reference_output = tree._combine_ignore_rules(bzrlib.DEFAULT_IGNORE)[0]
 
314
        regex_rules = tree._get_ignore_rules_as_regex()[0]
 
315
        self.assertEqual(len(reference_output[1]), regex_rules[0].groups)
 
316
        self.assertEqual(reference_output[1], regex_rules[1])