/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/tests/tree_implementations/__init__.py

  • Committer: Robert Collins
  • Date: 2008-08-20 02:07:36 UTC
  • mfrom: (3640 +trunk)
  • mto: This revision was merged to the branch mainline in revision 3682.
  • Revision ID: robertc@robertcollins.net-20080820020736-g2xe4921zzxtymle
Merge bzr.dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2006, 2007, 2008 Canonical Ltd
 
2
#
 
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.
 
7
#
 
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.
 
12
#
 
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
 
16
 
 
17
 
 
18
"""Tree implementation tests for bzr.
 
19
 
 
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:
 
22
 - tests/test_tree.py
 
23
 - tests/test_revision.py
 
24
 - tests/test_workingtree.py
 
25
 - tests/workingtree_implementations/*.py.
 
26
"""
 
27
 
 
28
from bzrlib import (
 
29
    errors,
 
30
    osutils,
 
31
    tests,
 
32
    transform,
 
33
    )
 
34
from bzrlib.transport import get_transport
 
35
from bzrlib.tests import (
 
36
                          adapt_modules,
 
37
                          default_transport,
 
38
                          TestCaseWithTransport,
 
39
                          TestSkipped,
 
40
                          )
 
41
from bzrlib.tests.bzrdir_implementations.test_bzrdir import TestCaseWithBzrDir
 
42
from bzrlib.tests.workingtree_implementations import (
 
43
    WorkingTreeTestProviderAdapter,
 
44
    )
 
45
from bzrlib.revisiontree import RevisionTree
 
46
from bzrlib.transform import TransformPreview
 
47
from bzrlib.workingtree import (
 
48
    WorkingTreeFormat,
 
49
    WorkingTreeFormat3,
 
50
    _legacy_formats,
 
51
    )
 
52
from bzrlib.workingtree_4 import (
 
53
    DirStateRevisionTree,
 
54
    WorkingTreeFormat4,
 
55
    )
 
56
 
 
57
 
 
58
def return_parameter(testcase, something):
 
59
    """A trivial thunk to return its input."""
 
60
    return something
 
61
 
 
62
 
 
63
def revision_tree_from_workingtree(testcase, tree):
 
64
    """Create a revision tree from a working tree."""
 
65
    revid = tree.commit('save tree', allow_pointless=True, recursive=None)
 
66
    return tree.branch.repository.revision_tree(revid)
 
67
 
 
68
 
 
69
def _dirstate_tree_from_workingtree(testcase, tree):
 
70
    revid = tree.commit('save tree', allow_pointless=True, recursive=None)
 
71
    return tree.basis_tree()
 
72
 
 
73
 
 
74
def preview_tree_pre(testcase, tree):
 
75
    tt = TransformPreview(tree)
 
76
    testcase.addCleanup(tt.finalize)
 
77
    preview_tree = tt.get_preview_tree()
 
78
    preview_tree.set_parent_ids(tree.get_parent_ids())
 
79
    return preview_tree
 
80
 
 
81
 
 
82
class TestTreeImplementationSupport(TestCaseWithTransport):
 
83
 
 
84
    def test_revision_tree_from_workingtree(self):
 
85
        tree = self.make_branch_and_tree('.')
 
86
        tree = revision_tree_from_workingtree(self, tree)
 
87
        self.assertIsInstance(tree, RevisionTree)
 
88
 
 
89
 
 
90
class TestCaseWithTree(TestCaseWithBzrDir):
 
91
 
 
92
    def make_branch_and_tree(self, relpath):
 
93
        made_control = self.make_bzrdir(relpath, format=
 
94
            self.workingtree_format._matchingbzrdir)
 
95
        made_control.create_repository()
 
96
        made_control.create_branch()
 
97
        return self.workingtree_format.initialize(made_control)
 
98
 
 
99
    def workingtree_to_test_tree(self, tree):
 
100
        return self._workingtree_to_test_tree(self, tree)
 
101
 
 
102
    def _convert_tree(self, tree, converter=None):
 
103
        """helper to convert using the converter or a supplied one."""
 
104
        # convert that to the final shape
 
105
        if converter is None:
 
106
            converter = self.workingtree_to_test_tree
 
107
        return converter(tree)
 
108
 
 
109
    def get_tree_no_parents_no_content(self, empty_tree, converter=None):
 
110
        """Make a tree with no parents and no contents from empty_tree.
 
111
        
 
112
        :param empty_tree: A working tree with no content and no parents to
 
113
            modify.
 
114
        """
 
