/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
1185.82.7 by John Arbash Meinel
Adding patches.py into bzrlib, including the tests into the test suite.
1
# Copyright (C) 2004-2006 by 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
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
16
17
from StringIO import StringIO
18
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
19
from bzrlib.builtins import merge
1185.82.40 by Aaron Bentley
Started work on testing install_revisions/handling empty changesets
20
from bzrlib.bzrdir import BzrDir
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
21
from bzrlib.bundle.apply_bundle import install_bundle, merge_bundle
22
from bzrlib.bundle.read_bundle import BundleTree, BundleReader
23
from bzrlib.bundle.serializer import write_bundle
1185.82.90 by Aaron Bentley
Reorganized test suite
24
from bzrlib.diff import internal_diff
1185.82.139 by Aaron Bentley
Raise NotABundle when a non-bundle is supplied
25
from bzrlib.errors import BzrError, TestamentMismatch, NotABundle
1185.82.44 by Aaron Bentley
Switch to merge_changeset in test suite
26
from bzrlib.merge import Merge3Merger
1185.82.87 by Aaron Bentley
Got symlink adding working
27
from bzrlib.osutils import has_symlinks, sha_file
1185.82.137 by Aaron Bentley
Skip unicode changeset test
28
from bzrlib.tests import TestCaseInTempDir, TestCase, TestSkipped
1185.82.66 by Aaron Bentley
Handle new executable files
29
from bzrlib.transform import TreeTransform
1185.82.17 by Aaron Bentley
More API updates
30
from bzrlib.workingtree import WorkingTree
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
31
1185.82.90 by Aaron Bentley
Reorganized test suite
32
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
33
class MockTree(object):
34
    def __init__(self):
0.6.1 by Aaron Bentley
Fleshed out MockTree, fixed all test failures
35
        from bzrlib.inventory import RootEntry, ROOT_ID
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
36
        object.__init__(self)
0.6.1 by Aaron Bentley
Fleshed out MockTree, fixed all test failures
37
        self.paths = {ROOT_ID: ""}
38
        self.ids = {"": ROOT_ID}
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
39
        self.contents = {}
0.6.1 by Aaron Bentley
Fleshed out MockTree, fixed all test failures
40
        self.root = RootEntry(ROOT_ID)
41
42
    inventory = property(lambda x:x)
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
43
44
    def __iter__(self):
45
        return self.paths.iterkeys()
46
0.6.1 by Aaron Bentley
Fleshed out MockTree, fixed all test failures
47
    def __getitem__(self, file_id):
48
        if file_id == self.root.file_id:
49
            return self.root
50
        else:
51
            return self.make_entry(file_id, self.paths[file_id])
52
53
    def parent_id(self, file_id):
54
        from os.path import dirname
55
        parent_dir = dirname(self.paths[file_id])
56
        if parent_dir == "":
57
            return None
58
        return self.ids[parent_dir]
59
60
    def iter_entries(self):
61
        for path, file_id in self.ids.iteritems():
62
            yield path, self[file_id]
63
64
    def get_file_kind(self, file_id):
65
        if file_id in self.contents:
66
            kind = 'file'
67
        else:
68
            kind = 'directory'
69
        return kind
70
71
    def make_entry(self, file_id, path):
72
        from os.path import basename
0.5.119 by John Arbash Meinel
Recreated the factory. We really need InventoryEntry.create()
73
        from bzrlib.inventory import (InventoryEntry, InventoryFile
74
                                    , InventoryDirectory, InventoryLink)
0.6.1 by Aaron Bentley
Fleshed out MockTree, fixed all test failures
75
        name = basename(path)
76
        kind = self.get_file_kind(file_id)
77
        parent_id = self.parent_id(file_id)
78
        text_sha_1, text_size = self.contents_stats(file_id)
0.5.119 by John Arbash Meinel
Recreated the factory. We really need InventoryEntry.create()
79
        if kind == 'directory':
80
            ie = InventoryDirectory(file_id, name, parent_id)
81
        elif kind == 'file':
82
            ie = InventoryFile(file_id, name, parent_id)
83
        elif kind == 'symlink':
84
            ie = InventoryLink(file_id, name, parent_id)
85
        else:
86
            raise BzrError('unknown kind %r' % kind)
0.5.91 by Aaron Bentley
Updated to match API change
87
        ie.text_sha1 = text_sha_1
0.6.1 by Aaron Bentley
Fleshed out MockTree, fixed all test failures
88
        ie.text_size = text_size
89
        return ie
90
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
91
    def add_dir(self, file_id, path):
92
        self.paths[file_id] = path
93
        self.ids[path] = file_id
94
    
95
    def add_file(self, file_id, path, contents):
96
        self.add_dir(file_id, path)
97
        self.contents[file_id] = contents
98
99
    def path2id(self, path):
100
        return self.ids.get(path)
101
102
    def id2path(self, file_id):
103
        return self.paths.get(file_id)
104
105
    def has_id(self, file_id):
106
        return self.id2path(file_id) is not None
107
108
    def get_file(self, file_id):
109
        result = StringIO()
110
        result.write(self.contents[file_id])
111
        result.seek(0,0)
112
        return result
113
0.6.1 by Aaron Bentley
Fleshed out MockTree, fixed all test failures
114
    def contents_stats(self, file_id):
115
        if file_id not in self.contents:
116
            return None, None
117
        text_sha1 = sha_file(self.get_file(file_id))
