~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

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

  • Committer: Robert Collins
  • Date: 2007-03-08 04:06:06 UTC
  • mfrom: (2323.1.1 integration)
  • mto: This revision was merged to the branch mainline in revision 2442.
  • Revision ID: robertc@robertcollins.net-20070308040606-84gsniv56huiyjt4
Merge bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2006, 2007 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
                          TestLoader,
 
40
                          TestSkipped,
 
41
                          TestSuite,
 
42
                          )
 
43
from bzrlib.tests.bzrdir_implementations.test_bzrdir import TestCaseWithBzrDir
 
44
from bzrlib.revisiontree import RevisionTree
 
45
from bzrlib.workingtree import (
 
46
    WorkingTreeFormat,
 
47
    WorkingTreeFormat3,
 
48
    WorkingTreeTestProviderAdapter,
 
49
    _legacy_formats,
 
50
    )
 
51
from bzrlib.workingtree_4 import (
 
52
    DirStateRevisionTree,
 
53
    WorkingTreeFormat4,
 
54
    )
 
55
 
 
56
 
 
57
def return_parameter(something):
 
58
    """A trivial thunk to return its input."""
 
59
    return something
 
60
 
 
61
 
 
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)
 
66
 
 
67
 
 
68
def _dirstate_tree_from_workingtree(tree):
 
69
    revid = tree.commit('save tree', allow_pointless=True)
 
70
    return tree.basis_tree()
 
71
 
 
72
 
 
73
class TestTreeImplementationSupport(TestCaseWithTransport):
 
74
 
 
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)
 
79
 
 
80
 
 
81
class TestCaseWithTree(TestCaseWithBzrDir):
 
82
 
 
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)
 
89
 
 
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
 
93
        if converter is None:
 
94
            converter = self.workingtree_to_test_tree
 
95
        return converter(tree)
 
96
 
 
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.
 
99
        
 
100
        :param empty_tree: A working tree with no content and no parents to
 
101
            modify.
 
102
        """
 
103
        empty_tree.set_root_id('empty-root-id')
 
104
        return self._convert_tree(empty_tree, converter)
 
105
 
 
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'])
 
113
 
 
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)
 
118
 
 
119
    def get_tree_no_parents_abc_content_2(self, tree, converter=None):
 
120
        """return a test tree with a, b/, b/c contents.
 
121
        
 
122
        This variation changes the content of 'a' to foobar\n.
 
123
        """
 
124
        self._make_abc_tree(tree)
 
125
        f = open(tree.basedir + '/a', 'wb')
 
126
        try:
 
127
            f.write('foobar\n')
 
128
        finally:
 
129
            f.close()
 
130
        return self._convert_tree(tree, converter)
 
131
 
 
132
    def get_tree_no_parents_abc_content_3(self, tree, converter=None):
 
133
        """return a test tree with a, b/, b/c contents.
 
134
        
 
135
        This variation changes the executable flag of b/c to True.
 
136
        """
 
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)
 
141
        tt.apply()
 
142
        return self._convert_tree(tree, converter)
 
143
 
 
144
    def get_tree_no_parents_abc_content_4(self, tree, converter=None):
 
145
        """return a test tree with d, b/, b/c contents.
 
146
        
 
147
        This variation renames a to d.
 
148
        """
 
149
        self._make_abc_tree(tree)
 
150
        tree.rename_one('a', 'd')
 
151
        return self._convert_tree(tree, converter)
 
152
 
 
153
    def get_tree_no_parents_abc_content_5(self, tree, converter=None):
 
154
        """return a test tree with d, b/, b/c contents.
 
155
        
 
156
        This variation renames a to d and alters its content to 'bar\n'.
 
157
        """
 
158
        self._make_abc_tree(tree)
 
159
        tree.rename_one('a', 'd')
 
160
        f = open(tree.basedir + '/d', 'wb')
 
161
        try:
 
162
            f.write('bar\n')
 
163
        finally:
 
164
            f.close()
 
165
        return self._convert_tree(tree, converter)
 
166
 
 
167
    def get_tree_no_parents_abc_content_6(self, tree, converter=None):
 
168
        """return a test tree with a, b/, e contents.
 