115
        empty_tree.set_root_id('empty-root-id')
 
116
        return self._convert_tree(empty_tree, converter)
 
117
 
 
118
    def _make_abc_tree(self, tree):
 
119
        """setup an abc content tree."""
 
120
        files = ['a', 'b/', 'b/c']
 
121
        self.build_tree(files, line_endings='binary',
 
122
                        transport=tree.bzrdir.root_transport)
 
123
        tree.set_root_id('root-id')
 
124
        tree.add(files, ['a-id', 'b-id', 'c-id'])
 
125
 
 
126
    def get_tree_no_parents_abc_content(self, tree, converter=None):
 
127
        """return a test tree with a, b/, b/c contents."""
 
128
        self._make_abc_tree(tree)
 
129
        return self._convert_tree(tree, converter)
 
130
 
 
131
    def get_tree_no_parents_abc_content_2(self, tree, converter=None):
 
132
        """return a test tree with a, b/, b/c contents.
 
133
        
 
134
        This variation changes the content of 'a' to foobar\n.
 
135
        """
 
136
        self._make_abc_tree(tree)
 
137
        f = open(tree.basedir + '/a', 'wb')
 
138
        try:
 
139
            f.write('foobar\n')
 
140
        finally:
 
141
            f.close()
 
142
        return self._convert_tree(tree, converter)
 
143
 
 
144
    def get_tree_no_parents_abc_content_3(self, tree, converter=None):
 
145
        """return a test tree with a, b/, b/c contents.
 
146
        
 
147
        This variation changes the executable flag of b/c to True.
 
148
        """
 
149
        self._make_abc_tree(tree)
 
150
        tt = transform.TreeTransform(tree)
 
151
        trans_id = tt.trans_id_tree_path('b/c')
 
152
        tt.set_executability(True, trans_id)
 
153
        tt.apply()
 
154
        return self._convert_tree(tree, converter)
 
155
 
 
156
    def get_tree_no_parents_abc_content_4(self, tree, converter=None):
 
157
        """return a test tree with d, b/, b/c contents.
 
158
        
 
159
        This variation renames a to d.
 
160
        """
 
161
        self._make_abc_tree(tree)
 
162
        tree.rename_one('a', 'd')
 
163
        return self._convert_tree(tree, converter)
 
164
 
 
165
    def get_tree_no_parents_abc_content_5(self, tree, converter=None):
 
166
        """return a test tree with d, b/, b/c contents.
 
167
        
 
168
        This variation renames a to d and alters its content to 'bar\n'.
 
169
        """
 
170
        self._make_abc_tree(tree)
 
171
        tree.rename_one('a', 'd')
 
172
        f = open(tree.basedir + '/d', 'wb')
 
173
        try:
 
174
            f.write('bar\n')
 
175
        finally:
 
176
            f.close()
 
177
        return self._convert_tree(tree, converter)
 
178
 
 
179
    def get_tree_no_parents_abc_content_6(self, tree, converter=None):
 
180
        """return a test tree with a, b/, e contents.
 
181
        
 
182
        This variation renames b/c to e, and makes it executable.
 
183
        """
 
184
        self._make_abc_tree(tree)
 
185
        tt = transform.TreeTransform(tree)
 
186
        trans_id = tt.trans_id_tree_path('b/c')
 
187
        parent_trans_id = tt.trans_id_tree_path('')
 
188
        tt.adjust_path('e', parent_trans_id, trans_id)
 
189
        tt.set_executability(True, trans_id)
 
190
        tt.apply()
 
191
        return self._convert_tree(tree, converter)
 
192
 
 
193
    def get_tree_with_subdirs_and_all_content_types(self):
 
194
        """Return a test tree with subdirs and all content types.
 
195
        See get_tree_with_subdirs_and_all_supported_content_types for details.
 
196
        """
 
197
        return self.get_tree_with_subdirs_and_all_supported_content_types(True)
 
198
 
 
199
    def get_tree_with_subdirs_and_all_supported_content_types(self, symlinks):
 