118
        return text_sha1, len(self.contents[file_id])
119
120
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
121
class BTreeTester(TestCase):
122
    """A simple unittest tester for the BundleTree class."""
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
123
124
    def make_tree_1(self):
125
        mtree = MockTree()
126
        mtree.add_dir("a", "grandparent")
127
        mtree.add_dir("b", "grandparent/parent")
128
        mtree.add_file("c", "grandparent/parent/file", "Hello\n")
129
        mtree.add_dir("d", "grandparent/alt_parent")
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
130
        return BundleTree(mtree, ''), mtree
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
131
        
132
    def test_renames(self):
133
        """Ensure that file renames have the proper effect on children"""
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
134
        btree = self.make_tree_1()[0]
135
        self.assertEqual(btree.old_path("grandparent"), "grandparent")
136
        self.assertEqual(btree.old_path("grandparent/parent"), 
137
                         "grandparent/parent")
138
        self.assertEqual(btree.old_path("grandparent/parent/file"),
139
                         "grandparent/parent/file")
140
141
        self.assertEqual(btree.id2path("a"), "grandparent")
142
        self.assertEqual(btree.id2path("b"), "grandparent/parent")
143
        self.assertEqual(btree.id2path("c"), "grandparent/parent/file")
144
145
        self.assertEqual(btree.path2id("grandparent"), "a")
146
        self.assertEqual(btree.path2id("grandparent/parent"), "b")
147
        self.assertEqual(btree.path2id("grandparent/parent/file"), "c")
148
149
        assert btree.path2id("grandparent2") is None
150
        assert btree.path2id("grandparent2/parent") is None
151
        assert btree.path2id("grandparent2/parent/file") is None
152
153
        btree.note_rename("grandparent", "grandparent2")
154
        assert btree.old_path("grandparent") is None
155
        assert btree.old_path("grandparent/parent") is None
156
        assert btree.old_path("grandparent/parent/file") is None
157
158
        self.assertEqual(btree.id2path("a"), "grandparent2")
159
        self.assertEqual(btree.id2path("b"), "grandparent2/parent")
160
        self.assertEqual(btree.id2path("c"), "grandparent2/parent/file")
161
162
        self.assertEqual(btree.path2id("grandparent2"), "a")
163
        self.assertEqual(btree.path2id("grandparent2/parent"), "b")
164
        self.assertEqual(btree.path2id("grandparent2/parent/file"), "c")
165
166
        assert btree.path2id("grandparent") is None
167
        assert btree.path2id("grandparent/parent") is None
168
        assert btree.path2id("grandparent/parent/file") is None
169
170
        btree.note_rename("grandparent/parent", "grandparent2/parent2")
171
        self.assertEqual(btree.id2path("a"), "grandparent2")
172
        self.assertEqual(btree.id2path("b"), "grandparent2/parent2")
173
        self.assertEqual(btree.id2path("c"), "grandparent2/parent2/file")
174
175
        self.assertEqual(btree.path2id("grandparent2"), "a")
176
        self.assertEqual(btree.path2id("grandparent2/parent2"), "b")
177
        self.assertEqual(btree.path2id("grandparent2/parent2/file"), "c")
178
179
        assert btree.path2id("grandparent2/parent") is None
180
        assert btree.path2id("grandparent2/parent/file") is None
181
182
        btree.note_rename("grandparent/parent/file", 
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
183
                          "grandparent2/parent2/file2")
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
184
        self.assertEqual(btree.id2path("a"), "grandparent2")
185
        self.assertEqual(btree.id2path("b"), "grandparent2/parent2")
186
        self.assertEqual(btree.id2path("c"), "grandparent2/parent2/file2")
187
188
        self.assertEqual(btree.path2id("grandparent2"), "a")
189
        self.assertEqual(btree.path2id("grandparent2/parent2"), "b")
190
        self.assertEqual(btree.path2id("grandparent2/parent2/file2"), "c")
191
192
        assert btree.path2id("grandparent2/parent2/file") is None
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
193
194
    def test_moves(self):
195
        """Ensure that file moves have the proper effect on children"""
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
196
        btree = self.make_tree_1()[0]
197
        btree.note_rename("grandparent/parent/file", 
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
198
                          "grandparent/alt_parent/file")
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
199
        self.assertEqual(btree.id2path("c"), "grandparent/alt_parent/file")
200
        self.assertEqual(btree.path2id("grandparent/alt_parent/file"), "c")
201
        assert btree.path2id("grandparent/parent/file") is None
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
202
203
    def unified_diff(self, old, new):
204
        out = StringIO()
205
        internal_diff("old", old, "new", new, out)
206
        out.seek(0,0)
207
        return out.read()
208
209
    def make_tree_2(self):
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
210
        btree = self.make_tree_1()[0]
211
        btree.note_rename("grandparent/parent/file", 
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
212
                          "grandparent/alt_parent/file")
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
213
        assert btree.id2path("e") is None
214
        assert btree.path2id("grandparent/parent/file") is None
215
        btree.note_id("e", "grandparent/parent/file")
216
        return btree
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
217
218
    def test_adds(self):
219
        """File/inventory adds"""
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
220
        btree = self.make_tree_2()
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
221
        add_patch = self.unified_diff([], ["Extra cheese\n"])
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
222
        btree.note_patch("grandparent/parent/file", add_patch)
223
        btree.note_id('f', 'grandparent/parent/symlink', kind='symlink')