169
        
 
170
        This variation renames b/c to e, and makes it executable.
 
171
        """
 
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)
 
178
        tt.apply()
 
179
        return self._convert_tree(tree, converter)
 
180
 
 
181
    def get_tree_with_subdirs_and_all_content_types(self):
 
182
        """Return a test tree with subdirs and all content types.
 
183
 
 
184
        The returned tree has the following inventory:
 
185
            [('', inventory.ROOT_ID),
 
186
             ('0file', '2file'),
 
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.
 
193
 
 
194
        note that the order of the paths and fileids is deliberately 
 
195
        mismatched to ensure that the result order is path based.
 
196
        """
 
197
        tree = self.make_branch_and_tree('.')
 
198
        paths = ['0file',
 
199
            '1top-dir/',
 
200
            u'2utf\u1234file',
 
201
            '1top-dir/0file-in-1topdir',
 
202
            '1top-dir/1dir-in-1topdir/'
 
203
            ]
 
204
        ids = [
 
205
            '2file',
 
206
            '1top-dir',
 
207
            u'0utf\u1234file'.encode('utf8'),
 
208
            '1file-in-1topdir',
 
209
            '0dir-in-1topdir'
 
210
            ]
 
211
        try:
 
212
            self.build_tree(paths)
 
213
        except UnicodeError:
 
214
            raise TestSkipped(
 
215
                'This platform does not support unicode file paths.')
 
216
        tree.add(paths, ids)
 
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')
 
221
        tt.apply()
 
222
        return self.workingtree_to_test_tree(tree)
 
223
 
 
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)
 
228
 
 
229
    def _create_tree_with_utf8(self, tree):
 
230
        """Generate a tree with a utf8 revision and unicode paths."""
 
231
        paths = [u'',
 
232
                 u'f\xf6',
 
233
                 u'b\xe5r/',
 
234
                 u'b\xe5r/b\xe1z',
 
235
                ]
 
236
        # bzr itself does not create unicode file ids, but we want them for
 
237
        # testing.
 
238
        file_ids = ['TREE_ROOT',
 
239
                    'f\xc3\xb6-id',
 
240
                    'b\xc3\xa5r-id',
 
241
                    'b\xc3\xa1z-id',
 
242
                   ]
 
243
        try:
 
244
            self.build_tree(paths[1:])
 
245
        except UnicodeError:
 
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)
 
250
        else:
 
251
            # Some trees will already have a root
 
252
            tree.set_root_id(file_ids[0])
 
253
            tree.add(paths[1:], file_ids[1:])
 
254
        try:
 
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')
 
258
 
 
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'))
 
267
 
 
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)
 
271
 
 
272
 
 
273
class TreeTestProviderAdapter(WorkingTreeTestProviderAdapter):
 
274
    """Generate test suites for each Tree implementation in bzrlib.
 
275
 
 
276
    Currently this covers all working tree formats, and RevisionTree by 
 
277
    committing a working tree to create the revision tree.
 
278
    """
 
279
 
 
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
 
286
        # code.
 
287
        default_format = WorkingTreeFormat3()
 
288
        revision_tree_test = self._clone_test(
 
289
            test,
 
290
            default_format._matchingbzrdir, 
 
291
            default_format,
 
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(
 
298
            test,
 
299
            dirstate_format._matchingbzrdir,
 
300
            dirstate_format,
 
301
            DirStateRevisionTree.__name__)
 
302
        dirstate_revision_tree_test.workingtree_to_test_tree = _dirstate_tree_from_workingtree
 
303
        result.addTest(dirstate_revision_tree_test)
 
304
        return result
 
305
 
 
306
 
 
307
def test_suite():
 
308
    result = TestSuite()
 
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',
 
317
        ]
 
318
    adapter = TreeTestProviderAdapter(
 
319
        default_transport,
 
320
        # None here will cause a readonly decorator to be created
 
321
        # by the TestCaseWithTransport.get_readonly_transport method.
 
322
        None,
 
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']))
 
328
    return result