200
        """Return a test tree with subdirs and all supported content types.
 
201
        Some content types may not be created on some platforms
 
202
        (like symlinks on native win32)
 
203
 
 
204
        :param  symlinks:   control is symlink should be created in the tree.
 
205
                            Note: if you wish to automatically set this
 
206
                            parameters depending on underlying system,
 
207
                            please use value returned
 
208
                            by bzrlib.osutils.has_symlinks() function.
 
209
 
 
210
        The returned tree has the following inventory:
 
211
            [('', inventory.ROOT_ID),
 
212
             ('0file', '2file'),
 
213
             ('1top-dir', '1top-dir'),
 
214
             (u'2utf\u1234file', u'0utf\u1234file'),
 
215
             ('symlink', 'symlink'),            # only if symlinks arg is True
 
216
             ('1top-dir/0file-in-1topdir', '1file-in-1topdir'),
 
217
             ('1top-dir/1dir-in-1topdir', '0dir-in-1topdir')]
 
218
        where each component has the type of its name -
 
219
        i.e. '1file..' is afile.
 
220
 
 
221
        note that the order of the paths and fileids is deliberately 
 
222
        mismatched to ensure that the result order is path based.
 
223
        """
 
224
        tree = self.make_branch_and_tree('.')
 
225
        paths = ['0file',
 
226
            '1top-dir/',
 
227
            u'2utf\u1234file',
 
228
            '1top-dir/0file-in-1topdir',
 
229
            '1top-dir/1dir-in-1topdir/'
 
230
            ]
 
231
        ids = [
 
232
            '2file',
 
233
            '1top-dir',
 
234
            u'0utf\u1234file'.encode('utf8'),
 
235
            '1file-in-1topdir',
 
236
            '0dir-in-1topdir'
 
237
            ]
 
238
        try:
 
239
            self.build_tree(paths)
 
240
        except UnicodeError:
 
241
            raise TestSkipped(
 
242
                'This platform does not support unicode file paths.')
 
243
        tree.add(paths, ids)
 
244
        tt = transform.TreeTransform(tree)
 
245
        if symlinks:
 
246
            root_transaction_id = tt.trans_id_tree_path('')
 
247
            tt.new_symlink('symlink',
 
248
                root_transaction_id, 'link-target', 'symlink')
 
249
        tt.apply()
 
250
        return self.workingtree_to_test_tree(tree)
 
251
 
 
252
    def get_tree_with_utf8(self, tree):
 
253
        """Generate a tree with a utf8 revision and unicode paths."""
 
254
        self._create_tree_with_utf8(tree)
 
255
        return self.workingtree_to_test_tree(tree)
 
256
 
 
257
    def _create_tree_with_utf8(self, tree):
 
258
        """Generate a tree with a utf8 revision and unicode paths."""
 
259
        paths = [u'',
 
260
                 u'f\xf6',
 
261
                 u'b\xe5r/',
 
262
                 u'b\xe5r/b\xe1z',
 
263
                ]
 
264
        # bzr itself does not create unicode file ids, but we want them for
 
265
        # testing.
 
266
        file_ids = ['TREE_ROOT',
 
267
                    'f\xc3\xb6-id',
 
268
                    'b\xc3\xa5r-id',
 
269
                    'b\xc3\xa1z-id',
 
270
                   ]
 
271
        try:
 
272
            self.build_tree(paths[1:])
 
273
        except UnicodeError:
 
274
            raise tests.TestSkipped('filesystem does not support unicode.')
 
275
        if tree.get_root_id() is None:
 
276
            # Some trees do not have a root yet.
 
277
            tree.add(paths, file_ids)
 
278
        else:
 
279
            # Some trees will already have a root
 
280
            tree.set_root_id(file_ids[0])
 
281
            tree.add(paths[1:], file_ids[1:])
 
282
        try:
 
283
            tree.commit(u'in\xedtial', rev_id=u'r\xe9v-1'.encode('utf8'))
 
284
        except errors.NonAsciiRevisionId:
 
285
            raise tests.TestSkipped('non-ascii revision ids not supported')
 
286
 
 
287
    def get_tree_with_merged_utf8(self, tree):
 
288
        """Generate a tree with utf8 ancestors."""
 
289
        self._create_tree_with_utf8(tree)
 
290
        tree2 = tree.bzrdir.sprout('tree2').open_workingtree()
 
291
        self.build_tree([u'tree2/b\xe5r/z\xf7z'])
 
292
        tree2.add([u'b\xe5r/z\xf7z'], [u'z\xf7z-id'.encode('utf-8')])
 
293
        tree2.commit(u'to m\xe9rge', rev_id=u'r\xe9v-2'.encode('utf8'))
 