224
        btree.note_target('grandparent/parent/symlink', 'venus')
225
        self.adds_test(btree)
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
226
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
227
    def adds_test(self, btree):
228
        self.assertEqual(btree.id2path("e"), "grandparent/parent/file")
229
        self.assertEqual(btree.path2id("grandparent/parent/file"), "e")
230
        self.assertEqual(btree.get_file("e").read(), "Extra cheese\n")
231
        self.assertEqual(btree.get_symlink_target('f'), 'venus')
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
232
233
    def test_adds2(self):
234
        """File/inventory adds, with patch-compatibile renames"""
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
235
        btree = self.make_tree_2()
236
        btree.contents_by_id = False
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
237
        add_patch = self.unified_diff(["Hello\n"], ["Extra cheese\n"])
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
238
        btree.note_patch("grandparent/parent/file", add_patch)
239
        btree.note_id('f', 'grandparent/parent/symlink', kind='symlink')
240
        btree.note_target('grandparent/parent/symlink', 'venus')
241
        self.adds_test(btree)
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
242
243
    def make_tree_3(self):
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
244
        btree, mtree = self.make_tree_1()
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
245
        mtree.add_file("e", "grandparent/parent/topping", "Anchovies\n")
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
246
        btree.note_rename("grandparent/parent/file", 
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
247
                          "grandparent/alt_parent/file")
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
248
        btree.note_rename("grandparent/parent/topping", 
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
249
                          "grandparent/alt_parent/stopping")
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
250
        return btree
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
251
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
252
    def get_file_test(self, btree):
253
        self.assertEqual(btree.get_file("e").read(), "Lemon\n")
254
        self.assertEqual(btree.get_file("c").read(), "Hello\n")
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
255
256
    def test_get_file(self):
257
        """Get file contents"""
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
258
        btree = self.make_tree_3()
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
259
        mod_patch = self.unified_diff(["Anchovies\n"], ["Lemon\n"])
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
260
        btree.note_patch("grandparent/alt_parent/stopping", mod_patch)
261
        self.get_file_test(btree)
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
262
263
    def test_get_file2(self):
264
        """Get file contents, with patch-compatibile renames"""
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
265
        btree = self.make_tree_3()
266
        btree.contents_by_id = False
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
267
        mod_patch = self.unified_diff([], ["Lemon\n"])
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
268
        btree.note_patch("grandparent/alt_parent/stopping", mod_patch)
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
269
        mod_patch = self.unified_diff([], ["Hello\n"])
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
270
        btree.note_patch("grandparent/alt_parent/file", mod_patch)
271
        self.get_file_test(btree)
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
272
273
    def test_delete(self):
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
274
        "Deletion by bundle"
275
        btree = self.make_tree_1()[0]
276
        self.assertEqual(btree.get_file("c").read(), "Hello\n")
277
        btree.note_deletion("grandparent/parent/file")
278
        assert btree.id2path("c") is None
279
        assert btree.path2id("grandparent/parent/file") is None
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
280
281
    def sorted_ids(self, tree):
282
        ids = list(tree)
283
        ids.sort()
284
        return ids
285
286
    def test_iteration(self):
287
        """Ensure that iteration through ids works properly"""
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
288
        btree = self.make_tree_1()[0]
289
        self.assertEqual(self.sorted_ids(btree), ['a', 'b', 'c', 'd'])
290
        btree.note_deletion("grandparent/parent/file")
291
        btree.note_id("e", "grandparent/alt_parent/fool", kind="directory")
292
        btree.note_last_changed("grandparent/alt_parent/fool", 
1185.82.95 by Aaron Bentley
Restore path-orientation of ChangesetTree
293
                                "revisionidiguess")
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
294
        self.assertEqual(self.sorted_ids(btree), ['a', 'b', 'd', 'e'])
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
295
1185.82.7 by John Arbash Meinel
Adding patches.py into bzrlib, including the tests into the test suite.
296
0.5.97 by Aaron Bentley
Updated tests
297
class CSetTester(TestCaseInTempDir):
0.5.80 by John Arbash Meinel
Starting to write tests for changeset, discovering some errors as I go.
298
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
299
    def get_valid_bundle(self, base_rev_id, rev_id, checkout_dir=None,
300
                         message=None):
301
        """Create a bundle from base_rev_id -> rev_id in built-in branch.
0.5.80 by John Arbash Meinel
Starting to write tests for changeset, discovering some errors as I go.
302
        Make sure that the text generated is valid, and that it
303
        can be applied against the base, and generate the same information.
304
        
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
305
        :return: The in-memory bundle 
0.5.80 by John Arbash Meinel
Starting to write tests for changeset, discovering some errors as I go.
306
        """
307
        from cStringIO import StringIO
308
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
309
        bundle_txt = StringIO()
310
        rev_ids = write_bundle(self.b1.repository, rev_id, base_rev_id, 
311
                               bundle_txt)
312
        bundle_txt.seek(0)
313
        self.assertEqual(bundle_txt.readline(), 
314
                         '# Bazaar revision bundle v0.7\n')
315
        self.assertEqual(bundle_txt.readline(), '#\n')
0.5.80 by John Arbash Meinel
Starting to write tests for changeset, discovering some errors as I go.
316
1185.82.14 by Aaron Bentley
API updates
317
        rev = self.b1.repository.get_revision(rev_id)
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
318
        self.assertEqual(bundle_txt.readline().decode('utf-8'),
319
                         u'# message:\n')
