1
# Copyright (C) 2006, 2007 Canonical Ltd
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
# GNU General Public License for more details.
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
"""Tree implementation tests for bzr.
20
These test the conformance of all the tree variations to the expected API.
21
Specific tests for individual variations are in other places such as:
23
- tests/test_revision.py
24
- tests/test_workingtree.py
25
- tests/workingtree_implementations/*.py.
34
from bzrlib.transport import get_transport
35
from bzrlib.tests import (
38
TestCaseWithTransport,
43
from bzrlib.tests.bzrdir_implementations.test_bzrdir import TestCaseWithBzrDir
44
from bzrlib.revisiontree import RevisionTree
45
from bzrlib.workingtree import (
48
WorkingTreeTestProviderAdapter,
51
from bzrlib.workingtree_4 import (
57
def return_parameter(something):
58
"""A trivial thunk to return its input."""
62
def revision_tree_from_workingtree(tree):
63
"""Create a revision tree from a working tree."""
64
revid = tree.commit('save tree', allow_pointless=True, recursive=None)
65
return tree.branch.repository.revision_tree(revid)
68
def _dirstate_tree_from_workingtree(tree):
69
revid = tree.commit('save tree', allow_pointless=True)
70
return tree.basis_tree()
73
class TestTreeImplementationSupport(TestCaseWithTransport):
75
def test_revision_tree_from_workingtree(self):
76
tree = self.make_branch_and_tree('.')
77
tree = revision_tree_from_workingtree(tree)
78
self.assertIsInstance(tree, RevisionTree)
81
class TestCaseWithTree(TestCaseWithBzrDir):
83
def make_branch_and_tree(self, relpath):
84
made_control = self.make_bzrdir(relpath, format=
85
self.workingtree_format._matchingbzrdir)
86
made_control.create_repository()
87
made_control.create_branch()
88
return self.workingtree_format.initialize(made_control)
90
def _convert_tree(self, tree, converter=None):
91
"""helper to convert using the converter or a supplied one."""
92
# convert that to the final shape
94
converter = self.workingtree_to_test_tree
95
return converter(tree)
97
def get_tree_no_parents_no_content(self, empty_tree, converter=None):
98
"""Make a tree with no parents and no contents from empty_tree.
100
:param empty_tree: A working tree with no content and no parents to
103
empty_tree.set_root_id('empty-root-id')
104
return self._convert_tree(empty_tree, converter)
106
def _make_abc_tree(self, tree):
107
"""setup an abc content tree."""
108
files = ['a', 'b/', 'b/c']
109
self.build_tree(files, line_endings='binary',
110
transport=tree.bzrdir.root_transport)
111
tree.set_root_id('root-id')
112
tree.add(files, ['a-id', 'b-id', 'c-id'])
114
def get_tree_no_parents_abc_content(self, tree, converter=None):
115
"""return a test tree with a, b/, b/c contents."""
116
self._make_abc_tree(tree)
117
return self._convert_tree(tree, converter)
119
def get_tree_no_parents_abc_content_2(self, tree, converter=None):
120
"""return a test tree with a, b/, b/c contents.
122
This variation changes the content of 'a' to foobar\n.
124
self._make_abc_tree(tree)
125
f = open(tree.basedir + '/a', 'wb')
130
return self._convert_tree(tree, converter)
132
def get_tree_no_parents_abc_content_3(self, tree, converter=None):
133
"""return a test tree with a, b/, b/c contents.
135
This variation changes the executable flag of b/c to True.
137
self._make_abc_tree(tree)
138
tt = transform.TreeTransform(tree)
139
trans_id = tt.trans_id_tree_path('b/c')
140
tt.set_executability(True, trans_id)
142
return self._convert_tree(tree, converter)
144
def get_tree_no_parents_abc_content_4(self, tree, converter=None):
145
"""return a test tree with d, b/, b/c contents.
147
This variation renames a to d.
149
self._make_abc_tree(tree)
150
tree.rename_one('a', 'd')
151
return self._convert_tree(tree, converter)
153
def get_tree_no_parents_abc_content_5(self, tree, converter=None):
154
"""return a test tree with d, b/, b/c contents.
156
This variation renames a to d and alters its content to 'bar\n'.
158
self._make_abc_tree(tree)
159
tree.rename_one('a', 'd')
160
f = open(tree.basedir + '/d', 'wb')
165
return self._convert_tree(tree, converter)
167
def get_tree_no_parents_abc_content_6(self, tree, converter=None):
168
"""return a test tree with a, b/, e contents.
170
This variation renames b/c to e, and makes it executable.
172
self._make_abc_tree(tree)
173
tt = transform.TreeTransform(tree)
174
trans_id = tt.trans_id_tree_path('b/c')
175
parent_trans_id = tt.trans_id_tree_path('')
176
tt.adjust_path('e', parent_trans_id, trans_id)
177
tt.set_executability(True, trans_id)
179
return self._convert_tree(tree, converter)
181
def get_tree_with_subdirs_and_all_content_types(self):
182
"""Return a test tree with subdirs and all content types.
184
The returned tree has the following inventory:
185
[('', inventory.ROOT_ID),
187
('1top-dir', '1top-dir'),
188
(u'2utf\u1234file', u'0utf\u1234file'),
189
('symlink', 'symlink'),
190
('1top-dir/0file-in-1topdir', '1file-in-1topdir'),
191
('1top-dir/1dir-in-1topdir', '0dir-in-1topdir')]
192
where each component has the type of its name - i.e. '1file..' is afile.
194
note that the order of the paths and fileids is deliberately
195
mismatched to ensure that the result order is path based.
197
tree = self.make_branch_and_tree('.')
201
'1top-dir/0file-in-1topdir',
202
'1top-dir/1dir-in-1topdir/'
207
u'0utf\u1234file'.encode('utf8'),
212
self.build_tree(paths)
215
'This platform does not support unicode file paths.')
217
tt = transform.TreeTransform(tree)
218
root_transaction_id = tt.trans_id_tree_path('')
219
tt.new_symlink('symlink',
220
root_transaction_id, 'link-target', 'symlink')
222
return self.workingtree_to_test_tree(tree)
224
def get_tree_with_utf8(self, tree):
225
"""Generate a tree with a utf8 revision and unicode paths."""
226
self._create_tree_with_utf8(tree)
227
return self.workingtree_to_test_tree(tree)
229
def _create_tree_with_utf8(self, tree):
230
"""Generate a tree with a utf8 revision and unicode paths."""
236
# bzr itself does not create unicode file ids, but we want them for
238
file_ids = ['TREE_ROOT',
244
self.build_tree(paths[1:])
246
raise tests.TestSkipped('filesystem does not support unicode.')
247
if tree.path2id('') is None:
248
# Some trees do not have a root yet.
249
tree.add(paths, file_ids)
251
# Some trees will already have a root
252
tree.set_root_id(file_ids[0])
253
tree.add(paths[1:], file_ids[1:])
255
tree.commit(u'in\xedtial', rev_id=u'r\xe9v-1'.encode('utf8'))
256
except errors.NonAsciiRevisionId:
257
raise tests.TestSkipped('non-ascii revision ids not supported')
259
def get_tree_with_merged_utf8(self, tree):
260
"""Generate a tree with utf8 ancestors."""
261
self._create_tree_with_utf8(tree)
262
tree2 = tree.bzrdir.sprout('tree2').open_workingtree()
263
self.build_tree([u'tree2/b\xe5r/z\xf7z'])
264
self.callDeprecated([osutils._file_id_warning],
265
tree2.add, [u'b\xe5r/z\xf7z'], [u'z\xf7z-id'])
266
tree2.commit(u'to m\xe9rge', rev_id=u'r\xe9v-2'.encode('utf8'))
268
tree.merge_from_branch(tree2.branch)
269
tree.commit(u'm\xe9rge', rev_id=u'r\xe9v-3'.encode('utf8'))
270
return self.workingtree_to_test_tree(tree)
273
class TreeTestProviderAdapter(WorkingTreeTestProviderAdapter):
274
"""Generate test suites for each Tree implementation in bzrlib.
276
Currently this covers all working tree formats, and RevisionTree by
277
committing a working tree to create the revision tree.
280
def adapt(self, test):
281
result = super(TreeTestProviderAdapter, self).adapt(test)
282
for adapted_test in result:
283
# for working tree adapted tests, preserve the tree
284
adapted_test.workingtree_to_test_tree = return_parameter
285
# this is the default in that it's used to test the generic InterTree
287
default_format = WorkingTreeFormat3()
288
revision_tree_test = self._clone_test(
290
default_format._matchingbzrdir,
292
RevisionTree.__name__)
293
revision_tree_test.workingtree_to_test_tree = revision_tree_from_workingtree
294
result.addTest(revision_tree_test)
295
# also explicity test WorkingTree4 against everything
296
dirstate_format = WorkingTreeFormat4()
297
dirstate_revision_tree_test = self._clone_test(
299
dirstate_format._matchingbzrdir,
301
DirStateRevisionTree.__name__)
302
dirstate_revision_tree_test.workingtree_to_test_tree = _dirstate_tree_from_workingtree
303
result.addTest(dirstate_revision_tree_test)
309
test_tree_implementations = [
310
'bzrlib.tests.tree_implementations.test_get_file_mtime',
311
'bzrlib.tests.tree_implementations.test_get_symlink_target',
312
'bzrlib.tests.tree_implementations.test_list_files',
313
'bzrlib.tests.tree_implementations.test_revision_tree',
314
'bzrlib.tests.tree_implementations.test_test_trees',
315
'bzrlib.tests.tree_implementations.test_tree',
316
'bzrlib.tests.tree_implementations.test_walkdirs',
318
adapter = TreeTestProviderAdapter(
320
# None here will cause a readonly decorator to be created
321
# by the TestCaseWithTransport.get_readonly_transport method.
323
[(format, format._matchingbzrdir) for format in
324
WorkingTreeFormat._formats.values() + _legacy_formats])
325
loader = TestLoader()
326
adapt_modules(test_tree_implementations, adapter, loader, result)
327
result.addTests(loader.loadTestsFromModuleNames(['bzrlib.tests.tree_implementations']))