/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

Merge with prepare-shelf

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