0.5.80 by John Arbash Meinel
Starting to write tests for changeset, discovering some errors as I go.
320
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
321
        open(',,bundle', 'wb').write(bundle_txt.getvalue())
322
        bundle_txt.seek(0)
323
        # This should also validate the generated bundle 
324
        bundle = BundleReader(bundle_txt)
325
        repository = self.b1.repository
326
        for bundle_rev in bundle.info.real_revisions:
327
            # These really should have already been checked when we read the
328
            # bundle, since it computes the sha1 hash for the revision, which
329
            # only will match if everything is okay, but lets be explicit about
330
            # it
331
            branch_rev = repository.get_revision(bundle_rev.revision_id)
1185.82.33 by Aaron Bentley
Strengthen tests
332
            for a in ('inventory_sha1', 'revision_id', 'parent_ids',
333
                      'timestamp', 'timezone', 'message', 'committer', 
334
                      'parent_ids', 'properties'):
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
335
                self.assertEqual(getattr(branch_rev, a), 
336
                                 getattr(bundle_rev, a))
337
            self.assertEqual(len(branch_rev.parent_ids), 
338
                             len(bundle_rev.parent_ids))
1185.82.47 by Aaron Bentley
Ensure all intended rev_ids end up in the revision
339
        self.assertEqual(rev_ids, 
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
340
                         [r.revision_id for r in bundle.info.real_revisions])
341
        self.valid_apply_bundle(base_rev_id, bundle,
1185.82.89 by Aaron Bentley
Remove auto_commit stuff
342
                                   checkout_dir=checkout_dir)
0.5.80 by John Arbash Meinel
Starting to write tests for changeset, discovering some errors as I go.
343
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
344
        return bundle
0.5.80 by John Arbash Meinel
Starting to write tests for changeset, discovering some errors as I go.
345
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
346
    def get_invalid_bundle(self, base_rev_id, rev_id):
347
        """Create a bundle from base_rev_id -> rev_id in built-in branch.
1185.82.118 by Aaron Bentley
Ensure that StrictTestament handles execute bit differences
348
        Munge the text so that it's invalid.
349
        
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
350
        :return: The in-memory bundle
1185.82.118 by Aaron Bentley
Ensure that StrictTestament handles execute bit differences
351
        """
352
        from cStringIO import StringIO
353
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
354
        bundle_txt = StringIO()
355
        rev_ids = write_bundle(self.b1.repository, rev_id, base_rev_id, 
356
                               bundle_txt)
357
        bundle_txt.seek(0)
358
        open(',,bundle', 'wb').write(bundle_txt.getvalue())
359
        bundle_txt.seek(0)
360
        new_text = bundle_txt.getvalue().replace('executable:no', 
1185.82.118 by Aaron Bentley
Ensure that StrictTestament handles execute bit differences
361
                                               'executable:yes')
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
362
        bundle_txt = StringIO(new_text)
363
        bundle = BundleReader(bundle_txt)
364
        self.valid_apply_bundle(base_rev_id, bundle)
365
        return bundle 
1185.82.118 by Aaron Bentley
Ensure that StrictTestament handles execute bit differences
366
1185.82.139 by Aaron Bentley
Raise NotABundle when a non-bundle is supplied
367
    def test_non_bundle(self):
368
        self.assertRaises(NotABundle, BundleReader, StringIO('#!/bin/sh\n'))
369
0.5.88 by John Arbash Meinel
Fixed a bug in the rename code, added more tests.
370
    def get_checkout(self, rev_id, checkout_dir=None):
0.5.80 by John Arbash Meinel
Starting to write tests for changeset, discovering some errors as I go.
371
        """Get a new tree, with the specified revision in it.
372
        """
0.5.102 by John Arbash Meinel
Updated to latest bzr.dev changes (serialization, test cases, etc)
373
        from bzrlib.branch import Branch
0.5.80 by John Arbash Meinel
Starting to write tests for changeset, discovering some errors as I go.
374
        import tempfile
375
0.5.88 by John Arbash Meinel
Fixed a bug in the rename code, added more tests.
376
        if checkout_dir is None:
377
            checkout_dir = tempfile.mkdtemp(prefix='test-branch-', dir='.')
0.5.89 by John Arbash Meinel
Updating for explicitly defined directories.
378
        else:
379
            import os
380
            if not os.path.exists(checkout_dir):
381
                os.mkdir(checkout_dir)
1185.82.40 by Aaron Bentley
Started work on testing install_revisions/handling empty changesets
382
        tree = BzrDir.create_standalone_workingtree(checkout_dir)
383
        s = StringIO()
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
384
        ancestors = write_bundle(self.b1.repository, rev_id, None, s)
1185.82.40 by Aaron Bentley
Started work on testing install_revisions/handling empty changesets
385
        s.seek(0)
1185.82.135 by Aaron Bentley
Ensure that bundles are bytestrings
386
        assert isinstance(s.getvalue(), str), (
387
            "Bundle isn't a bytestring:\n %s..." % repr(s.getvalue())[:40])
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
388
        install_bundle(tree.branch.repository, BundleReader(s))
1185.82.41 by Aaron Bentley
More work on installing changesets
389
        for ancestor in ancestors:
390
            old = self.b1.repository.revision_tree(ancestor)
391
            new = tree.branch.repository.revision_tree(ancestor)
392
            for inventory_id in old:
393
                try:
