18
18
from cStringIO import StringIO
21
from bzrlib import ignores
22
23
from bzrlib.branch import Branch
23
24
from bzrlib import bzrdir, conflicts, errors, workingtree
24
25
from bzrlib.bzrdir import BzrDir
25
26
from bzrlib.errors import NotBranchError, NotVersionedError
26
27
from bzrlib.lockdir import LockDir
28
from bzrlib.mutabletree import needs_tree_write_lock
27
29
from bzrlib.osutils import pathjoin, getcwd, has_symlinks
28
from bzrlib.tests import TestCaseWithTransport, TestSkipped
30
from bzrlib.tests import TestCase, TestCaseWithTransport, TestSkipped
29
31
from bzrlib.trace import mutter
30
32
from bzrlib.transport import get_transport
31
from bzrlib.workingtree import (TreeEntry, TreeDirectory, TreeFile, TreeLink,
33
from bzrlib.workingtree import (
34
41
class TestTreeDirectory(TestCaseWithTransport):
248
255
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-')
256
gen_file_id = bzrlib.workingtree.gen_file_id
258
# We try to use the filename if possible
259
self.assertStartsWith(gen_file_id('bar'), 'bar-')
261
# but we squash capitalization, and remove non word characters
262
self.assertStartsWith(gen_file_id('Mwoo oof\t m'), 'mwoooofm-')
264
# We also remove leading '.' characters to prevent hidden file-ids
265
self.assertStartsWith(gen_file_id('..gam.py'), 'gam.py-')
266
self.assertStartsWith(gen_file_id('..Mwoo oof\t m'), 'mwoooofm-')
268
# we remove unicode characters, and still don't end up with a
270
self.assertStartsWith(gen_file_id(u'\xe5\xb5.txt'), 'txt-')
272
# Our current method of generating unique ids adds 33 characters
273
# plus an serial number (log10(N) characters)
274
# to the end of the filename. We now restrict the filename portion to
275
# be <= 20 characters, so the maximum length should now be approx < 60
277
# Test both case squashing and length restriction
278
fid = gen_file_id('A'*50 + '.txt')
279
self.assertStartsWith(fid, 'a'*20 + '-')
280
self.failUnless(len(fid) < 60)
282
# restricting length happens after the other actions, so
283
# we preserve as much as possible
284
fid = gen_file_id('\xe5\xb5..aBcd\tefGhijKLMnop\tqrstuvwxyz')
285
self.assertStartsWith(fid, 'abcdefghijklmnopqrst-')
286
self.failUnless(len(fid) < 60)
254
288
def test_next_id_suffix(self):
255
289
bzrlib.workingtree._gen_id_suffix = None
315
349
def test__get_ignore_rules_as_regex(self):
316
350
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])
351
# Setup the default ignore list to be empty
352
ignores._set_user_ignores([])
354
# some plugins (shelf) modifies the DEFAULT_IGNORE list in memory
355
# which causes this test to fail so force the DEFAULT_IGNORE
357
orig_default = bzrlib.DEFAULT_IGNORE
358
# Also make sure the runtime ignore list is empty
359
orig_runtime = ignores._runtime_ignores
361
bzrlib.DEFAULT_IGNORE = []
362
ignores._runtime_ignores = set()
364
self.build_tree_contents([('.bzrignore', 'CVS\n.hg\n')])
365
reference_output = tree._combine_ignore_rules(
366
set(['CVS', '.hg']))[0]
367
regex_rules = tree._get_ignore_rules_as_regex()[0]
368
self.assertEqual(len(reference_output[1]), regex_rules[0].groups)
369
self.assertEqual(reference_output[1], regex_rules[1])
371
bzrlib.DEFAULT_IGNORE = orig_default
372
ignores._runtime_ignores = orig_runtime
375
class InstrumentedTree(object):
376
"""A instrumented tree to check the needs_tree_write_lock decorator."""
381
def lock_tree_write(self):
382
self._locks.append('t')
384
@needs_tree_write_lock
385
def method_with_tree_write_lock(self, *args, **kwargs):
386
"""A lock_tree_write decorated method that returns its arguments."""
389
@needs_tree_write_lock
390
def method_that_raises(self):
391
"""This method causes an exception when called with parameters.
393
This allows the decorator code to be checked - it should still call
398
self._locks.append('u')
401
class TestInstrumentedTree(TestCase):
403
def test_needs_tree_write_lock(self):
404
"""@needs_tree_write_lock should be semantically transparent."""
405
tree = InstrumentedTree()
407
'method_with_tree_write_lock',
408
tree.method_with_tree_write_lock.__name__)
410
"A lock_tree_write decorated method that returns its arguments.",
411
tree.method_with_tree_write_lock.__doc__)
414
result = tree.method_with_tree_write_lock(1,2,3, a='b')
415
self.assertEqual((args, kwargs), result)
416
self.assertEqual(['t', 'u'], tree._locks)
417
self.assertRaises(TypeError, tree.method_that_raises, 'foo')
418
self.assertEqual(['t', 'u', 't', 'u'], tree._locks)