206
210
self.assertEquals(our_lock.peek(), None)
212
def test_missing_pending_merges(self):
213
control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
214
control.create_repository()
215
control.create_branch()
216
tree = workingtree.WorkingTreeFormat3().initialize(control)
217
tree._control_files._transport.delete("pending-merges")
218
self.assertEqual([], tree.get_parent_ids())
221
class TestFormat2WorkingTree(TestCaseWithTransport):
222
"""Tests that are specific to format 2 trees."""
208
224
def create_format2_tree(self, url):
209
return BzrDir.create_standalone_workingtree(url)
225
return self.make_branch_and_tree(
226
url, format=bzrlib.bzrdir.BzrDirFormat6())
211
def test_conflicts_format2(self):
228
def test_conflicts(self):
212
229
# test backwards compatability
213
230
tree = self.create_format2_tree('.')
214
231
self.assertRaises(errors.UnsupportedOperation, tree.set_conflicts,
216
233
file('lala.BASE', 'wb').write('labase')
217
expected = ContentsConflict('lala')
234
expected = conflicts.ContentsConflict('lala')
218
235
self.assertEqual(list(tree.conflicts()), [expected])
219
236
file('lala', 'wb').write('la')
220
237
tree.add('lala', 'lala-id')
221
expected = ContentsConflict('lala', file_id='lala-id')
238
expected = conflicts.ContentsConflict('lala', file_id='lala-id')
222
239
self.assertEqual(list(tree.conflicts()), [expected])
223
240
file('lala.THIS', 'wb').write('lathis')
224
241
file('lala.OTHER', 'wb').write('laother')
225
242
# When "text conflict"s happen, stem, THIS and OTHER are text
226
expected = TextConflict('lala', file_id='lala-id')
243
expected = conflicts.TextConflict('lala', file_id='lala-id')
227
244
self.assertEqual(list(tree.conflicts()), [expected])
228
245
os.unlink('lala.OTHER')
229
246
os.mkdir('lala.OTHER')
230
expected = ContentsConflict('lala', file_id='lala-id')
247
expected = conflicts.ContentsConflict('lala', file_id='lala-id')
231
248
self.assertEqual(list(tree.conflicts()), [expected])
251
class TestNonFormatSpecificCode(TestCaseWithTransport):
252
"""This class contains tests of workingtree that are not format specific."""
255
def test_gen_file_id(self):
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)
288
def test_next_id_suffix(self):
289
bzrlib.workingtree._gen_id_suffix = None
290
bzrlib.workingtree._next_id_suffix()
291
self.assertNotEqual(None, bzrlib.workingtree._gen_id_suffix)
292
bzrlib.workingtree._gen_id_suffix = "foo-"
293
bzrlib.workingtree._gen_id_serial = 1
294
self.assertEqual("foo-2", bzrlib.workingtree._next_id_suffix())
295
self.assertEqual("foo-3", bzrlib.workingtree._next_id_suffix())
296
self.assertEqual("foo-4", bzrlib.workingtree._next_id_suffix())
297
self.assertEqual("foo-5", bzrlib.workingtree._next_id_suffix())
298
self.assertEqual("foo-6", bzrlib.workingtree._next_id_suffix())
299
self.assertEqual("foo-7", bzrlib.workingtree._next_id_suffix())
300
self.assertEqual("foo-8", bzrlib.workingtree._next_id_suffix())
301
self.assertEqual("foo-9", bzrlib.workingtree._next_id_suffix())
302
self.assertEqual("foo-10", bzrlib.workingtree._next_id_suffix())
304
def test__translate_ignore_rule(self):
305
tree = self.make_branch_and_tree('.')
306
# translation should return the regex, the number of groups in it,
307
# and the original rule in a tuple.
308
# there are three sorts of ignore rules:
309
# root only - regex is the rule itself without the leading ./
312
tree._translate_ignore_rule("./rootdirrule"))
313
# full path - regex is the rule itself
315
"(path\\/to\\/file$)",
316
tree._translate_ignore_rule("path/to/file"))
317
# basename only rule - regex is a rule that ignores everything up
318
# to the last / in the filename
320
"((?:.*/)?(?!.*/)basenamerule$)",
321
tree._translate_ignore_rule("basenamerule"))
323
def test__combine_ignore_rules(self):
324
tree = self.make_branch_and_tree('.')
325
# the combined ignore regexs need the outer group indices
326
# placed in a dictionary with the rules that were combined.
327
# an empty set of rules
328
# this is returned as a list of combined regex,rule sets, because
329
# python has a limit of 100 combined regexes.
330
compiled_rules = tree._combine_ignore_rules([])
331
self.assertEqual([], compiled_rules)
332
# one of each type of rule.
333
compiled_rules = tree._combine_ignore_rules(
334
["rule1", "rule/two", "./three"])[0]
335
# what type *is* the compiled regex to do an isinstance of ?
336
self.assertEqual(3, compiled_rules[0].groups)
338
{0:"rule1",1:"rule/two",2:"./three"},
341
def test__combine_ignore_rules_grouping(self):
342
tree = self.make_branch_and_tree('.')
343
# when there are too many rules, the output is split into groups of 100
345
for index in range(198):
347
self.assertEqual(2, len(tree._combine_ignore_rules(rules)))
349
def test__get_ignore_rules_as_regex(self):
350
tree = self.make_branch_and_tree('.')
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)