394
                    old_file = old.get_file(inventory_id)
395
                except:
396
                    continue
397
                if old_file is None:
398
                    continue
399
                self.assertEqual(old_file.read(),
400
                                 new.get_file(inventory_id).read())
1185.82.44 by Aaron Bentley
Switch to merge_changeset in test suite
401
        if rev_id is not None:
402
            rh = self.b1.revision_history()
403
            tree.branch.set_revision_history(rh[:rh.index(rev_id)+1])
404
            tree.update()
1185.82.40 by Aaron Bentley
Started work on testing install_revisions/handling empty changesets
405
        return tree
0.5.80 by John Arbash Meinel
Starting to write tests for changeset, discovering some errors as I go.
406
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
407
    def valid_apply_bundle(self, base_rev_id, reader, checkout_dir=None):
0.5.80 by John Arbash Meinel
Starting to write tests for changeset, discovering some errors as I go.
408
        """Get the base revision, apply the changes, and make
409
        sure everything matches the builtin branch.
410
        """
1185.82.17 by Aaron Bentley
More API updates
411
        to_tree = self.get_checkout(base_rev_id, checkout_dir=checkout_dir)
1185.82.40 by Aaron Bentley
Started work on testing install_revisions/handling empty changesets
412
        repository = to_tree.branch.repository
1185.82.41 by Aaron Bentley
More work on installing changesets
413
        self.assertIs(repository.has_revision(base_rev_id), True)
1185.82.45 by Aaron Bentley
Take ChangesetReader as input to merge_changeset
414
        info = reader.info
1185.82.40 by Aaron Bentley
Started work on testing install_revisions/handling empty changesets
415
        for rev in info.real_revisions:
416
            self.assert_(not repository.has_revision(rev.revision_id),
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
417
                'Revision {%s} present before applying bundle' 
1185.82.40 by Aaron Bentley
Started work on testing install_revisions/handling empty changesets
418
                % rev.revision_id)
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
419
        merge_bundle(reader, to_tree, True, Merge3Merger, False, False)
0.5.80 by John Arbash Meinel
Starting to write tests for changeset, discovering some errors as I go.
420
421
        for rev in info.real_revisions:
1185.82.17 by Aaron Bentley
More API updates
422
            self.assert_(repository.has_revision(rev.revision_id),
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
423
                'Missing revision {%s} after applying bundle' 
0.5.80 by John Arbash Meinel
Starting to write tests for changeset, discovering some errors as I go.
424
                % rev.revision_id)
425
1185.82.17 by Aaron Bentley
More API updates
426
        self.assert_(to_tree.branch.repository.has_revision(info.target))
0.5.117 by John Arbash Meinel
Almost there. Just need to track down a few remaining bugs.
427
        # Do we also want to verify that all the texts have been added?
0.5.86 by John Arbash Meinel
Updated the auto-commit functionality, and adding to pending-merges, more testing.
428
1185.82.44 by Aaron Bentley
Switch to merge_changeset in test suite
429
        self.assert_(info.target in to_tree.pending_merges())
0.5.86 by John Arbash Meinel
Updated the auto-commit functionality, and adding to pending-merges, more testing.
430
431
0.5.80 by John Arbash Meinel
Starting to write tests for changeset, discovering some errors as I go.
432
        rev = info.real_revisions[-1]
1185.82.17 by Aaron Bentley
More API updates
433
        base_tree = self.b1.repository.revision_tree(rev.revision_id)
434
        to_tree = to_tree.branch.repository.revision_tree(rev.revision_id)
0.5.80 by John Arbash Meinel
Starting to write tests for changeset, discovering some errors as I go.
435
        
436
        # TODO: make sure the target tree is identical to base tree
0.5.86 by John Arbash Meinel
Updated the auto-commit functionality, and adding to pending-merges, more testing.
437
        #       we might also check the working tree.
438
439
        base_files = list(base_tree.list_files())
440
        to_files = list(to_tree.list_files())
441
        self.assertEqual(len(base_files), len(to_files))
1185.82.66 by Aaron Bentley
Handle new executable files
442
        for base_file, to_file in zip(base_files, to_files):
443
            self.assertEqual(base_file, to_file)
0.5.86 by John Arbash Meinel
Updated the auto-commit functionality, and adding to pending-merges, more testing.
444
0.5.117 by John Arbash Meinel
Almost there. Just need to track down a few remaining bugs.
445
        for path, status, kind, fileid, entry in base_files:
0.5.86 by John Arbash Meinel
Updated the auto-commit functionality, and adding to pending-merges, more testing.
446
            # Check that the meta information is the same
447
            self.assertEqual(base_tree.get_file_size(fileid),
448
                    to_tree.get_file_size(fileid))
449
            self.assertEqual(base_tree.get_file_sha1(fileid),
450
                    to_tree.get_file_sha1(fileid))
451
            # Check that the contents are the same
452
            # This is pretty expensive
453
            # self.assertEqual(base_tree.get_file(fileid).read(),
454
            #         to_tree.get_file(fileid).read())
0.5.80 by John Arbash Meinel
Starting to write tests for changeset, discovering some errors as I go.
455
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
456
    def test_bundle(self):
0.5.78 by John Arbash Meinel
Working on test cases, starting with the empty project issues.
457
0.5.80 by John Arbash Meinel
Starting to write tests for changeset, discovering some errors as I go.
458
        import os, sys
0.5.78 by John Arbash Meinel
Working on test cases, starting with the empty project issues.
459
        pjoin = os.path.join
