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