15
15
# along with this program; if not, write to the Free Software
16
16
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
from cStringIO import StringIO
19
22
from bzrlib.branch import Branch
20
from bzrlib.selftest import TestCaseInTempDir
23
from bzrlib import bzrdir, conflicts, errors, workingtree
24
from bzrlib.bzrdir import BzrDir
25
from bzrlib.errors import NotBranchError, NotVersionedError
26
from bzrlib.lockdir import LockDir
27
from bzrlib.osutils import pathjoin, getcwd, has_symlinks
28
from bzrlib.tests import TestCaseWithTransport, TestSkipped
21
29
from bzrlib.trace import mutter
22
from bzrlib.workingtree import TreeEntry, TreeDirectory, TreeFile, TreeLink
30
from bzrlib.transport import get_transport
31
from bzrlib.workingtree import (TreeEntry, TreeDirectory, TreeFile, TreeLink,
24
class TestTreeDirectory(TestCaseInTempDir):
34
class TestTreeDirectory(TestCaseWithTransport):
26
36
def test_kind_character(self):
27
37
self.assertEqual(TreeDirectory().kind_character(), '/')
30
class TestTreeEntry(TestCaseInTempDir):
40
class TestTreeEntry(TestCaseWithTransport):
32
42
def test_kind_character(self):
33
43
self.assertEqual(TreeEntry().kind_character(), '???')
36
class TestTreeFile(TestCaseInTempDir):
46
class TestTreeFile(TestCaseWithTransport):
38
48
def test_kind_character(self):
39
49
self.assertEqual(TreeFile().kind_character(), '')
42
class TestTreeLink(TestCaseInTempDir):
52
class TestTreeLink(TestCaseWithTransport):
44
54
def test_kind_character(self):
45
55
self.assertEqual(TreeLink().kind_character(), '')
48
class TestWorkingTree(TestCaseInTempDir):
50
def test_listfiles(self):
51
branch = Branch.initialize('.')
53
print >> open('file', 'w'), "content"
54
os.symlink('target', 'symlink')
55
tree = branch.working_tree()
56
files = list(tree.list_files())
57
self.assertEqual(files[0], ('dir', '?', 'directory', None, TreeDirectory()))
58
self.assertEqual(files[1], ('file', '?', 'file', None, TreeFile()))
59
self.assertEqual(files[2], ('symlink', '?', 'symlink', None, TreeLink()))
58
class TestDefaultFormat(TestCaseWithTransport):
60
def test_get_set_default_format(self):
61
old_format = workingtree.WorkingTreeFormat.get_default_format()
63
self.assertTrue(isinstance(old_format, workingtree.WorkingTreeFormat3))
64
workingtree.WorkingTreeFormat.set_default_format(SampleTreeFormat())
66
# the default branch format is used by the meta dir format
67
# which is not the default bzrdir format at this point
68
dir = bzrdir.BzrDirMetaFormat1().initialize('.')
69
dir.create_repository()
71
result = dir.create_workingtree()
72
self.assertEqual(result, 'A tree')
74
workingtree.WorkingTreeFormat.set_default_format(old_format)
75
self.assertEqual(old_format, workingtree.WorkingTreeFormat.get_default_format())
78
class SampleTreeFormat(workingtree.WorkingTreeFormat):
81
this format is initializable, unsupported to aid in testing the
82
open and open_downlevel routines.
85
def get_format_string(self):
86
"""See WorkingTreeFormat.get_format_string()."""
87
return "Sample tree format."
89
def initialize(self, a_bzrdir, revision_id=None):
90
"""Sample branches cannot be created."""
91
t = a_bzrdir.get_workingtree_transport(self)
92
t.put('format', StringIO(self.get_format_string()))
95
def is_supported(self):
98
def open(self, transport, _found=False):
102
class TestWorkingTreeFormat(TestCaseWithTransport):
103
"""Tests for the WorkingTreeFormat facility."""
105
def test_find_format(self):
106
# is the right format object found for a working tree?
107
# create a branch with a few known format objects.
108
self.build_tree(["foo/", "bar/"])
109
def check_format(format, url):
110
dir = format._matchingbzrdir.initialize(url)
111
dir.create_repository()
113
format.initialize(dir)
114
t = get_transport(url)
115
found_format = workingtree.WorkingTreeFormat.find_format(dir)
116
self.failUnless(isinstance(found_format, format.__class__))
117
check_format(workingtree.WorkingTreeFormat3(), "bar")
119
def test_find_format_no_tree(self):
120
dir = bzrdir.BzrDirMetaFormat1().initialize('.')
121
self.assertRaises(errors.NoWorkingTree,
122
workingtree.WorkingTreeFormat.find_format,
125
def test_find_format_unknown_format(self):
126
dir = bzrdir.BzrDirMetaFormat1().initialize('.')
127
dir.create_repository()
129
SampleTreeFormat().initialize(dir)
130
self.assertRaises(errors.UnknownFormatError,
131
workingtree.WorkingTreeFormat.find_format,
134
def test_register_unregister_format(self):
135
format = SampleTreeFormat()
137
dir = bzrdir.BzrDirMetaFormat1().initialize('.')
138
dir.create_repository()
141
format.initialize(dir)
142
# register a format for it.
143
workingtree.WorkingTreeFormat.register_format(format)
144
# which branch.Open will refuse (not supported)
145
self.assertRaises(errors.UnsupportedFormatError, workingtree.WorkingTree.open, '.')
146
# but open_downlevel will work
147
self.assertEqual(format.open(dir), workingtree.WorkingTree.open_downlevel('.'))
148
# unregister the format
149
workingtree.WorkingTreeFormat.unregister_format(format)
152
class TestWorkingTreeFormat3(TestCaseWithTransport):
153
"""Tests specific to WorkingTreeFormat3."""
155
def test_disk_layout(self):
156
control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
157
control.create_repository()
158
control.create_branch()
159
tree = workingtree.WorkingTreeFormat3().initialize(control)
161
# format 'Bazaar-NG Working Tree format 3'
162
# inventory = blank inventory
163
# pending-merges = ''
165
# no inventory.basis yet
166
t = control.get_workingtree_transport(None)
167
self.assertEqualDiff('Bazaar-NG Working Tree format 3',
168
t.get('format').read())
169
self.assertEqualDiff('<inventory format="5">\n'
171
t.get('inventory').read())
172
self.assertEqualDiff('### bzr hashcache v5\n',
173
t.get('stat-cache').read())
174
self.assertFalse(t.has('inventory.basis'))
175
# no last-revision file means 'None' or 'NULLREVISION'
176
self.assertFalse(t.has('last-revision'))
177
# TODO RBC 20060210 do a commit, check the inventory.basis is created
178
# correctly and last-revision file becomes present.
180
def test_uses_lockdir(self):
181
"""WorkingTreeFormat3 uses its own LockDir:
183
- lock is a directory
184
- when the WorkingTree is locked, LockDir can see that
186
t = self.get_transport()
188
dir = bzrdir.BzrDirMetaFormat1().initialize(url)
189
repo = dir.create_repository()
190
branch = dir.create_branch()
192
tree = workingtree.WorkingTreeFormat3().initialize(dir)
193
except errors.NotLocalUrl:
194
raise TestSkipped('Not a local URL')
195
self.assertIsDirectory('.bzr', t)
196
self.assertIsDirectory('.bzr/checkout', t)
197
self.assertIsDirectory('.bzr/checkout/lock', t)
198
our_lock = LockDir(t, '.bzr/checkout/lock')
199
self.assertEquals(our_lock.peek(), None)
201
self.assertTrue(our_lock.peek())
203
self.assertEquals(our_lock.peek(), None)
205
def test_missing_pending_merges(self):
206
control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
207
control.create_repository()
208
control.create_branch()
209
tree = workingtree.WorkingTreeFormat3().initialize(control)
210
tree._control_files._transport.delete("pending-merges")
211
self.assertEqual([], tree.pending_merges())
214
class TestFormat2WorkingTree(TestCaseWithTransport):
215
"""Tests that are specific to format 2 trees."""
217
def create_format2_tree(self, url):
218
return self.make_branch_and_tree(
219
url, format=bzrlib.bzrdir.BzrDirFormat6())
221
def test_conflicts(self):
222
# test backwards compatability
223
tree = self.create_format2_tree('.')
224
self.assertRaises(errors.UnsupportedOperation, tree.set_conflicts,
226
file('lala.BASE', 'wb').write('labase')
227
expected = conflicts.ContentsConflict('lala')
228
self.assertEqual(list(tree.conflicts()), [expected])
229
file('lala', 'wb').write('la')
230
tree.add('lala', 'lala-id')
231
expected = conflicts.ContentsConflict('lala', file_id='lala-id')
232
self.assertEqual(list(tree.conflicts()), [expected])
233
file('lala.THIS', 'wb').write('lathis')
234
file('lala.OTHER', 'wb').write('laother')
235
# When "text conflict"s happen, stem, THIS and OTHER are text
236
expected = conflicts.TextConflict('lala', file_id='lala-id')
237
self.assertEqual(list(tree.conflicts()), [expected])
238
os.unlink('lala.OTHER')
239
os.mkdir('lala.OTHER')
240
expected = conflicts.ContentsConflict('lala', file_id='lala-id')
241
self.assertEqual(list(tree.conflicts()), [expected])
244
class TestNonFormatSpecificCode(TestCaseWithTransport):
245
"""This class contains tests of workingtree that are not format specific."""
248
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-')
254
def test_next_id_suffix(self):
255
bzrlib.workingtree._gen_id_suffix = None
256
bzrlib.workingtree._next_id_suffix()
257
self.assertNotEqual(None, bzrlib.workingtree._gen_id_suffix)
258
bzrlib.workingtree._gen_id_suffix = "foo-"
259
bzrlib.workingtree._gen_id_serial = 1
260
self.assertEqual("foo-2", bzrlib.workingtree._next_id_suffix())
261
self.assertEqual("foo-3", bzrlib.workingtree._next_id_suffix())
262
self.assertEqual("foo-4", bzrlib.workingtree._next_id_suffix())
263
self.assertEqual("foo-5", bzrlib.workingtree._next_id_suffix())
264
self.assertEqual("foo-6", bzrlib.workingtree._next_id_suffix())
265
self.assertEqual("foo-7", bzrlib.workingtree._next_id_suffix())
266
self.assertEqual("foo-8", bzrlib.workingtree._next_id_suffix())
267
self.assertEqual("foo-9", bzrlib.workingtree._next_id_suffix())
268
self.assertEqual("foo-10", bzrlib.workingtree._next_id_suffix())
270
def test__translate_ignore_rule(self):
271
tree = self.make_branch_and_tree('.')
272
# translation should return the regex, the number of groups in it,
273
# and the original rule in a tuple.
274
# there are three sorts of ignore rules:
275
# root only - regex is the rule itself without the leading ./
278
tree._translate_ignore_rule("./rootdirrule"))
279
# full path - regex is the rule itself
281
"(path\\/to\\/file$)",
282
tree._translate_ignore_rule("path/to/file"))
283
# basename only rule - regex is a rule that ignores everything up
284
# to the last / in the filename
286
"((?:.*/)?(?!.*/)basenamerule$)",
287
tree._translate_ignore_rule("basenamerule"))
289
def test__combine_ignore_rules(self):
290
tree = self.make_branch_and_tree('.')
291
# the combined ignore regexs need the outer group indices
292
# placed in a dictionary with the rules that were combined.
293
# an empty set of rules
294
# this is returned as a list of combined regex,rule sets, because
295
# python has a limit of 100 combined regexes.
296
compiled_rules = tree._combine_ignore_rules([])
297
self.assertEqual([], compiled_rules)
298
# one of each type of rule.
299
compiled_rules = tree._combine_ignore_rules(
300
["rule1", "rule/two", "./three"])[0]
301
# what type *is* the compiled regex to do an isinstance of ?
302
self.assertEqual(3, compiled_rules[0].groups)
304
{0:"rule1",1:"rule/two",2:"./three"},
307
def test__combine_ignore_rules_grouping(self):
308
tree = self.make_branch_and_tree('.')
309
# when there are too many rules, the output is split into groups of 100
311
for index in range(198):
313
self.assertEqual(2, len(tree._combine_ignore_rules(rules)))
315
def test__get_ignore_rules_as_regex(self):
316
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])