460
1185.82.14 by Aaron Bentley
API updates
461
        self.tree1 = BzrDir.create_standalone_workingtree('b1')
462
        self.b1 = self.tree1.branch
0.5.78 by John Arbash Meinel
Working on test cases, starting with the empty project issues.
463
464
        open(pjoin('b1/one'), 'wb').write('one\n')
1185.82.14 by Aaron Bentley
API updates
465
        self.tree1.add('one')
466
        self.tree1.commit('add one', rev_id='a@cset-0-1')
0.5.78 by John Arbash Meinel
Working on test cases, starting with the empty project issues.
467
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
468
        bundle = self.get_valid_bundle(None, 'a@cset-0-1')
469
        bundle = self.get_valid_bundle(None, 'a@cset-0-1',
0.5.103 by John Arbash Meinel
Updated to having a changeset specific message.
470
                message='With a specialized message')
0.5.80 by John Arbash Meinel
Starting to write tests for changeset, discovering some errors as I go.
471
472
        # Make sure we can handle files with spaces, tabs, other
473
        # bogus characters
0.5.82 by John Arbash Meinel
Lots of changes, changing separators, updating tests, updated ChangesetTree to include text_ids
474
        self.build_tree([
0.5.84 by John Arbash Meinel
(broken) problem with removes.
475
                'b1/with space.txt'
476
                , 'b1/dir/'
477
                , 'b1/dir/filein subdir.c'
478
                , 'b1/dir/WithCaps.txt'
0.5.87 by John Arbash Meinel
Handling international characters, added more test cases.
479
                , 'b1/dir/trailing space '
0.5.84 by John Arbash Meinel
(broken) problem with removes.
480
                , 'b1/sub/'
481
                , 'b1/sub/sub/'
482
                , 'b1/sub/sub/nonempty.txt'
0.5.82 by John Arbash Meinel
Lots of changes, changing separators, updating tests, updated ChangesetTree to include text_ids
483
                # Tabs are not valid in filenames on windows
484
                #'b1/with\ttab.txt'
485
                ])
0.5.84 by John Arbash Meinel
(broken) problem with removes.
486
        open('b1/sub/sub/emptyfile.txt', 'wb').close()
0.5.94 by Aaron Bentley
Switched to native patch application, added tests for terminating newlines
487
        open('b1/dir/nolastnewline.txt', 'wb').write('bloop')
1185.82.66 by Aaron Bentley
Handle new executable files
488
        tt = TreeTransform(self.tree1)
489
        tt.new_file('executable', tt.root, '#!/bin/sh\n', 'exe-1', True)
490
        tt.apply()
1185.82.14 by Aaron Bentley
API updates
491
        self.tree1.add([
0.5.84 by John Arbash Meinel
(broken) problem with removes.
492
                'with space.txt'
493
                , 'dir'
494
                , 'dir/filein subdir.c'
495
                , 'dir/WithCaps.txt'
0.5.87 by John Arbash Meinel
Handling international characters, added more test cases.
496
                , 'dir/trailing space '
0.5.94 by Aaron Bentley
Switched to native patch application, added tests for terminating newlines
497
                , 'dir/nolastnewline.txt'
0.5.84 by John Arbash Meinel
(broken) problem with removes.
498
                , 'sub'
499
                , 'sub/sub'
500
                , 'sub/sub/nonempty.txt'
501
                , 'sub/sub/emptyfile.txt'
0.5.82 by John Arbash Meinel
Lots of changes, changing separators, updating tests, updated ChangesetTree to include text_ids
502
                ])
1185.82.14 by Aaron Bentley
API updates
503
        self.tree1.commit('add whitespace', rev_id='a@cset-0-2')
0.5.80 by John Arbash Meinel
Starting to write tests for changeset, discovering some errors as I go.
504
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
505
        bundle = self.get_valid_bundle('a@cset-0-1', 'a@cset-0-2')
0.5.117 by John Arbash Meinel
Almost there. Just need to track down a few remaining bugs.
506
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
507
        # Check a rollup bundle 
508
        bundle = self.get_valid_bundle(None, 'a@cset-0-2')
0.5.84 by John Arbash Meinel
(broken) problem with removes.
509
510
        # Now delete entries
1185.82.21 by Aaron Bentley
Stop using deprecated function
511
        self.tree1.remove(
0.5.118 by John Arbash Meinel
Got most of test_changeset to work. Still needs work for Aaron's test code.
512
                ['sub/sub/nonempty.txt'
0.5.84 by John Arbash Meinel
(broken) problem with removes.
513
                , 'sub/sub/emptyfile.txt'
0.5.118 by John Arbash Meinel
Got most of test_changeset to work. Still needs work for Aaron's test code.
514
                , 'sub/sub'
515
                ])
1185.82.68 by Aaron Bentley
Handle execute bit on modified files
516
        tt = TreeTransform(self.tree1)
517
        trans_id = tt.trans_id_tree_file_id('exe-1')
518
        tt.set_executability(False, trans_id)
519
        tt.apply()
1185.82.19 by Aaron Bentley
More API updates
520
        self.tree1.commit('removed', rev_id='a@cset-0-3')
0.5.80 by John Arbash Meinel
Starting to write tests for changeset, discovering some errors as I go.
521
        
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
522
        bundle = self.get_valid_bundle('a@cset-0-2', 'a@cset-0-3')