294
 
 
295
        tree.merge_from_branch(tree2.branch)
 
296
        tree.commit(u'm\xe9rge', rev_id=u'r\xe9v-3'.encode('utf8'))
 
297
        return self.workingtree_to_test_tree(tree)
 
298
 
 
299
 
 
300
class TreeTestProviderAdapter(WorkingTreeTestProviderAdapter):
 
301
    """Generate test suites for each Tree implementation in bzrlib.
 
302
 
 
303
    Currently this covers all working tree formats, and RevisionTree and
 
304
    DirStateRevisionTree by committing a working tree to create the revision
 
305
    tree.
 
306
    """
 
307
 
 
308
    def __init__(self, transport_server, transport_readonly_server, formats):
 
309
        """Create a TreeTestProviderAdapter.
 
310
 
 
311
        :param formats: [workingtree_format]
 
312
        """
 
313
        super(TreeTestProviderAdapter, self).__init__(transport_server,
 
314
            transport_readonly_server, formats)
 
315
        # now adjust the scenarios and add the non-working-tree tree scenarios.
 
316
        for scenario in self.scenarios:
 
317
            # for working tree adapted tests, preserve the tree
 
318
            scenario[1]["_workingtree_to_test_tree"] = return_parameter
 
319
        # add RevisionTree scenario
 
320
        self.scenarios.append(self.create_tree_scenario(RevisionTree.__name__,
 
321
                              revision_tree_from_workingtree,))
 
322
 
 
323
        # also test WorkingTree4's RevisionTree implementation which is
 
324
        # specialised.
 
325
        self.scenarios.append(self.create_tree_scenario(
 
326
            DirStateRevisionTree.__name__, _dirstate_tree_from_workingtree,
 
327
            WorkingTreeFormat4()))
 
328
        self.scenarios.append(self.create_tree_scenario('PreviewTree',
 
329
            preview_tree_pre))
 
330
 
 
331
    def create_tree_scenario(self, name, converter, workingtree_format=None):
 
332
        """Create a scenario for the specified converter
 
333
 
 
334
        :param name: The name to append to tests using this converter
 
335
        :param converter: A function that converts a workingtree into the
 
336
            desired format.
 
337
        :param workingtree_format: The particular workingtree format to
 
338
            convert from.
 
339
        :return: a (name, options) tuple, where options is a dict of values
 
340
            to be used as members of the TestCase.
 
341
        """
 
342
        if workingtree_format is None:
 
343
            workingtree_format = WorkingTreeFormat._default_format
 
344
        scenario_options = WorkingTreeTestProviderAdapter.create_scenario(self,
 
345
            workingtree_format)[1]
 
346
        scenario_options["_workingtree_to_test_tree"] = converter
 
347
        return name, scenario_options
 
348
 
 
349
 
 
350
def load_tests(basic_tests, module, loader):
 
351
    result = loader.suiteClass()
 
352
    # add the tests for this module
 
353
    result.addTests(basic_tests)
 
354
 
 
355
    test_tree_implementations = [
 
356
        'bzrlib.tests.tree_implementations.test_annotate_iter',
 
357
        'bzrlib.tests.tree_implementations.test_get_file_mtime',
 
358
        'bzrlib.tests.tree_implementations.test_get_root_id',
 
359
        'bzrlib.tests.tree_implementations.test_get_symlink_target',
 
360
        'bzrlib.tests.tree_implementations.test_inv',
 
361
        'bzrlib.tests.tree_implementations.test_iter_search_rules',
 
362
        'bzrlib.tests.tree_implementations.test_list_files',
 
363
        'bzrlib.tests.tree_implementations.test_path_content_summary',
 
364
        'bzrlib.tests.tree_implementations.test_revision_tree',
 
365
        'bzrlib.tests.tree_implementations.test_test_trees',
 
366
        'bzrlib.tests.tree_implementations.test_tree',
 
367
        'bzrlib.tests.tree_implementations.test_walkdirs',
 
368
        ]
 
369
 
 
370
    adapter = TreeTestProviderAdapter(
 
371
        default_transport,
 
372
        # None here will cause a readonly decorator to be created
 
373
        # by the TestCaseWithTransport.get_readonly_transport method.
 
374
        None,
 
375
        WorkingTreeFormat._formats.values() + _legacy_formats)
 
376
 
 
377
    # add the tests for the sub modules
 
378
    adapt_modules(test_tree_implementations, adapter, loader, result)
 
379
    return result