206
211
self.assertEquals(our_lock.peek(), None)
213
def test_missing_pending_merges(self):
214
control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
215
control.create_repository()
216
control.create_branch()
217
tree = workingtree.WorkingTreeFormat3().initialize(control)
218
tree._control_files._transport.delete("pending-merges")
219
self.assertEqual([], tree.get_parent_ids())
222
class TestFormat2WorkingTree(TestCaseWithTransport):
223
"""Tests that are specific to format 2 trees."""
208
225
def create_format2_tree(self, url):
209
return BzrDir.create_standalone_workingtree(url)
226
return self.make_branch_and_tree(
227
url, format=bzrlib.bzrdir.BzrDirFormat6())
211
def test_conflicts_format2(self):
229
def test_conflicts(self):
212
230
# test backwards compatability
213
231
tree = self.create_format2_tree('.')
214
232
self.assertRaises(errors.UnsupportedOperation, tree.set_conflicts,
216
234
file('lala.BASE', 'wb').write('labase')
217
expected = ContentsConflict('lala')
235
expected = conflicts.ContentsConflict('lala')
218
236
self.assertEqual(list(tree.conflicts()), [expected])
219
237
file('lala', 'wb').write('la')
220
238
tree.add('lala', 'lala-id')
221
expected = ContentsConflict('lala', file_id='lala-id')
239
expected = conflicts.ContentsConflict('lala', file_id='lala-id')
222
240
self.assertEqual(list(tree.conflicts()), [expected])
223
241
file('lala.THIS', 'wb').write('lathis')
224
242
file('lala.OTHER', 'wb').write('laother')
225
243
# When "text conflict"s happen, stem, THIS and OTHER are text
226
expected = TextConflict('lala', file_id='lala-id')
244
expected = conflicts.TextConflict('lala', file_id='lala-id')
227
245
self.assertEqual(list(tree.conflicts()), [expected])
228
246
os.unlink('lala.OTHER')
229
247
os.mkdir('lala.OTHER')
230
expected = ContentsConflict('lala', file_id='lala-id')
248
expected = conflicts.ContentsConflict('lala', file_id='lala-id')
231
249
self.assertEqual(list(tree.conflicts()), [expected])
252
class TestNonFormatSpecificCode(TestCaseWithTransport):
253
"""This class contains tests of workingtree that are not format specific."""
256
def test_gen_file_id(self):
257
gen_file_id = bzrlib.workingtree.gen_file_id
259
# We try to use the filename if possible
260
self.assertStartsWith(gen_file_id('bar'), 'bar-')
262
# but we squash capitalization, and remove non word characters
263
self.assertStartsWith(gen_file_id('Mwoo oof\t m'), 'mwoooofm-')
265
# We also remove leading '.' characters to prevent hidden file-ids
266
self.assertStartsWith(gen_file_id('..gam.py'), 'gam.py-')
267
self.assertStartsWith(gen_file_id('..Mwoo oof\t m'), 'mwoooofm-')
269
# we remove unicode characters, and still don't end up with a
271
self.assertStartsWith(gen_file_id(u'\xe5\xb5.txt'), 'txt-')
273
# Our current method of generating unique ids adds 33 characters
274
# plus an serial number (log10(N) characters)
275
# to the end of the filename. We now restrict the filename portion to
276
# be <= 20 characters, so the maximum length should now be approx < 60
278
# Test both case squashing and length restriction
279
fid = gen_file_id('A'*50 + '.txt')
280
self.assertStartsWith(fid, 'a'*20 + '-')
281
self.failUnless(len(fid) < 60)
283
# restricting length happens after the other actions, so
284
# we preserve as much as possible
285
fid = gen_file_id('\xe5\xb5..aBcd\tefGhijKLMnop\tqrstuvwxyz')
286
self.assertStartsWith(fid, 'abcdefghijklmnopqrst-')
287
self.failUnless(len(fid) < 60)
289
def test_next_id_suffix(self):
290
bzrlib.workingtree._gen_id_suffix = None
291
bzrlib.workingtree._next_id_suffix()
292
self.assertNotEqual(None, bzrlib.workingtree._gen_id_suffix)
293
bzrlib.workingtree._gen_id_suffix = "foo-"
294
bzrlib.workingtree._gen_id_serial = 1
295
self.assertEqual("foo-2", bzrlib.workingtree._next_id_suffix())
296
self.assertEqual("foo-3", bzrlib.workingtree._next_id_suffix())
297
self.assertEqual("foo-4", bzrlib.workingtree._next_id_suffix())
298
self.assertEqual("foo-5", bzrlib.workingtree._next_id_suffix())
299
self.assertEqual("foo-6", bzrlib.workingtree._next_id_suffix())
300
self.assertEqual("foo-7", bzrlib.workingtree._next_id_suffix())
301
self.assertEqual("foo-8", bzrlib.workingtree._next_id_suffix())
302
self.assertEqual("foo-9", bzrlib.workingtree._next_id_suffix())
303
self.assertEqual("foo-10", bzrlib.workingtree._next_id_suffix())
305
def test__translate_ignore_rule(self):
306
tree = self.make_branch_and_tree('.')
307
# translation should return the regex, the number of groups in it,
308
# and the original rule in a tuple.
309
# there are three sorts of ignore rules:
310
# root only - regex is the rule itself without the leading ./
313
tree._translate_ignore_rule("./rootdirrule"))
314
# full path - regex is the rule itself
316
"(path\\/to\\/file$)",
317
tree._translate_ignore_rule("path/to/file"))
318
# basename only rule - regex is a rule that ignores everything up
319
# to the last / in the filename
321
"((?:.*/)?(?!.*/)basenamerule$)",
322
tree._translate_ignore_rule("basenamerule"))
324
def test__combine_ignore_rules(self):
325
tree = self.make_branch_and_tree('.')
326
# the combined ignore regexs need the outer group indices
327
# placed in a dictionary with the rules that were combined.
328
# an empty set of rules
329
# this is returned as a list of combined regex,rule sets, because
330
# python has a limit of 100 combined regexes.
331
compiled_rules = tree._combine_ignore_rules([])
332
self.assertEqual([], compiled_rules)
333
# one of each type of rule.
334
compiled_rules = tree._combine_ignore_rules(
335
["rule1", "rule/two", "./three"])[0]
336
# what type *is* the compiled regex to do an isinstance of ?
337
self.assertEqual(3, compiled_rules[0].groups)
339
{0:"rule1",1:"rule/two",2:"./three"},
342
def test__combine_ignore_rules_grouping(self):
343
tree = self.make_branch_and_tree('.')
344
# when there are too many rules, the output is split into groups of 100
346
for index in range(198):
348
self.assertEqual(2, len(tree._combine_ignore_rules(rules)))
350
def test__get_ignore_rules_as_regex(self):
351
tree = self.make_branch_and_tree('.')
352
# Setup the default ignore list to be empty
353
ignores._set_user_ignores([])
355
# some plugins (shelf) modifies the DEFAULT_IGNORE list in memory
356
# which causes this test to fail so force the DEFAULT_IGNORE
358
orig_default = bzrlib.DEFAULT_IGNORE
359
# Also make sure the runtime ignore list is empty
360
orig_runtime = ignores._runtime_ignores
362
bzrlib.DEFAULT_IGNORE = []
363
ignores._runtime_ignores = set()
365
self.build_tree_contents([('.bzrignore', 'CVS\n.hg\n')])
366
reference_output = tree._combine_ignore_rules(
367
set(['CVS', '.hg']))[0]
368
regex_rules = tree._get_ignore_rules_as_regex()[0]
369
self.assertEqual(len(reference_output[1]), regex_rules[0].groups)
370
self.assertEqual(reference_output[1], regex_rules[1])
372
bzrlib.DEFAULT_IGNORE = orig_default
373
ignores._runtime_ignores = orig_runtime
376
class InstrumentedTree(object):
377
"""A instrumented tree to check the needs_tree_write_lock decorator."""
382
def lock_tree_write(self):
383
self._locks.append('t')
385
@needs_tree_write_lock
386
def method_with_tree_write_lock(self, *args, **kwargs):
387
"""A lock_tree_write decorated method that returns its arguments."""
390
@needs_tree_write_lock
391
def method_that_raises(self):
392
"""This method causes an exception when called with parameters.
394
This allows the decorator code to be checked - it should still call
399
self._locks.append('u')
402
class TestInstrumentedTree(TestCase):
404
def test_needs_tree_write_lock(self):
405
"""@needs_tree_write_lock should be semantically transparent."""
406
tree = InstrumentedTree()
408
'method_with_tree_write_lock',
409
tree.method_with_tree_write_lock.__name__)
411
"A lock_tree_write decorated method that returns its arguments.",
412
tree.method_with_tree_write_lock.__doc__)
415
result = tree.method_with_tree_write_lock(1,2,3, a='b')
416
self.assertEqual((args, kwargs), result)
417
self.assertEqual(['t', 'u'], tree._locks)
418
self.assertRaises(TypeError, tree.method_that_raises, 'foo')
419
self.assertEqual(['t', 'u', 't', 'u'], tree._locks)