523
        self.assertRaises(TestamentMismatch, self.get_invalid_bundle, 
1185.82.118 by Aaron Bentley
Ensure that StrictTestament handles execute bit differences
524
                          'a@cset-0-2', 'a@cset-0-3')
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
525
        # Check a rollup bundle 
526
        bundle = self.get_valid_bundle(None, 'a@cset-0-3')
0.5.84 by John Arbash Meinel
(broken) problem with removes.
527
528
529
        # Now move the directory
1185.82.19 by Aaron Bentley
More API updates
530
        self.tree1.rename_one('dir', 'sub/dir')
531
        self.tree1.commit('rename dir', rev_id='a@cset-0-4')
0.5.84 by John Arbash Meinel
(broken) problem with removes.
532
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
533
        bundle = self.get_valid_bundle('a@cset-0-3', 'a@cset-0-4')
534
        # Check a rollup bundle 
535
        bundle = self.get_valid_bundle(None, 'a@cset-0-4')
0.5.84 by John Arbash Meinel
(broken) problem with removes.
536
0.5.87 by John Arbash Meinel
Handling international characters, added more test cases.
537
        # Modified files
538
        open('b1/sub/dir/WithCaps.txt', 'ab').write('\nAdding some text\n')
0.5.88 by John Arbash Meinel
Fixed a bug in the rename code, added more tests.
539
        open('b1/sub/dir/trailing space ', 'ab').write('\nAdding some\nDOS format lines\n')
0.5.94 by Aaron Bentley
Switched to native patch application, added tests for terminating newlines
540
        open('b1/sub/dir/nolastnewline.txt', 'ab').write('\n')
1185.82.19 by Aaron Bentley
More API updates
541
        self.tree1.rename_one('sub/dir/trailing space ', 
542
                              'sub/ start and end space ')
543
        self.tree1.commit('Modified files', rev_id='a@cset-0-5')
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
544
        bundle = self.get_valid_bundle('a@cset-0-4', 'a@cset-0-5')
0.5.87 by John Arbash Meinel
Handling international characters, added more test cases.
545
546
        # Handle international characters
1185.82.137 by Aaron Bentley
Skip unicode changeset test
547
        try:
548
            f = open(u'b1/with Dod\xe9', 'wb')
549
        except UnicodeEncodeError:
550
            raise TestSkipped("Filesystem doesn't support unicode")
0.5.87 by John Arbash Meinel
Handling international characters, added more test cases.
551
        f.write((u'A file\n'
552
            u'With international man of mystery\n'
553
            u'William Dod\xe9\n').encode('utf-8'))
1185.82.19 by Aaron Bentley
More API updates
554
        self.tree1.add([u'with Dod\xe9'])
0.5.87 by John Arbash Meinel
Handling international characters, added more test cases.
555
        # BUG: (sort of) You must set verbose=False, so that python doesn't try
556
        #       and print the name of William Dode as part of the commit
1185.82.19 by Aaron Bentley
More API updates
557
        self.tree1.commit(u'i18n commit from William Dod\xe9', 
558
                          rev_id='a@cset-0-6', committer=u'William Dod\xe9',
559
                          verbose=False)
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
560
        bundle = self.get_valid_bundle('a@cset-0-5', 'a@cset-0-6')
1185.82.70 by Aaron Bentley
Handle renamed files better
561
        self.tree1.rename_one('sub/dir/WithCaps.txt', 'temp')
562
        self.tree1.rename_one('with space.txt', 'WithCaps.txt')
563
        self.tree1.rename_one('temp', 'with space.txt')
1185.82.72 by Aaron Bentley
Always use leftmost base for changesets
564
        self.tree1.commit(u'swap filenames', rev_id='a@cset-0-7',
1185.82.70 by Aaron Bentley
Handle renamed files better
565
                          verbose=False)
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
566
        bundle = self.get_valid_bundle('a@cset-0-6', 'a@cset-0-7')
1185.82.72 by Aaron Bentley
Always use leftmost base for changesets
567
        other = self.get_checkout('a@cset-0-6')
568
        other.rename_one('sub/dir/nolastnewline.txt', 'sub/nolastnewline.txt')
569
        other.commit('rename file', rev_id='a@cset-0-7b')
570
        merge([other.basedir, -1], [None, None], this_dir=self.tree1.basedir)
571
        self.tree1.commit(u'Merge', rev_id='a@cset-0-8',
572
                          verbose=False)
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
573
        bundle = self.get_valid_bundle('a@cset-0-7', 'a@cset-0-8')
1185.82.72 by Aaron Bentley
Always use leftmost base for changesets
574
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
575
    def test_symlink_bundle(self):
1185.82.87 by Aaron Bentley
Got symlink adding working
576
        if not has_symlinks():
577
            raise TestSkipped("No symlink support")
578
        self.tree1 = BzrDir.create_standalone_workingtree('b1')
579
        self.b1 = self.tree1.branch
580
        tt = TreeTransform(self.tree1)
1185.82.88 by Aaron Bentley
Get symlink modification, renames and deletion under test
581
        tt.new_symlink('link', tt.root, 'bar/foo', 'link-1')
1185.82.87 by Aaron Bentley
Got symlink adding working
582
        tt.apply()
583
        self.tree1.commit('add symlink', rev_id='l@cset-0-1')
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
584
        self.get_valid_bundle(None, 'l@cset-0-1')
