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)
206
class TestFormat2WorkingTree(TestCaseWithTransport):
207
"""Tests that are specific to format 2 trees."""
209
def create_format2_tree(self, url):
210
return self.make_branch_and_tree(
211
url, format=bzrlib.bzrdir.BzrDirFormat6())
213
def test_conflicts(self):
214
# test backwards compatability
215
tree = self.create_format2_tree('.')
216
self.assertRaises(errors.UnsupportedOperation, tree.set_conflicts,
218
file('lala.BASE', 'wb').write('labase')
219
expected = conflicts.ContentsConflict('lala')
220
self.assertEqual(list(tree.conflicts()), [expected])
221
file('lala', 'wb').write('la')
222
tree.add('lala', 'lala-id')
223
expected = conflicts.ContentsConflict('lala', file_id='lala-id')
224
self.assertEqual(list(tree.conflicts()), [expected])
225
file('lala.THIS', 'wb').write('lathis')
226
file('lala.OTHER', 'wb').write('laother')
227
# When "text conflict"s happen, stem, THIS and OTHER are text
228
expected = conflicts.TextConflict('lala', file_id='lala-id')
229
self.assertEqual(list(tree.conflicts()), [expected])
230
os.unlink('lala.OTHER')
231
os.mkdir('lala.OTHER')
232
expected = conflicts.ContentsConflict('lala', file_id='lala-id')
233
self.assertEqual(list(tree.conflicts()), [expected])
236
class TestNonFormatSpecificCode(TestCaseWithTransport):
237
"""This class contains tests of workingtree that are not format specific."""
240
def test_gen_file_id(self):
241
self.assertStartsWith(bzrlib.workingtree.gen_file_id('bar'), 'bar-')
242
self.assertStartsWith(bzrlib.workingtree.gen_file_id('Mwoo oof\t m'), 'Mwoooofm-')
243
self.assertStartsWith(bzrlib.workingtree.gen_file_id('..gam.py'), 'gam.py-')
244
self.assertStartsWith(bzrlib.workingtree.gen_file_id('..Mwoo oof\t m'), 'Mwoooofm-')
246
def test_next_id_suffix(self):
247
bzrlib.workingtree._gen_id_suffix = None
248
bzrlib.workingtree._next_id_suffix()
249
self.assertNotEqual(None, bzrlib.workingtree._gen_id_suffix)
250
bzrlib.workingtree._gen_id_suffix = "foo-"
251
bzrlib.workingtree._gen_id_serial = 1
252
self.assertEqual("foo-2", bzrlib.workingtree._next_id_suffix())
253
self.assertEqual("foo-3", bzrlib.workingtree._next_id_suffix())
254
self.assertEqual("foo-4", bzrlib.workingtree._next_id_suffix())
255
self.assertEqual("foo-5", bzrlib.workingtree._next_id_suffix())
256
self.assertEqual("foo-6", bzrlib.workingtree._next_id_suffix())
257
self.assertEqual("foo-7", bzrlib.workingtree._next_id_suffix())
258
self.assertEqual("foo-8", bzrlib.workingtree._next_id_suffix())
259
self.assertEqual("foo-9", bzrlib.workingtree._next_id_suffix())
260
self.assertEqual("foo-10", bzrlib.workingtree._next_id_suffix())
262
def test__translate_ignore_rule(self):
263
tree = self.make_branch_and_tree('.')
264
# translation should return the regex, the number of groups in it,
265
# and the original rule in a tuple.
266
# there are three sorts of ignore rules:
267
# root only - regex is the rule itself without the leading ./
270
tree._translate_ignore_rule("./rootdirrule"))
271
# full path - regex is the rule itself
273
"(path\\/to\\/file$)",
274
tree._translate_ignore_rule("path/to/file"))
275
# basename only rule - regex is a rule that ignores everything up
276
# to the last / in the filename
278
"((?:.*/)?(?!.*/)basenamerule$)",
279
tree._translate_ignore_rule("basenamerule"))
281
def test__combine_ignore_rules(self):
282
tree = self.make_branch_and_tree('.')
283
# the combined ignore regexs need the outer group indices
284
# placed in a dictionary with the rules that were combined.
285
# an empty set of rules
286
# this is returned as a list of combined regex,rule sets, because
287
# python has a limit of 100 combined regexes.
288
compiled_rules = tree._combine_ignore_rules([])
289
self.assertEqual([], compiled_rules)
290
# one of each type of rule.
291
compiled_rules = tree._combine_ignore_rules(
292
["rule1", "rule/two", "./three"])[0]
293
# what type *is* the compiled regex to do an isinstance of ?
294
self.assertEqual(3, compiled_rules[0].groups)
296
{0:"rule1",1:"rule/two",2:"./three"},
299
def test__combine_ignore_rules_grouping(self):
300
tree = self.make_branch_and_tree('.')
301
# when there are too many rules, the output is split into groups of 100
303
for index in range(198):
305
self.assertEqual(2, len(tree._combine_ignore_rules(rules)))
307
def test__get_ignore_rules_as_regex(self):
308
tree = self.make_branch_and_tree('.')
309
# test against the default rules.
310
reference_output = tree._combine_ignore_rules(bzrlib.DEFAULT_IGNORE)[0]
311
regex_rules = tree._get_ignore_rules_as_regex()[0]
312
self.assertEqual(len(reference_output[1]), regex_rules[0].groups)
313
self.assertEqual(reference_output[1], regex_rules[1])