1185.82.88 by Aaron Bentley
Get symlink modification, renames and deletion under test
585
        tt = TreeTransform(self.tree1)
586
        trans_id = tt.trans_id_tree_file_id('link-1')
587
        tt.adjust_path('link2', tt.root, trans_id)
588
        tt.delete_contents(trans_id)
589
        tt.create_symlink('mars', trans_id)
590
        tt.apply()
591
        self.tree1.commit('rename and change symlink', rev_id='l@cset-0-2')
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
592
        self.get_valid_bundle('l@cset-0-1', 'l@cset-0-2')
1185.82.88 by Aaron Bentley
Get symlink modification, renames and deletion under test
593
        tt = TreeTransform(self.tree1)
594
        trans_id = tt.trans_id_tree_file_id('link-1')
595
        tt.delete_contents(trans_id)
596
        tt.create_symlink('jupiter', trans_id)
597
        tt.apply()
598
        self.tree1.commit('just change symlink target', rev_id='l@cset-0-3')
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
599
        self.get_valid_bundle('l@cset-0-2', 'l@cset-0-3')
1185.82.88 by Aaron Bentley
Get symlink modification, renames and deletion under test
600
        tt = TreeTransform(self.tree1)
601
        trans_id = tt.trans_id_tree_file_id('link-1')
602
        tt.delete_contents(trans_id)
603
        tt.apply()
604
        self.tree1.commit('Delete symlink', rev_id='l@cset-0-4')
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
605
        self.get_valid_bundle('l@cset-0-3', 'l@cset-0-4')
1185.82.96 by Aaron Bentley
Got first binary test passing
606
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
607
    def test_binary_bundle(self):
1185.82.96 by Aaron Bentley
Got first binary test passing
608
        self.tree1 = BzrDir.create_standalone_workingtree('b1')
609
        self.b1 = self.tree1.branch
610
        tt = TreeTransform(self.tree1)
611
        tt.new_file('file', tt.root, '\x00\xff', 'binary-1')
1185.82.97 by Aaron Bentley
Got binary files working for adds, renames, modifications
612
        tt.new_file('file2', tt.root, '\x00\xff', 'binary-2')
1185.82.96 by Aaron Bentley
Got first binary test passing
613
        tt.apply()
614
        self.tree1.commit('add binary', rev_id='b@cset-0-1')
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
615
        self.get_valid_bundle(None, 'b@cset-0-1')
1185.82.97 by Aaron Bentley
Got binary files working for adds, renames, modifications
616
        tt = TreeTransform(self.tree1)
617
        trans_id = tt.trans_id_tree_file_id('binary-1')
618
        tt.delete_contents(trans_id)
619
        tt.apply()
620
        self.tree1.commit('delete binary', rev_id='b@cset-0-2')
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
621
        self.get_valid_bundle('b@cset-0-1', 'b@cset-0-2')
1185.82.97 by Aaron Bentley
Got binary files working for adds, renames, modifications
622
        tt = TreeTransform(self.tree1)
623
        trans_id = tt.trans_id_tree_file_id('binary-2')
624
        tt.adjust_path('file3', tt.root, trans_id)
625
        tt.delete_contents(trans_id)
626
        tt.create_file('filecontents\x00', trans_id)
627
        tt.apply()
628
        self.tree1.commit('rename and modify binary', rev_id='b@cset-0-3')
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
629
        self.get_valid_bundle('b@cset-0-2', 'b@cset-0-3')
1185.82.97 by Aaron Bentley
Got binary files working for adds, renames, modifications
630
        tt = TreeTransform(self.tree1)
631
        trans_id = tt.trans_id_tree_file_id('binary-2')
632
        tt.delete_contents(trans_id)
633
        tt.create_file('\x00filecontents', trans_id)
634
        tt.apply()
635
        self.tree1.commit('just modify binary', rev_id='b@cset-0-4')
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
636
        self.get_valid_bundle('b@cset-0-3', 'b@cset-0-4')
1185.82.115 by Aaron Bentley
Add test for last-changed special cases
637
638
    def test_last_modified(self):
639
        self.tree1 = BzrDir.create_standalone_workingtree('b1')
640
        self.b1 = self.tree1.branch
641
        tt = TreeTransform(self.tree1)
642
        tt.new_file('file', tt.root, 'file', 'file')
643
        tt.apply()
644
        self.tree1.commit('create file', rev_id='a@lmod-0-1')
645
646
        tt = TreeTransform(self.tree1)
647
        trans_id = tt.trans_id_tree_file_id('file')
648
        tt.delete_contents(trans_id)
649
        tt.create_file('file2', trans_id)
650
        tt.apply()
651
        self.tree1.commit('modify text', rev_id='a@lmod-0-2a')
652
653
        other = self.get_checkout('a@lmod-0-1')
654
        tt = TreeTransform(other)
655
        trans_id = tt.trans_id_tree_file_id('file')
656
        tt.delete_contents(trans_id)
657
        tt.create_file('file2', trans_id)
658
        tt.apply()
659
        other.commit('modify text in another tree', rev_id='a@lmod-0-2b')
660
        merge([other.basedir, -1], [None, None], this_dir=self.tree1.basedir)
661
        self.tree1.commit(u'Merge', rev_id='a@lmod-0-3',
662
                          verbose=False)
663
        self.tree1.commit(u'Merge', rev_id='a@lmod-0-4')
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
664
        bundle = self.get_valid_bundle('a@lmod-0-2a', 'a@lmod-0-4')