/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
2241.1.6 by Martin Pool
Move Knit repositories into the submodule bzrlib.repofmt.knitrepo and
1
# Copyright (C) 2004, 2005, 2006, 2007 Canonical Ltd
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
2
#
1185.82.7 by John Arbash Meinel
Adding patches.py into bzrlib, including the tests into the test suite.
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.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
7
#
1185.82.7 by John Arbash Meinel
Adding patches.py into bzrlib, including the tests into the test suite.
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.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
12
#
1185.82.7 by John Arbash Meinel
Adding patches.py into bzrlib, including the tests into the test suite.
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
1793.3.2 by John Arbash Meinel
(failing) add some tests which munge trailing whitespace
17
from cStringIO import StringIO
1711.7.27 by John Arbash Meinel
Investigating why test_bundle fails, something isn't transmitting properly.
18
import os
1711.7.34 by John Arbash Meinel
Include a test to ensure bundles handle trailing whitespace.
19
import sys
1711.7.27 by John Arbash Meinel
Investigating why test_bundle fails, something isn't transmitting properly.
20
import tempfile
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
21
1910.2.64 by Aaron Bentley
Changes from review
22
from bzrlib import (
1996.3.20 by John Arbash Meinel
[merge] bzr.dev 2063
23
    bzrdir,
24
    errors,
25
    inventory,
26
    repository,
1910.2.64 by Aaron Bentley
Changes from review
27
    treebuilder,
28
    )
1996.3.5 by John Arbash Meinel
Cleanup, deprecated, and get the tests passing again.
29
from bzrlib.builtins import _merge_helper
1185.82.40 by Aaron Bentley
Started work on testing install_revisions/handling empty changesets
30
from bzrlib.bzrdir import BzrDir
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
31
from bzrlib.bundle.apply_bundle import install_bundle, merge_bundle
1793.2.3 by Aaron Bentley
Rename read_bundle.py to bundle_data.py
32
from bzrlib.bundle.bundle_data import BundleTree
2520.4.72 by Aaron Bentley
Rename format to 4alpha
33
from bzrlib.bundle.serializer import write_bundle, read_bundle, v4
1910.2.49 by Aaron Bentley
Ensure that 0.8 bundles aren't used with KnitRepository2
34
from bzrlib.bundle.serializer.v08 import BundleSerializerV08
1910.2.51 by Aaron Bentley
Bundles now corrupt repositories
35
from bzrlib.bundle.serializer.v09 import BundleSerializerV09
2520.4.72 by Aaron Bentley
Rename format to 4alpha
36
from bzrlib.bundle.serializer.v4 import BundleSerializerV4
1711.7.27 by John Arbash Meinel
Investigating why test_bundle fails, something isn't transmitting properly.
37
from bzrlib.branch import Branch
1185.82.90 by Aaron Bentley
Reorganized test suite
38
from bzrlib.diff import internal_diff
1910.2.3 by Aaron Bentley
All tests pass
39
from bzrlib.errors import (BzrError, TestamentMismatch, NotABundle, BadBundle, 
40
                           NoSuchFile,)
1185.82.44 by Aaron Bentley
Switch to merge_changeset in test suite
41
from bzrlib.merge import Merge3Merger
2241.1.5 by Martin Pool
Move KnitFormat2 into repofmt
42
from bzrlib.repofmt import knitrepo
1185.82.87 by Aaron Bentley
Got symlink adding working
43
from bzrlib.osutils import has_symlinks, sha_file
1793.3.2 by John Arbash Meinel
(failing) add some tests which munge trailing whitespace
44
from bzrlib.tests import (TestCaseInTempDir, TestCaseWithTransport,
2520.4.34 by Aaron Bentley
Add signature support
45
                          TestCase, TestSkipped, test_commit)
1185.82.66 by Aaron Bentley
Handle new executable files
46
from bzrlib.transform import TreeTransform
1185.82.17 by Aaron Bentley
More API updates
47
from bzrlib.workingtree import WorkingTree
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
48
1185.82.90 by Aaron Bentley
Reorganized test suite
49
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
50
class MockTree(object):
51
    def __init__(self):
1731.1.4 by Aaron Bentley
merge from bzr.dev
52
        from bzrlib.inventory import InventoryDirectory, ROOT_ID
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
53
        object.__init__(self)
0.6.1 by Aaron Bentley
Fleshed out MockTree, fixed all test failures
54
        self.paths = {ROOT_ID: ""}
55
        self.ids = {"": ROOT_ID}
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
56
        self.contents = {}
1731.1.4 by Aaron Bentley
merge from bzr.dev
57
        self.root = InventoryDirectory(ROOT_ID, '', None)
0.6.1 by Aaron Bentley
Fleshed out MockTree, fixed all test failures
58
59
    inventory = property(lambda x:x)
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
60
61
    def __iter__(self):
62
        return self.paths.iterkeys()
63
0.6.1 by Aaron Bentley
Fleshed out MockTree, fixed all test failures
64
    def __getitem__(self, file_id):
65
        if file_id == self.root.file_id:
66
            return self.root
67
        else:
68
            return self.make_entry(file_id, self.paths[file_id])
69
70
    def parent_id(self, file_id):
1711.7.27 by John Arbash Meinel
Investigating why test_bundle fails, something isn't transmitting properly.
71
        parent_dir = os.path.dirname(self.paths[file_id])
0.6.1 by Aaron Bentley
Fleshed out MockTree, fixed all test failures
72
        if parent_dir == "":
73
            return None
74
        return self.ids[parent_dir]
75
76
    def iter_entries(self):
77
        for path, file_id in self.ids.iteritems():
78
            yield path, self[file_id]
79
80
    def get_file_kind(self, file_id):
81
        if file_id in self.contents:
82
            kind = 'file'
83
        else:
84
            kind = 'directory'
85
        return kind
86
87
    def make_entry(self, file_id, path):
0.5.119 by John Arbash Meinel
Recreated the factory. We really need InventoryEntry.create()
88
        from bzrlib.inventory import (InventoryEntry, InventoryFile
89
                                    , InventoryDirectory, InventoryLink)
1711.7.27 by John Arbash Meinel
Investigating why test_bundle fails, something isn't transmitting properly.
90
        name = os.path.basename(path)
0.6.1 by Aaron Bentley
Fleshed out MockTree, fixed all test failures
91
        kind = self.get_file_kind(file_id)
92
        parent_id = self.parent_id(file_id)
93
        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()
94
        if kind == 'directory':
95
            ie = InventoryDirectory(file_id, name, parent_id)
96
        elif kind == 'file':
97
            ie = InventoryFile(file_id, name, parent_id)
98
        elif kind == 'symlink':
99
            ie = InventoryLink(file_id, name, parent_id)
100
        else:
101
            raise BzrError('unknown kind %r' % kind)
0.5.91 by Aaron Bentley
Updated to match API change
102
        ie.text_sha1 = text_sha_1
0.6.1 by Aaron Bentley
Fleshed out MockTree, fixed all test failures
103
        ie.text_size = text_size
104
        return ie
105
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
106
    def add_dir(self, file_id, path):
107
        self.paths[file_id] = path
108
        self.ids[path] = file_id
109
    
110
    def add_file(self, file_id, path, contents):
111
        self.add_dir(file_id, path)
112
        self.contents[file_id] = contents
113
114
    def path2id(self, path):
115
        return self.ids.get(path)
116
117
    def id2path(self, file_id):
118
        return self.paths.get(file_id)
119
120
    def has_id(self, file_id):
121
        return self.id2path(file_id) is not None
122
123
    def get_file(self, file_id):
124
        result = StringIO()
125
        result.write(self.contents[file_id])
126
        result.seek(0,0)
127
        return result
128
0.6.1 by Aaron Bentley
Fleshed out MockTree, fixed all test failures
129
    def contents_stats(self, file_id):
130
        if file_id not in self.contents:
131
            return None, None
132
        text_sha1 = sha_file(self.get_file(file_id))
133
        return text_sha1, len(self.contents[file_id])
134
135
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
136
class BTreeTester(TestCase):
137
    """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)
138
139
    def make_tree_1(self):
140
        mtree = MockTree()
141
        mtree.add_dir("a", "grandparent")
142
        mtree.add_dir("b", "grandparent/parent")
143
        mtree.add_file("c", "grandparent/parent/file", "Hello\n")
144
        mtree.add_dir("d", "grandparent/alt_parent")
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
145
        return BundleTree(mtree, ''), mtree
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
146
        
147
    def test_renames(self):
148
        """Ensure that file renames have the proper effect on children"""
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
149
        btree = self.make_tree_1()[0]
150
        self.assertEqual(btree.old_path("grandparent"), "grandparent")
151
        self.assertEqual(btree.old_path("grandparent/parent"), 
152
                         "grandparent/parent")
153
        self.assertEqual(btree.old_path("grandparent/parent/file"),
154
                         "grandparent/parent/file")
155
156
        self.assertEqual(btree.id2path("a"), "grandparent")
157
        self.assertEqual(btree.id2path("b"), "grandparent/parent")
158
        self.assertEqual(btree.id2path("c"), "grandparent/parent/file")
159
160
        self.assertEqual(btree.path2id("grandparent"), "a")
161
        self.assertEqual(btree.path2id("grandparent/parent"), "b")
162
        self.assertEqual(btree.path2id("grandparent/parent/file"), "c")
163
164
        assert btree.path2id("grandparent2") is None
165
        assert btree.path2id("grandparent2/parent") is None
166
        assert btree.path2id("grandparent2/parent/file") is None
167
168
        btree.note_rename("grandparent", "grandparent2")
169
        assert btree.old_path("grandparent") is None
170
        assert btree.old_path("grandparent/parent") is None
171
        assert btree.old_path("grandparent/parent/file") is None
172
173
        self.assertEqual(btree.id2path("a"), "grandparent2")
174
        self.assertEqual(btree.id2path("b"), "grandparent2/parent")
175
        self.assertEqual(btree.id2path("c"), "grandparent2/parent/file")
176
177
        self.assertEqual(btree.path2id("grandparent2"), "a")
178
        self.assertEqual(btree.path2id("grandparent2/parent"), "b")
179
        self.assertEqual(btree.path2id("grandparent2/parent/file"), "c")
180
181
        assert btree.path2id("grandparent") is None
182
        assert btree.path2id("grandparent/parent") is None
183
        assert btree.path2id("grandparent/parent/file") is None
184
185
        btree.note_rename("grandparent/parent", "grandparent2/parent2")
186
        self.assertEqual(btree.id2path("a"), "grandparent2")
187
        self.assertEqual(btree.id2path("b"), "grandparent2/parent2")
188
        self.assertEqual(btree.id2path("c"), "grandparent2/parent2/file")
189
190
        self.assertEqual(btree.path2id("grandparent2"), "a")
191
        self.assertEqual(btree.path2id("grandparent2/parent2"), "b")
192
        self.assertEqual(btree.path2id("grandparent2/parent2/file"), "c")
193
194
        assert btree.path2id("grandparent2/parent") is None
195
        assert btree.path2id("grandparent2/parent/file") is None
196
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
                          "grandparent2/parent2/file2")
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
199
        self.assertEqual(btree.id2path("a"), "grandparent2")
200
        self.assertEqual(btree.id2path("b"), "grandparent2/parent2")
201
        self.assertEqual(btree.id2path("c"), "grandparent2/parent2/file2")
202
203
        self.assertEqual(btree.path2id("grandparent2"), "a")
204
        self.assertEqual(btree.path2id("grandparent2/parent2"), "b")
205
        self.assertEqual(btree.path2id("grandparent2/parent2/file2"), "c")
206
207
        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)
208
209
    def test_moves(self):
210
        """Ensure that file moves have the proper effect on children"""
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
211
        btree = self.make_tree_1()[0]
212
        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)
213
                          "grandparent/alt_parent/file")
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
214
        self.assertEqual(btree.id2path("c"), "grandparent/alt_parent/file")
215
        self.assertEqual(btree.path2id("grandparent/alt_parent/file"), "c")
216
        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)
217
218
    def unified_diff(self, old, new):
219
        out = StringIO()
220
        internal_diff("old", old, "new", new, out)
221
        out.seek(0,0)
222
        return out.read()
223
224
    def make_tree_2(self):
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
225
        btree = self.make_tree_1()[0]
226
        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)
227
                          "grandparent/alt_parent/file")
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
228
        assert btree.id2path("e") is None
229
        assert btree.path2id("grandparent/parent/file") is None
230
        btree.note_id("e", "grandparent/parent/file")
231
        return btree
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
232
233
    def test_adds(self):
234
        """File/inventory adds"""
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
235
        btree = self.make_tree_2()
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
236
        add_patch = self.unified_diff([], ["Extra cheese\n"])
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
237
        btree.note_patch("grandparent/parent/file", add_patch)
238
        btree.note_id('f', 'grandparent/parent/symlink', kind='symlink')
239
        btree.note_target('grandparent/parent/symlink', 'venus')
240
        self.adds_test(btree)
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
241
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
242
    def adds_test(self, btree):
243
        self.assertEqual(btree.id2path("e"), "grandparent/parent/file")
244
        self.assertEqual(btree.path2id("grandparent/parent/file"), "e")
245
        self.assertEqual(btree.get_file("e").read(), "Extra cheese\n")
246
        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)
247
248
    def test_adds2(self):
249
        """File/inventory adds, with patch-compatibile renames"""
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
250
        btree = self.make_tree_2()
251
        btree.contents_by_id = False
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
252
        add_patch = self.unified_diff(["Hello\n"], ["Extra cheese\n"])
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
253
        btree.note_patch("grandparent/parent/file", add_patch)
254
        btree.note_id('f', 'grandparent/parent/symlink', kind='symlink')
255
        btree.note_target('grandparent/parent/symlink', 'venus')
256
        self.adds_test(btree)
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
257
258
    def make_tree_3(self):
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
259
        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)
260
        mtree.add_file("e", "grandparent/parent/topping", "Anchovies\n")
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
261
        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)
262
                          "grandparent/alt_parent/file")
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
263
        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)
264
                          "grandparent/alt_parent/stopping")
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
265
        return btree
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
266
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
267
    def get_file_test(self, btree):
268
        self.assertEqual(btree.get_file("e").read(), "Lemon\n")
269
        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)
270
271
    def test_get_file(self):
272
        """Get file contents"""
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
273
        btree = self.make_tree_3()
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
274
        mod_patch = self.unified_diff(["Anchovies\n"], ["Lemon\n"])
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
275
        btree.note_patch("grandparent/alt_parent/stopping", mod_patch)
276
        self.get_file_test(btree)
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
277
278
    def test_get_file2(self):
279
        """Get file contents, with patch-compatibile renames"""
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
280
        btree = self.make_tree_3()
281
        btree.contents_by_id = False
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
282
        mod_patch = self.unified_diff([], ["Lemon\n"])
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
283
        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)
284
        mod_patch = self.unified_diff([], ["Hello\n"])
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
285
        btree.note_patch("grandparent/alt_parent/file", mod_patch)
286
        self.get_file_test(btree)
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
287
288
    def test_delete(self):
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
289
        "Deletion by bundle"
290
        btree = self.make_tree_1()[0]
291
        self.assertEqual(btree.get_file("c").read(), "Hello\n")
292
        btree.note_deletion("grandparent/parent/file")
293
        assert btree.id2path("c") is None
294
        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)
295
296
    def sorted_ids(self, tree):
297
        ids = list(tree)
298
        ids.sort()
299
        return ids
300
301
    def test_iteration(self):
302
        """Ensure that iteration through ids works properly"""
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
303
        btree = self.make_tree_1()[0]
1852.6.3 by Robert Collins
Make iter(Tree) consistent for all tree types.
304
        self.assertEqual(self.sorted_ids(btree),
305
            [inventory.ROOT_ID, 'a', 'b', 'c', 'd'])
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
306
        btree.note_deletion("grandparent/parent/file")
307
        btree.note_id("e", "grandparent/alt_parent/fool", kind="directory")
308
        btree.note_last_changed("grandparent/alt_parent/fool", 
1185.82.95 by Aaron Bentley
Restore path-orientation of ChangesetTree
309
                                "revisionidiguess")
1852.6.3 by Robert Collins
Make iter(Tree) consistent for all tree types.
310
        self.assertEqual(self.sorted_ids(btree),
311
            [inventory.ROOT_ID, 'a', 'b', 'd', 'e'])
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
312
1185.82.7 by John Arbash Meinel
Adding patches.py into bzrlib, including the tests into the test suite.
313
1910.2.49 by Aaron Bentley
Ensure that 0.8 bundles aren't used with KnitRepository2
314
class BundleTester1(TestCaseWithTransport):
315
316
    def test_mismatched_bundle(self):
317
        format = bzrdir.BzrDirMetaFormat1()
2255.2.211 by Robert Collins
Remove knit2 repository format- it has never been supported.
318
        format.repository_format = knitrepo.RepositoryFormatKnit3()
1910.2.49 by Aaron Bentley
Ensure that 0.8 bundles aren't used with KnitRepository2
319
        serializer = BundleSerializerV08('0.8')
320
        b = self.make_branch('.', format=format)
2067.3.1 by Martin Pool
Clean up BzrNewError, other exception classes and users.
321
        self.assertRaises(errors.IncompatibleBundleFormat, serializer.write, 
1910.2.49 by Aaron Bentley
Ensure that 0.8 bundles aren't used with KnitRepository2
322
                          b.repository, [], {}, StringIO())
323
1910.2.51 by Aaron Bentley
Bundles now corrupt repositories
324
    def test_matched_bundle(self):
2067.3.1 by Martin Pool
Clean up BzrNewError, other exception classes and users.
325
        """Don't raise IncompatibleBundleFormat for knit2 and bundle0.9"""
1910.2.51 by Aaron Bentley
Bundles now corrupt repositories
326
        format = bzrdir.BzrDirMetaFormat1()
2255.2.211 by Robert Collins
Remove knit2 repository format- it has never been supported.
327
        format.repository_format = knitrepo.RepositoryFormatKnit3()
1910.2.51 by Aaron Bentley
Bundles now corrupt repositories
328
        serializer = BundleSerializerV09('0.9')
329
        b = self.make_branch('.', format=format)
330
        serializer.write(b.repository, [], {}, StringIO())
331
1910.2.60 by Aaron Bentley
Ensure that new-model revisions aren't installed into old-model repos
332
    def test_mismatched_model(self):
333
        """Try copying a bundle from knit2 to knit1"""
334
        format = bzrdir.BzrDirMetaFormat1()
2255.2.211 by Robert Collins
Remove knit2 repository format- it has never been supported.
335
        format.repository_format = knitrepo.RepositoryFormatKnit3()
1910.2.60 by Aaron Bentley
Ensure that new-model revisions aren't installed into old-model repos
336
        source = self.make_branch_and_tree('source', format=format)
337
        source.commit('one', rev_id='one-id')
338
        source.commit('two', rev_id='two-id')
339
        text = StringIO()
340
        write_bundle(source.branch.repository, 'two-id', None, text, 
341
                     format='0.9')
342
        text.seek(0)
343
344
        format = bzrdir.BzrDirMetaFormat1()
2241.1.6 by Martin Pool
Move Knit repositories into the submodule bzrlib.repofmt.knitrepo and
345
        format.repository_format = knitrepo.RepositoryFormatKnit1()
1910.2.60 by Aaron Bentley
Ensure that new-model revisions aren't installed into old-model repos
346
        target = self.make_branch('target', format=format)
347
        self.assertRaises(errors.IncompatibleRevision, install_bundle, 
348
                          target.repository, read_bundle(text))
349
1910.2.51 by Aaron Bentley
Bundles now corrupt repositories
350
2520.4.43 by Aaron Bentley
Fix test suite
351
class BundleTester(object):
1910.2.50 by Aaron Bentley
start work on format 0.9 serializer
352
353
    def bzrdir_format(self):
354
        format = bzrdir.BzrDirMetaFormat1()
2241.1.6 by Martin Pool
Move Knit repositories into the submodule bzrlib.repofmt.knitrepo and
355
        format.repository_format = knitrepo.RepositoryFormatKnit1()
1910.2.50 by Aaron Bentley
start work on format 0.9 serializer
356
        return format
357
358
    def make_branch_and_tree(self, path, format=None):
359
        if format is None:
360
            format = self.bzrdir_format()
361
        return TestCaseWithTransport.make_branch_and_tree(self, path, format)
362
363
    def make_branch(self, path, format=None):
364
        if format is None:
365
            format = self.bzrdir_format()
366
        return TestCaseWithTransport.make_branch(self, path, format)
0.5.80 by John Arbash Meinel
Starting to write tests for changeset, discovering some errors as I go.
367
1793.3.1 by John Arbash Meinel
Clean up the bundle tests a little bit.
368
    def create_bundle_text(self, base_rev_id, rev_id):
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
369
        bundle_txt = StringIO()
370
        rev_ids = write_bundle(self.b1.repository, rev_id, base_rev_id, 
1910.2.50 by Aaron Bentley
start work on format 0.9 serializer
371
                               bundle_txt, format=self.format)
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
372
        bundle_txt.seek(0)
373
        self.assertEqual(bundle_txt.readline(), 
1910.2.51 by Aaron Bentley
Bundles now corrupt repositories
374
                         '# Bazaar revision bundle v%s\n' % self.format)
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
375
        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.
376
1185.82.14 by Aaron Bentley
API updates
377
        rev = self.b1.repository.get_revision(rev_id)
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
378
        self.assertEqual(bundle_txt.readline().decode('utf-8'),
379
                         u'# message:\n')
0.5.80 by John Arbash Meinel
Starting to write tests for changeset, discovering some errors as I go.
380
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
381
        open(',,bundle', 'wb').write(bundle_txt.getvalue())
382
        bundle_txt.seek(0)
1793.3.1 by John Arbash Meinel
Clean up the bundle tests a little bit.
383
        return bundle_txt, rev_ids
384
385
    def get_valid_bundle(self, base_rev_id, rev_id, checkout_dir=None):
386
        """Create a bundle from base_rev_id -> rev_id in built-in branch.
387
        Make sure that the text generated is valid, and that it
388
        can be applied against the base, and generate the same information.
389
        
390
        :return: The in-memory bundle 
391
        """
392
        bundle_txt, rev_ids = self.create_bundle_text(base_rev_id, rev_id)
393
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
394
        # This should also validate the generated bundle 
1793.2.2 by Aaron Bentley
Move BundleReader into v07 serializer
395
        bundle = read_bundle(bundle_txt)
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
396
        repository = self.b1.repository
1793.2.2 by Aaron Bentley
Move BundleReader into v07 serializer
397
        for bundle_rev in bundle.real_revisions:
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
398
            # These really should have already been checked when we read the
399
            # bundle, since it computes the sha1 hash for the revision, which
400
            # only will match if everything is okay, but lets be explicit about
401
            # it
402
            branch_rev = repository.get_revision(bundle_rev.revision_id)
1185.82.33 by Aaron Bentley
Strengthen tests
403
            for a in ('inventory_sha1', 'revision_id', 'parent_ids',
404
                      'timestamp', 'timezone', 'message', 'committer', 
405
                      'parent_ids', 'properties'):
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
406
                self.assertEqual(getattr(branch_rev, a), 
407
                                 getattr(bundle_rev, a))
408
            self.assertEqual(len(branch_rev.parent_ids), 
409
                             len(bundle_rev.parent_ids))
1185.82.47 by Aaron Bentley
Ensure all intended rev_ids end up in the revision
410
        self.assertEqual(rev_ids, 
1793.2.2 by Aaron Bentley
Move BundleReader into v07 serializer
411
                         [r.revision_id for r in bundle.real_revisions])
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
412
        self.valid_apply_bundle(base_rev_id, bundle,
1185.82.89 by Aaron Bentley
Remove auto_commit stuff
413
                                   checkout_dir=checkout_dir)
0.5.80 by John Arbash Meinel
Starting to write tests for changeset, discovering some errors as I go.
414
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
415
        return bundle
0.5.80 by John Arbash Meinel
Starting to write tests for changeset, discovering some errors as I go.
416
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
417
    def get_invalid_bundle(self, base_rev_id, rev_id):
418
        """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
419
        Munge the text so that it's invalid.
420
        
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
421
        :return: The in-memory bundle
1185.82.118 by Aaron Bentley
Ensure that StrictTestament handles execute bit differences
422
        """
1793.3.1 by John Arbash Meinel
Clean up the bundle tests a little bit.
423
        bundle_txt, rev_ids = self.create_bundle_text(base_rev_id, rev_id)
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
424
        new_text = bundle_txt.getvalue().replace('executable:no', 
1185.82.118 by Aaron Bentley
Ensure that StrictTestament handles execute bit differences
425
                                               'executable:yes')
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
426
        bundle_txt = StringIO(new_text)
1793.2.2 by Aaron Bentley
Move BundleReader into v07 serializer
427
        bundle = read_bundle(bundle_txt)
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
428
        self.valid_apply_bundle(base_rev_id, bundle)
429
        return bundle 
1185.82.118 by Aaron Bentley
Ensure that StrictTestament handles execute bit differences
430
1185.82.139 by Aaron Bentley
Raise NotABundle when a non-bundle is supplied
431
    def test_non_bundle(self):
1793.2.2 by Aaron Bentley
Move BundleReader into v07 serializer
432
        self.assertRaises(NotABundle, read_bundle, StringIO('#!/bin/sh\n'))
1185.82.139 by Aaron Bentley
Raise NotABundle when a non-bundle is supplied
433
1793.2.7 by Aaron Bentley
Fix reporting of malformed, (especially, crlf) bundles
434
    def test_malformed(self):
435
        self.assertRaises(BadBundle, read_bundle, 
436
                          StringIO('# Bazaar revision bundle v'))
437
438
    def test_crlf_bundle(self):
1793.2.9 by Aaron Bentley
Don't use assertNotRaises-- instead, catch BadBundle and pass
439
        try:
1793.3.14 by John Arbash Meinel
Actually fix the bug with missing trailing newline bug #49182
440
            read_bundle(StringIO('# Bazaar revision bundle v0.8\r\n'))
1793.2.9 by Aaron Bentley
Don't use assertNotRaises-- instead, catch BadBundle and pass
441
        except BadBundle:
442
            # It is currently permitted for bundles with crlf line endings to
443
            # make read_bundle raise a BadBundle, but this should be fixed.
1793.2.10 by Aaron Bentley
Whitespace/comment fix
444
            # Anything else, especially NotABundle, is an error.
1793.2.9 by Aaron Bentley
Don't use assertNotRaises-- instead, catch BadBundle and pass
445
            pass
446
0.5.88 by John Arbash Meinel
Fixed a bug in the rename code, added more tests.
447
    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.
448
        """Get a new tree, with the specified revision in it.
449
        """
450
0.5.88 by John Arbash Meinel
Fixed a bug in the rename code, added more tests.
451
        if checkout_dir is None:
452
            checkout_dir = tempfile.mkdtemp(prefix='test-branch-', dir='.')
0.5.89 by John Arbash Meinel
Updating for explicitly defined directories.
453
        else:
454
            if not os.path.exists(checkout_dir):
455
                os.mkdir(checkout_dir)
1910.2.50 by Aaron Bentley
start work on format 0.9 serializer
456
        tree = self.make_branch_and_tree(checkout_dir)
1185.82.40 by Aaron Bentley
Started work on testing install_revisions/handling empty changesets
457
        s = StringIO()
1910.2.64 by Aaron Bentley
Changes from review
458
        ancestors = write_bundle(self.b1.repository, rev_id, None, s,
1910.2.50 by Aaron Bentley
start work on format 0.9 serializer
459
                                 format=self.format)
1185.82.40 by Aaron Bentley
Started work on testing install_revisions/handling empty changesets
460
        s.seek(0)
1185.82.135 by Aaron Bentley
Ensure that bundles are bytestrings
461
        assert isinstance(s.getvalue(), str), (
462
            "Bundle isn't a bytestring:\n %s..." % repr(s.getvalue())[:40])
1793.2.2 by Aaron Bentley
Move BundleReader into v07 serializer
463
        install_bundle(tree.branch.repository, read_bundle(s))
1185.82.41 by Aaron Bentley
More work on installing changesets
464
        for ancestor in ancestors:
465
            old = self.b1.repository.revision_tree(ancestor)
466
            new = tree.branch.repository.revision_tree(ancestor)
1711.7.27 by John Arbash Meinel
Investigating why test_bundle fails, something isn't transmitting properly.
467
468
            # Check that there aren't any inventory level changes
1852.10.3 by Robert Collins
Remove all uses of compare_trees and replace with Tree.changes_from throughout bzrlib.
469
            delta = new.changes_from(old)
1711.7.32 by John Arbash Meinel
Switch from a trailing space to a beginning space, which is supported everywhere.
470
            self.assertFalse(delta.has_changed(),
471
                             'Revision %s not copied correctly.'
472
                             % (ancestor,))
1711.7.27 by John Arbash Meinel
Investigating why test_bundle fails, something isn't transmitting properly.
473
474
            # Now check that the file contents are all correct
1185.82.41 by Aaron Bentley
More work on installing changesets
475
            for inventory_id in old:
476
                try:
477
                    old_file = old.get_file(inventory_id)
1910.2.3 by Aaron Bentley
All tests pass
478
                except NoSuchFile:
1185.82.41 by Aaron Bentley
More work on installing changesets
479
                    continue
480
                if old_file is None:
481
                    continue
482
                self.assertEqual(old_file.read(),
483
                                 new.get_file(inventory_id).read())
1185.82.44 by Aaron Bentley
Switch to merge_changeset in test suite
484
        if rev_id is not None:
485
            rh = self.b1.revision_history()
486
            tree.branch.set_revision_history(rh[:rh.index(rev_id)+1])
487
            tree.update()
1852.10.3 by Robert Collins
Remove all uses of compare_trees and replace with Tree.changes_from throughout bzrlib.
488
            delta = tree.changes_from(self.b1.repository.revision_tree(rev_id))
1711.7.32 by John Arbash Meinel
Switch from a trailing space to a beginning space, which is supported everywhere.
489
            self.assertFalse(delta.has_changed(),
2255.10.5 by John Arbash Meinel
Fix a small bug when we have a symlink that does not need to be re-read.
490
                             'Working tree has modifications: %s' % delta)
1185.82.40 by Aaron Bentley
Started work on testing install_revisions/handling empty changesets
491
        return tree
0.5.80 by John Arbash Meinel
Starting to write tests for changeset, discovering some errors as I go.
492
1793.2.2 by Aaron Bentley
Move BundleReader into v07 serializer
493
    def valid_apply_bundle(self, base_rev_id, info, checkout_dir=None):
0.5.80 by John Arbash Meinel
Starting to write tests for changeset, discovering some errors as I go.
494
        """Get the base revision, apply the changes, and make
495
        sure everything matches the builtin branch.
496
        """
1185.82.17 by Aaron Bentley
More API updates
497
        to_tree = self.get_checkout(base_rev_id, checkout_dir=checkout_dir)
1908.6.4 by Robert Collins
Update to replaced parent checking api bzrlib/merge.py
498
        original_parents = to_tree.get_parent_ids()
1185.82.40 by Aaron Bentley
Started work on testing install_revisions/handling empty changesets
499
        repository = to_tree.branch.repository
1927.2.1 by Robert Collins
Alter set_pending_merges to shove the left most merge into the trees last-revision if that is not set. Related bugfixes include basis_tree handling ghosts, de-duping the merges with the last-revision and update changing where and how it adds its pending merge.
500
        original_parents = to_tree.get_parent_ids()
1185.82.41 by Aaron Bentley
More work on installing changesets
501
        self.assertIs(repository.has_revision(base_rev_id), True)
1185.82.40 by Aaron Bentley
Started work on testing install_revisions/handling empty changesets
502
        for rev in info.real_revisions:
503
            self.assert_(not repository.has_revision(rev.revision_id),
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
504
                'Revision {%s} present before applying bundle' 
1185.82.40 by Aaron Bentley
Started work on testing install_revisions/handling empty changesets
505
                % rev.revision_id)
1793.2.2 by Aaron Bentley
Move BundleReader into v07 serializer
506
        merge_bundle(info, 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.
507
508
        for rev in info.real_revisions:
1185.82.17 by Aaron Bentley
More API updates
509
            self.assert_(repository.has_revision(rev.revision_id),
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
510
                '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.
511
                % rev.revision_id)
512
1185.82.17 by Aaron Bentley
More API updates
513
        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.
514
        # 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.
515
1908.6.4 by Robert Collins
Update to replaced parent checking api bzrlib/merge.py
516
        self.assertEqual(original_parents + [info.target],
517
            to_tree.get_parent_ids())
0.5.86 by John Arbash Meinel
Updated the auto-commit functionality, and adding to pending-merges, more testing.
518
0.5.80 by John Arbash Meinel
Starting to write tests for changeset, discovering some errors as I go.
519
        rev = info.real_revisions[-1]
1185.82.17 by Aaron Bentley
More API updates
520
        base_tree = self.b1.repository.revision_tree(rev.revision_id)
521
        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.
522
        
523
        # 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.
524
        #       we might also check the working tree.
525
526
        base_files = list(base_tree.list_files())
527
        to_files = list(to_tree.list_files())
528
        self.assertEqual(len(base_files), len(to_files))
1185.82.66 by Aaron Bentley
Handle new executable files
529
        for base_file, to_file in zip(base_files, to_files):
530
            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.
531
0.5.117 by John Arbash Meinel
Almost there. Just need to track down a few remaining bugs.
532
        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.
533
            # Check that the meta information is the same
534
            self.assertEqual(base_tree.get_file_size(fileid),
535
                    to_tree.get_file_size(fileid))
536
            self.assertEqual(base_tree.get_file_sha1(fileid),
537
                    to_tree.get_file_sha1(fileid))
538
            # Check that the contents are the same
539
            # This is pretty expensive
540
            # self.assertEqual(base_tree.get_file(fileid).read(),
541
            #         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.
542
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
543
    def test_bundle(self):
1711.7.34 by John Arbash Meinel
Include a test to ensure bundles handle trailing whitespace.
544
        self.tree1 = self.make_branch_and_tree('b1')
1185.82.14 by Aaron Bentley
API updates
545
        self.b1 = self.tree1.branch
0.5.78 by John Arbash Meinel
Working on test cases, starting with the empty project issues.
546
1793.3.1 by John Arbash Meinel
Clean up the bundle tests a little bit.
547
        open('b1/one', 'wb').write('one\n')
1185.82.14 by Aaron Bentley
API updates
548
        self.tree1.add('one')
549
        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.
550
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
551
        bundle = self.get_valid_bundle(None, 'a@cset-0-1')
1793.3.1 by John Arbash Meinel
Clean up the bundle tests a little bit.
552
        # FIXME: The current write_bundle api no longer supports
553
        #        setting a custom summary message
554
        #        We should re-introduce the ability, and update
555
        #        the tests to make sure it works.
556
        # bundle = self.get_valid_bundle(None, 'a@cset-0-1',
557
        #         message='With a specialized message')
0.5.80 by John Arbash Meinel
Starting to write tests for changeset, discovering some errors as I go.
558
559
        # Make sure we can handle files with spaces, tabs, other
560
        # bogus characters
0.5.82 by John Arbash Meinel
Lots of changes, changing separators, updating tests, updated ChangesetTree to include text_ids
561
        self.build_tree([
0.5.84 by John Arbash Meinel
(broken) problem with removes.
562
                'b1/with space.txt'
563
                , 'b1/dir/'
564
                , 'b1/dir/filein subdir.c'
565
                , 'b1/dir/WithCaps.txt'
1711.7.32 by John Arbash Meinel
Switch from a trailing space to a beginning space, which is supported everywhere.
566
                , 'b1/dir/ pre space'
0.5.84 by John Arbash Meinel
(broken) problem with removes.
567
                , 'b1/sub/'
568
                , 'b1/sub/sub/'
569
                , '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
570
                ])
0.5.84 by John Arbash Meinel
(broken) problem with removes.
571
        open('b1/sub/sub/emptyfile.txt', 'wb').close()
0.5.94 by Aaron Bentley
Switched to native patch application, added tests for terminating newlines
572
        open('b1/dir/nolastnewline.txt', 'wb').write('bloop')
1185.82.66 by Aaron Bentley
Handle new executable files
573
        tt = TreeTransform(self.tree1)
574
        tt.new_file('executable', tt.root, '#!/bin/sh\n', 'exe-1', True)
575
        tt.apply()
1185.82.14 by Aaron Bentley
API updates
576
        self.tree1.add([
0.5.84 by John Arbash Meinel
(broken) problem with removes.
577
                'with space.txt'
578
                , 'dir'
579
                , 'dir/filein subdir.c'
580
                , 'dir/WithCaps.txt'
1711.7.32 by John Arbash Meinel
Switch from a trailing space to a beginning space, which is supported everywhere.
581
                , 'dir/ pre space'
0.5.94 by Aaron Bentley
Switched to native patch application, added tests for terminating newlines
582
                , 'dir/nolastnewline.txt'
0.5.84 by John Arbash Meinel
(broken) problem with removes.
583
                , 'sub'
584
                , 'sub/sub'
585
                , 'sub/sub/nonempty.txt'
586
                , 'sub/sub/emptyfile.txt'
0.5.82 by John Arbash Meinel
Lots of changes, changing separators, updating tests, updated ChangesetTree to include text_ids
587
                ])
1185.82.14 by Aaron Bentley
API updates
588
        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.
589
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
590
        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.
591
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
592
        # Check a rollup bundle 
593
        bundle = self.get_valid_bundle(None, 'a@cset-0-2')
0.5.84 by John Arbash Meinel
(broken) problem with removes.
594
595
        # Now delete entries
1185.82.21 by Aaron Bentley
Stop using deprecated function
596
        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.
597
                ['sub/sub/nonempty.txt'
0.5.84 by John Arbash Meinel
(broken) problem with removes.
598
                , '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.
599
                , 'sub/sub'
600
                ])
1185.82.68 by Aaron Bentley
Handle execute bit on modified files
601
        tt = TreeTransform(self.tree1)
602
        trans_id = tt.trans_id_tree_file_id('exe-1')
603
        tt.set_executability(False, trans_id)
604
        tt.apply()
1185.82.19 by Aaron Bentley
More API updates
605
        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.
606
        
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
607
        bundle = self.get_valid_bundle('a@cset-0-2', 'a@cset-0-3')
2520.4.71 by Aaron Bentley
Update test to accept VersionedFileInvalidChecksum instead of TestamentMismatch
608
        self.assertRaises((TestamentMismatch,
609
            errors.VersionedFileInvalidChecksum), self.get_invalid_bundle,
610
            'a@cset-0-2', 'a@cset-0-3')
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
611
        # Check a rollup bundle 
612
        bundle = self.get_valid_bundle(None, 'a@cset-0-3')
0.5.84 by John Arbash Meinel
(broken) problem with removes.
613
614
        # Now move the directory
1185.82.19 by Aaron Bentley
More API updates
615
        self.tree1.rename_one('dir', 'sub/dir')
616
        self.tree1.commit('rename dir', rev_id='a@cset-0-4')
0.5.84 by John Arbash Meinel
(broken) problem with removes.
617
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
618
        bundle = self.get_valid_bundle('a@cset-0-3', 'a@cset-0-4')
619
        # Check a rollup bundle 
620
        bundle = self.get_valid_bundle(None, 'a@cset-0-4')
0.5.84 by John Arbash Meinel
(broken) problem with removes.
621
0.5.87 by John Arbash Meinel
Handling international characters, added more test cases.
622
        # Modified files
623
        open('b1/sub/dir/WithCaps.txt', 'ab').write('\nAdding some text\n')
1711.7.32 by John Arbash Meinel
Switch from a trailing space to a beginning space, which is supported everywhere.
624
        open('b1/sub/dir/ pre space', 'ab').write('\r\nAdding some\r\nDOS format lines\r\n')
0.5.94 by Aaron Bentley
Switched to native patch application, added tests for terminating newlines
625
        open('b1/sub/dir/nolastnewline.txt', 'ab').write('\n')
1711.7.32 by John Arbash Meinel
Switch from a trailing space to a beginning space, which is supported everywhere.
626
        self.tree1.rename_one('sub/dir/ pre space', 
627
                              'sub/ start space')
1185.82.19 by Aaron Bentley
More API updates
628
        self.tree1.commit('Modified files', rev_id='a@cset-0-5')
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
629
        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.
630
1185.82.70 by Aaron Bentley
Handle renamed files better
631
        self.tree1.rename_one('sub/dir/WithCaps.txt', 'temp')
632
        self.tree1.rename_one('with space.txt', 'WithCaps.txt')
633
        self.tree1.rename_one('temp', 'with space.txt')
1711.7.35 by John Arbash Meinel
Factor out i18n bundle tests, so we don't always skip.
634
        self.tree1.commit(u'swap filenames', rev_id='a@cset-0-6',
635
                          verbose=False)
636
        bundle = self.get_valid_bundle('a@cset-0-5', 'a@cset-0-6')
637
        other = self.get_checkout('a@cset-0-5')
1910.2.62 by Aaron Bentley
Cleanups
638
        tree1_inv = self.tree1.branch.repository.get_inventory_xml(
639
            'a@cset-0-5')
1910.2.54 by Aaron Bentley
Implement testament format 3 strict
640
        tree2_inv = other.branch.repository.get_inventory_xml('a@cset-0-5')
641
        self.assertEqualDiff(tree1_inv, tree2_inv)
1711.7.35 by John Arbash Meinel
Factor out i18n bundle tests, so we don't always skip.
642
        other.rename_one('sub/dir/nolastnewline.txt', 'sub/nolastnewline.txt')
643
        other.commit('rename file', rev_id='a@cset-0-6b')
1996.3.5 by John Arbash Meinel
Cleanup, deprecated, and get the tests passing again.
644
        _merge_helper([other.basedir, -1], [None, None],
645
                      this_dir=self.tree1.basedir)
1711.7.35 by John Arbash Meinel
Factor out i18n bundle tests, so we don't always skip.
646
        self.tree1.commit(u'Merge', rev_id='a@cset-0-7',
1185.82.70 by Aaron Bentley
Handle renamed files better
647
                          verbose=False)
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
648
        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
649
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
650
    def test_symlink_bundle(self):
1185.82.87 by Aaron Bentley
Got symlink adding working
651
        if not has_symlinks():
652
            raise TestSkipped("No symlink support")
1910.2.50 by Aaron Bentley
start work on format 0.9 serializer
653
        self.tree1 = self.make_branch_and_tree('b1')
1185.82.87 by Aaron Bentley
Got symlink adding working
654
        self.b1 = self.tree1.branch
655
        tt = TreeTransform(self.tree1)
1185.82.88 by Aaron Bentley
Get symlink modification, renames and deletion under test
656
        tt.new_symlink('link', tt.root, 'bar/foo', 'link-1')
1185.82.87 by Aaron Bentley
Got symlink adding working
657
        tt.apply()
658
        self.tree1.commit('add symlink', rev_id='l@cset-0-1')
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
659
        self.get_valid_bundle(None, 'l@cset-0-1')
1185.82.88 by Aaron Bentley
Get symlink modification, renames and deletion under test
660
        tt = TreeTransform(self.tree1)
661
        trans_id = tt.trans_id_tree_file_id('link-1')
662
        tt.adjust_path('link2', tt.root, trans_id)
663
        tt.delete_contents(trans_id)
664
        tt.create_symlink('mars', trans_id)
665
        tt.apply()
666
        self.tree1.commit('rename and change symlink', rev_id='l@cset-0-2')
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
667
        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
668
        tt = TreeTransform(self.tree1)
669
        trans_id = tt.trans_id_tree_file_id('link-1')
670
        tt.delete_contents(trans_id)
671
        tt.create_symlink('jupiter', trans_id)
672
        tt.apply()
673
        self.tree1.commit('just change symlink target', rev_id='l@cset-0-3')
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
674
        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
675
        tt = TreeTransform(self.tree1)
676
        trans_id = tt.trans_id_tree_file_id('link-1')
677
        tt.delete_contents(trans_id)
678
        tt.apply()
679
        self.tree1.commit('Delete symlink', rev_id='l@cset-0-4')
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
680
        self.get_valid_bundle('l@cset-0-3', 'l@cset-0-4')
1185.82.96 by Aaron Bentley
Got first binary test passing
681
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
682
    def test_binary_bundle(self):
1910.2.50 by Aaron Bentley
start work on format 0.9 serializer
683
        self.tree1 = self.make_branch_and_tree('b1')
1185.82.96 by Aaron Bentley
Got first binary test passing
684
        self.b1 = self.tree1.branch
685
        tt = TreeTransform(self.tree1)
1848.1.1 by John Arbash Meinel
fix bug in bundle handling of binary files with just '\r' in them.
686
        
687
        # Add
688
        tt.new_file('file', tt.root, '\x00\n\x00\r\x01\n\x02\r\xff', 'binary-1')
689
        tt.new_file('file2', tt.root, '\x01\n\x02\r\x03\n\x04\r\xff', 'binary-2')
1185.82.96 by Aaron Bentley
Got first binary test passing
690
        tt.apply()
691
        self.tree1.commit('add binary', rev_id='b@cset-0-1')
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
692
        self.get_valid_bundle(None, 'b@cset-0-1')
1848.1.1 by John Arbash Meinel
fix bug in bundle handling of binary files with just '\r' in them.
693
694
        # Delete
1185.82.97 by Aaron Bentley
Got binary files working for adds, renames, modifications
695
        tt = TreeTransform(self.tree1)
696
        trans_id = tt.trans_id_tree_file_id('binary-1')
697
        tt.delete_contents(trans_id)
698
        tt.apply()
699
        self.tree1.commit('delete binary', rev_id='b@cset-0-2')
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
700
        self.get_valid_bundle('b@cset-0-1', 'b@cset-0-2')
1848.1.1 by John Arbash Meinel
fix bug in bundle handling of binary files with just '\r' in them.
701
702
        # Rename & modify
1185.82.97 by Aaron Bentley
Got binary files working for adds, renames, modifications
703
        tt = TreeTransform(self.tree1)
704
        trans_id = tt.trans_id_tree_file_id('binary-2')
705
        tt.adjust_path('file3', tt.root, trans_id)
706
        tt.delete_contents(trans_id)
1848.1.1 by John Arbash Meinel
fix bug in bundle handling of binary files with just '\r' in them.
707
        tt.create_file('file\rcontents\x00\n\x00', trans_id)
1185.82.97 by Aaron Bentley
Got binary files working for adds, renames, modifications
708
        tt.apply()
709
        self.tree1.commit('rename and modify binary', rev_id='b@cset-0-3')
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
710
        self.get_valid_bundle('b@cset-0-2', 'b@cset-0-3')
1848.1.1 by John Arbash Meinel
fix bug in bundle handling of binary files with just '\r' in them.
711
712
        # Modify
1185.82.97 by Aaron Bentley
Got binary files working for adds, renames, modifications
713
        tt = TreeTransform(self.tree1)
714
        trans_id = tt.trans_id_tree_file_id('binary-2')
715
        tt.delete_contents(trans_id)
1848.1.1 by John Arbash Meinel
fix bug in bundle handling of binary files with just '\r' in them.
716
        tt.create_file('\x00file\rcontents', trans_id)
1185.82.97 by Aaron Bentley
Got binary files working for adds, renames, modifications
717
        tt.apply()
718
        self.tree1.commit('just modify binary', rev_id='b@cset-0-4')
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
719
        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
720
1848.1.1 by John Arbash Meinel
fix bug in bundle handling of binary files with just '\r' in them.
721
        # Rollup
722
        self.get_valid_bundle(None, 'b@cset-0-4')
723
1185.82.115 by Aaron Bentley
Add test for last-changed special cases
724
    def test_last_modified(self):
1910.2.50 by Aaron Bentley
start work on format 0.9 serializer
725
        self.tree1 = self.make_branch_and_tree('b1')
1185.82.115 by Aaron Bentley
Add test for last-changed special cases
726
        self.b1 = self.tree1.branch
727
        tt = TreeTransform(self.tree1)
728
        tt.new_file('file', tt.root, 'file', 'file')
729
        tt.apply()
730
        self.tree1.commit('create file', rev_id='a@lmod-0-1')
731
732
        tt = TreeTransform(self.tree1)
733
        trans_id = tt.trans_id_tree_file_id('file')
734
        tt.delete_contents(trans_id)
735
        tt.create_file('file2', trans_id)
736
        tt.apply()
737
        self.tree1.commit('modify text', rev_id='a@lmod-0-2a')
738
739
        other = self.get_checkout('a@lmod-0-1')
740
        tt = TreeTransform(other)
741
        trans_id = tt.trans_id_tree_file_id('file')
742
        tt.delete_contents(trans_id)
743
        tt.create_file('file2', trans_id)
744
        tt.apply()
745
        other.commit('modify text in another tree', rev_id='a@lmod-0-2b')
1996.3.5 by John Arbash Meinel
Cleanup, deprecated, and get the tests passing again.
746
        _merge_helper([other.basedir, -1], [None, None],
747
                      this_dir=self.tree1.basedir)
1185.82.115 by Aaron Bentley
Add test for last-changed special cases
748
        self.tree1.commit(u'Merge', rev_id='a@lmod-0-3',
749
                          verbose=False)
750
        self.tree1.commit(u'Merge', rev_id='a@lmod-0-4')
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
751
        bundle = self.get_valid_bundle('a@lmod-0-2a', 'a@lmod-0-4')
1185.84.3 by Aaron Bentley
Hide diffs for old revisions in bundles
752
753
    def test_hide_history(self):
1910.2.50 by Aaron Bentley
start work on format 0.9 serializer
754
        self.tree1 = self.make_branch_and_tree('b1')
1185.84.3 by Aaron Bentley
Hide diffs for old revisions in bundles
755
        self.b1 = self.tree1.branch
756
1793.3.1 by John Arbash Meinel
Clean up the bundle tests a little bit.
757
        open('b1/one', 'wb').write('one\n')
1185.84.3 by Aaron Bentley
Hide diffs for old revisions in bundles
758
        self.tree1.add('one')
759
        self.tree1.commit('add file', rev_id='a@cset-0-1')
1793.3.1 by John Arbash Meinel
Clean up the bundle tests a little bit.
760
        open('b1/one', 'wb').write('two\n')
1185.84.3 by Aaron Bentley
Hide diffs for old revisions in bundles
761
        self.tree1.commit('modify', rev_id='a@cset-0-2')
1793.3.1 by John Arbash Meinel
Clean up the bundle tests a little bit.
762
        open('b1/one', 'wb').write('three\n')
1185.84.3 by Aaron Bentley
Hide diffs for old revisions in bundles
763
        self.tree1.commit('modify', rev_id='a@cset-0-3')
764
        bundle_file = StringIO()
765
        rev_ids = write_bundle(self.tree1.branch.repository, 'a@cset-0-3',
1910.2.51 by Aaron Bentley
Bundles now corrupt repositories
766
                               'a@cset-0-1', bundle_file, format=self.format)
2382.1.1 by Ian Clatworthy
Fixes #98510 - bundle selftest fails if email has 'two' embedded
767
        self.assertNotContainsRe(bundle_file.getvalue(), '\btwo\b')
2520.4.32 by Aaron Bentley
Fix test case
768
        self.assertContainsRe(self.get_raw(bundle_file), 'one')
769
        self.assertContainsRe(self.get_raw(bundle_file), 'three')
770
771
    @staticmethod
772
    def get_raw(bundle_file):
773
        return bundle_file.getvalue()
1793.3.2 by John Arbash Meinel
(failing) add some tests which munge trailing whitespace
774
1711.7.35 by John Arbash Meinel
Factor out i18n bundle tests, so we don't always skip.
775
    def test_unicode_bundle(self):
776
        # Handle international characters
777
        os.mkdir('b1')
778
        try:
779
            f = open(u'b1/with Dod\xe9', 'wb')
780
        except UnicodeEncodeError:
781
            raise TestSkipped("Filesystem doesn't support unicode")
782
783
        self.tree1 = self.make_branch_and_tree('b1')
784
        self.b1 = self.tree1.branch
785
786
        f.write((u'A file\n'
787
            u'With international man of mystery\n'
788
            u'William Dod\xe9\n').encode('utf-8'))
789
        f.close()
790
2386.1.1 by John Arbash Meinel
Update test_unicode_bundle, since we know how it fails on Mac OSX
791
        self.tree1.add([u'with Dod\xe9'], ['withdod-id'])
792
        self.tree1.commit(u'i18n commit from William Dod\xe9',
1711.7.35 by John Arbash Meinel
Factor out i18n bundle tests, so we don't always skip.
793
                          rev_id='i18n-1', committer=u'William Dod\xe9')
794
2386.1.1 by John Arbash Meinel
Update test_unicode_bundle, since we know how it fails on Mac OSX
795
        if sys.platform == 'darwin':
796
            # On Mac the '\xe9' gets changed to 'e\u0301'
797
            self.assertEqual([u'.bzr', u'with Dode\u0301'],
798
                             sorted(os.listdir(u'b1')))
799
            delta = self.tree1.changes_from(self.tree1.basis_tree())
800
            self.assertEqual([(u'with Dod\xe9', 'withdod-id', 'file')],
801
                             delta.removed)
802
            self.knownFailure("Mac OSX doesn't preserve unicode"
803
                              " combining characters.")
804
1711.7.35 by John Arbash Meinel
Factor out i18n bundle tests, so we don't always skip.
805
        # Add
806
        bundle = self.get_valid_bundle(None, 'i18n-1')
807
808
        # Modified
809
        f = open(u'b1/with Dod\xe9', 'wb')
810
        f.write(u'Modified \xb5\n'.encode('utf8'))
811
        f.close()
812
        self.tree1.commit(u'modified', rev_id='i18n-2')
813
814
        bundle = self.get_valid_bundle('i18n-1', 'i18n-2')
815
        
816
        # Renamed
817
        self.tree1.rename_one(u'with Dod\xe9', u'B\xe5gfors')
818
        self.tree1.commit(u'renamed, the new i18n man', rev_id='i18n-3',
819
                          committer=u'Erik B\xe5gfors')
820
821
        bundle = self.get_valid_bundle('i18n-2', 'i18n-3')
822
823
        # Removed
824
        self.tree1.remove([u'B\xe5gfors'])
825
        self.tree1.commit(u'removed', rev_id='i18n-4')
826
827
        bundle = self.get_valid_bundle('i18n-3', 'i18n-4')
828
829
        # Rollup
830
        bundle = self.get_valid_bundle(None, 'i18n-4')
831
832
1711.7.34 by John Arbash Meinel
Include a test to ensure bundles handle trailing whitespace.
833
    def test_whitespace_bundle(self):
834
        if sys.platform in ('win32', 'cygwin'):
835
            raise TestSkipped('Windows doesn\'t support filenames'
836
                              ' with tabs or trailing spaces')
837
        self.tree1 = self.make_branch_and_tree('b1')
838
        self.b1 = self.tree1.branch
839
840
        self.build_tree(['b1/trailing space '])
841
        self.tree1.add(['trailing space '])
842
        # TODO: jam 20060701 Check for handling files with '\t' characters
843
        #       once we actually support them
844
845
        # Added
846
        self.tree1.commit('funky whitespace', rev_id='white-1')
847
848
        bundle = self.get_valid_bundle(None, 'white-1')
849
850
        # Modified
851
        open('b1/trailing space ', 'ab').write('add some text\n')
852
        self.tree1.commit('add text', rev_id='white-2')
853
854
        bundle = self.get_valid_bundle('white-1', 'white-2')
855
856
        # Renamed
857
        self.tree1.rename_one('trailing space ', ' start and end space ')
858
        self.tree1.commit('rename', rev_id='white-3')
859
860
        bundle = self.get_valid_bundle('white-2', 'white-3')
861
862
        # Removed
863
        self.tree1.remove([' start and end space '])
864
        self.tree1.commit('removed', rev_id='white-4')
865
866
        bundle = self.get_valid_bundle('white-3', 'white-4')
867
        
868
        # Now test a complet roll-up
869
        bundle = self.get_valid_bundle(None, 'white-4')
870
1793.3.9 by John Arbash Meinel
Add a test to timezone for non integer tz offsets
871
    def test_alt_timezone_bundle(self):
1986.1.2 by Robert Collins
Various changes to allow non-workingtree specific tests to run entirely
872
        self.tree1 = self.make_branch_and_memory_tree('b1')
1793.3.9 by John Arbash Meinel
Add a test to timezone for non integer tz offsets
873
        self.b1 = self.tree1.branch
1986.1.2 by Robert Collins
Various changes to allow non-workingtree specific tests to run entirely
874
        builder = treebuilder.TreeBuilder()
1793.3.9 by John Arbash Meinel
Add a test to timezone for non integer tz offsets
875
1986.1.2 by Robert Collins
Various changes to allow non-workingtree specific tests to run entirely
876
        self.tree1.lock_write()
877
        builder.start_tree(self.tree1)
878
        builder.build(['newfile'])
879
        builder.finish_tree()
1793.3.9 by John Arbash Meinel
Add a test to timezone for non integer tz offsets
880
881
        # Asia/Colombo offset = 5 hours 30 minutes
882
        self.tree1.commit('non-hour offset timezone', rev_id='tz-1',
883
                          timezone=19800, timestamp=1152544886.0)
884
885
        bundle = self.get_valid_bundle(None, 'tz-1')
886
        
887
        rev = bundle.revisions[0]
888
        self.assertEqual('Mon 2006-07-10 20:51:26.000000000 +0530', rev.date)
889
        self.assertEqual(19800, rev.timezone)
890
        self.assertEqual(1152544886.0, rev.timestamp)
1986.1.2 by Robert Collins
Various changes to allow non-workingtree specific tests to run entirely
891
        self.tree1.unlock()
1793.3.9 by John Arbash Meinel
Add a test to timezone for non integer tz offsets
892
1910.2.1 by Aaron Bentley
Ensure root entry always has a revision
893
    def test_bundle_root_id(self):
894
        self.tree1 = self.make_branch_and_tree('b1')
895
        self.b1 = self.tree1.branch
896
        self.tree1.commit('message', rev_id='revid1')
897
        bundle = self.get_valid_bundle(None, 'revid1')
898
        tree = bundle.revision_tree(self.b1.repository, 'revid1')
1910.2.6 by Aaron Bentley
Update for merge review, handle deprecations
899
        self.assertEqual('revid1', tree.inventory.root.revision)
1910.2.1 by Aaron Bentley
Ensure root entry always has a revision
900
1551.14.9 by Aaron Bentley
rename get_target_revision to install_revisions
901
    def test_install_revisions(self):
1551.14.4 by Aaron Bentley
Change bundle reader and merge directive to both be 'mergeables'
902
        self.tree1 = self.make_branch_and_tree('b1')
903
        self.b1 = self.tree1.branch
904
        self.tree1.commit('message', rev_id='rev2a')
905
        bundle = self.get_valid_bundle(None, 'rev2a')
906
        branch2 = self.make_branch('b2')
907
        self.assertFalse(branch2.repository.has_revision('rev2a'))
1551.14.9 by Aaron Bentley
rename get_target_revision to install_revisions
908
        target_revision = bundle.install_revisions(branch2.repository)
1551.14.4 by Aaron Bentley
Change bundle reader and merge directive to both be 'mergeables'
909
        self.assertTrue(branch2.repository.has_revision('rev2a'))
1551.14.9 by Aaron Bentley
rename get_target_revision to install_revisions
910
        self.assertEqual('rev2a', target_revision)
1551.14.4 by Aaron Bentley
Change bundle reader and merge directive to both be 'mergeables'
911
2447.1.2 by John Arbash Meinel
Add tests that we handle empty values whether they end in ': \n' or ':\n'.
912
    def test_bundle_empty_property(self):
913
        """Test serializing revision properties with an empty value."""
914
        tree = self.make_branch_and_memory_tree('tree')
915
        tree.lock_write()
916
        self.addCleanup(tree.unlock)
917
        tree.add([''], ['TREE_ROOT'])
918
        tree.commit('One', revprops={'one':'two', 'empty':''}, rev_id='rev1')
919
        self.b1 = tree.branch
920
        bundle_sio, revision_ids = self.create_bundle_text(None, 'rev1')
2520.4.33 by Aaron Bentley
remove test dependencies on serialization minutia
921
        bundle = read_bundle(bundle_sio)
922
        revision_info = bundle.revisions[0]
923
        self.assertEqual('rev1', revision_info.revision_id)
924
        rev = revision_info.as_revision()
925
        self.assertEqual({'branch-nick':'tree', 'empty':'', 'one':'two'},
926
                         rev.properties)
927
928
    def test_bundle_sorted_properties(self):
929
        """For stability the writer should write properties in sorted order."""
930
        tree = self.make_branch_and_memory_tree('tree')
931
        tree.lock_write()
932
        self.addCleanup(tree.unlock)
933
934
        tree.add([''], ['TREE_ROOT'])
935
        tree.commit('One', rev_id='rev1',
936
                    revprops={'a':'4', 'b':'3', 'c':'2', 'd':'1'})
937
        self.b1 = tree.branch
938
        bundle_sio, revision_ids = self.create_bundle_text(None, 'rev1')
939
        bundle = read_bundle(bundle_sio)
940
        revision_info = bundle.revisions[0]
941
        self.assertEqual('rev1', revision_info.revision_id)
942
        rev = revision_info.as_revision()
943
        self.assertEqual({'branch-nick':'tree', 'a':'4', 'b':'3', 'c':'2',
944
                          'd':'1'}, rev.properties)
945
946
    def test_bundle_unicode_properties(self):
947
        """We should be able to round trip a non-ascii property."""
948
        tree = self.make_branch_and_memory_tree('tree')
949
        tree.lock_write()
950
        self.addCleanup(tree.unlock)
951
952
        tree.add([''], ['TREE_ROOT'])
953
        # Revisions themselves do not require anything about revision property
954
        # keys, other than that they are a basestring, and do not contain
955
        # whitespace.
956
        # However, Testaments assert than they are str(), and thus should not
957
        # be Unicode.
958
        tree.commit('One', rev_id='rev1',
959
                    revprops={'omega':u'\u03a9', 'alpha':u'\u03b1'})
960
        self.b1 = tree.branch
961
        bundle_sio, revision_ids = self.create_bundle_text(None, 'rev1')
962
        bundle = read_bundle(bundle_sio)
963
        revision_info = bundle.revisions[0]
964
        self.assertEqual('rev1', revision_info.revision_id)
965
        rev = revision_info.as_revision()
966
        self.assertEqual({'branch-nick':'tree', 'omega':u'\u03a9',
967
                          'alpha':u'\u03b1'}, rev.properties)
968
2520.4.43 by Aaron Bentley
Fix test suite
969
    def test_bundle_with_ghosts(self):
970
        tree = self.make_branch_and_tree('tree')
971
        self.b1 = tree.branch
972
        self.build_tree_contents([('tree/file', 'content1')])
973
        tree.add(['file'])
974
        tree.commit('rev1')
975
        self.build_tree_contents([('tree/file', 'content2')])
976
        tree.add_parent_tree_id('ghost')
977
        tree.commit('rev2', rev_id='rev2')
978
        bundle = self.get_valid_bundle(None, 'rev2')
979
980
981
class V08BundleTester(BundleTester, TestCaseWithTransport):
2520.4.33 by Aaron Bentley
remove test dependencies on serialization minutia
982
983
    format = '0.8'
984
985
    def test_bundle_empty_property(self):
986
        """Test serializing revision properties with an empty value."""
987
        tree = self.make_branch_and_memory_tree('tree')
988
        tree.lock_write()
989
        self.addCleanup(tree.unlock)
990
        tree.add([''], ['TREE_ROOT'])
991
        tree.commit('One', revprops={'one':'two', 'empty':''}, rev_id='rev1')
992
        self.b1 = tree.branch
993
        bundle_sio, revision_ids = self.create_bundle_text(None, 'rev1')
2447.1.2 by John Arbash Meinel
Add tests that we handle empty values whether they end in ': \n' or ':\n'.
994
        self.assertContainsRe(bundle_sio.getvalue(),
995
                              '# properties:\n'
996
                              '#   branch-nick: tree\n'
2447.1.3 by John Arbash Meinel
Change the default serializer to include a trailing whitespace for empty properties.
997
                              '#   empty: \n'
2447.1.2 by John Arbash Meinel
Add tests that we handle empty values whether they end in ': \n' or ':\n'.
998
                              '#   one: two\n'
999
                             )
1000
        bundle = read_bundle(bundle_sio)
1001
        revision_info = bundle.revisions[0]
1002
        self.assertEqual('rev1', revision_info.revision_id)
1003
        rev = revision_info.as_revision()
1004
        self.assertEqual({'branch-nick':'tree', 'empty':'', 'one':'two'},
1005
                         rev.properties)
1006
1007
    def test_bundle_empty_property_alt(self):
2447.1.3 by John Arbash Meinel
Change the default serializer to include a trailing whitespace for empty properties.
1008
        """Test serializing revision properties with an empty value.
1009
1010
        Older readers had a bug when reading an empty property.
1011
        They assumed that all keys ended in ': \n'. However they would write an
1012
        empty value as ':\n'. This tests make sure that all newer bzr versions
1013
        can handle th second form.
1014
        """
2447.1.2 by John Arbash Meinel
Add tests that we handle empty values whether they end in ': \n' or ':\n'.
1015
        tree = self.make_branch_and_memory_tree('tree')
1016
        tree.lock_write()
1017
        self.addCleanup(tree.unlock)
1018
        tree.add([''], ['TREE_ROOT'])
1019
        tree.commit('One', revprops={'one':'two', 'empty':''}, rev_id='rev1')
1020
        self.b1 = tree.branch
1021
        bundle_sio, revision_ids = self.create_bundle_text(None, 'rev1')
1022
        txt = bundle_sio.getvalue()
2447.1.3 by John Arbash Meinel
Change the default serializer to include a trailing whitespace for empty properties.
1023
        loc = txt.find('#   empty: ') + len('#   empty:')
1024
        # Create a new bundle, which strips the trailing space after empty
1025
        bundle_sio = StringIO(txt[:loc] + txt[loc+1:])
2447.1.2 by John Arbash Meinel
Add tests that we handle empty values whether they end in ': \n' or ':\n'.
1026
1027
        self.assertContainsRe(bundle_sio.getvalue(),
1028
                              '# properties:\n'
1029
                              '#   branch-nick: tree\n'
2447.1.3 by John Arbash Meinel
Change the default serializer to include a trailing whitespace for empty properties.
1030
                              '#   empty:\n'
2447.1.2 by John Arbash Meinel
Add tests that we handle empty values whether they end in ': \n' or ':\n'.
1031
                              '#   one: two\n'
1032
                             )
1033
        bundle = read_bundle(bundle_sio)
1034
        revision_info = bundle.revisions[0]
1035
        self.assertEqual('rev1', revision_info.revision_id)
1036
        rev = revision_info.as_revision()
1037
        self.assertEqual({'branch-nick':'tree', 'empty':'', 'one':'two'},
1038
                         rev.properties)
1039
2447.1.1 by John Arbash Meinel
For stability and ease of testing, write properties in sorted order.
1040
    def test_bundle_sorted_properties(self):
1041
        """For stability the writer should write properties in sorted order."""
1042
        tree = self.make_branch_and_memory_tree('tree')
1043
        tree.lock_write()
1044
        self.addCleanup(tree.unlock)
1045
1046
        tree.add([''], ['TREE_ROOT'])
1047
        tree.commit('One', rev_id='rev1',
1048
                    revprops={'a':'4', 'b':'3', 'c':'2', 'd':'1'})
1049
        self.b1 = tree.branch
1050
        bundle_sio, revision_ids = self.create_bundle_text(None, 'rev1')
1051
        self.assertContainsRe(bundle_sio.getvalue(),
1052
                              '# properties:\n'
1053
                              '#   a: 4\n'
1054
                              '#   b: 3\n'
1055
                              '#   branch-nick: tree\n'
1056
                              '#   c: 2\n'
1057
                              '#   d: 1\n'
1058
                             )
2447.1.4 by John Arbash Meinel
Add a test that we properly round-trip unicode properties.
1059
        bundle = read_bundle(bundle_sio)
1060
        revision_info = bundle.revisions[0]
1061
        self.assertEqual('rev1', revision_info.revision_id)
1062
        rev = revision_info.as_revision()
1063
        self.assertEqual({'branch-nick':'tree', 'a':'4', 'b':'3', 'c':'2',
1064
                          'd':'1'}, rev.properties)
1065
1066
    def test_bundle_unicode_properties(self):
1067
        """We should be able to round trip a non-ascii property."""
1068
        tree = self.make_branch_and_memory_tree('tree')
1069
        tree.lock_write()
1070
        self.addCleanup(tree.unlock)
1071
1072
        tree.add([''], ['TREE_ROOT'])
1073
        # Revisions themselves do not require anything about revision property
1074
        # keys, other than that they are a basestring, and do not contain
1075
        # whitespace.
1076
        # However, Testaments assert than they are str(), and thus should not
1077
        # be Unicode.
1078
        tree.commit('One', rev_id='rev1',
1079
                    revprops={'omega':u'\u03a9', 'alpha':u'\u03b1'})
1080
        self.b1 = tree.branch
1081
        bundle_sio, revision_ids = self.create_bundle_text(None, 'rev1')
1082
        self.assertContainsRe(bundle_sio.getvalue(),
1083
                              '# properties:\n'
1084
                              '#   alpha: \xce\xb1\n'
1085
                              '#   branch-nick: tree\n'
1086
                              '#   omega: \xce\xa9\n'
1087
                             )
1088
        bundle = read_bundle(bundle_sio)
1089
        revision_info = bundle.revisions[0]
1090
        self.assertEqual('rev1', revision_info.revision_id)
1091
        rev = revision_info.as_revision()
1092
        self.assertEqual({'branch-nick':'tree', 'omega':u'\u03a9',
1093
                          'alpha':u'\u03b1'}, rev.properties)
2447.1.1 by John Arbash Meinel
For stability and ease of testing, write properties in sorted order.
1094
1793.3.2 by John Arbash Meinel
(failing) add some tests which munge trailing whitespace
1095
1910.2.59 by Aaron Bentley
Test 0.9 bundles for knit format1 and knit format2
1096
class V09BundleKnit2Tester(V08BundleTester):
1910.2.50 by Aaron Bentley
start work on format 0.9 serializer
1097
1098
    format = '0.9'
1099
1100
    def bzrdir_format(self):
1101
        format = bzrdir.BzrDirMetaFormat1()
2255.2.211 by Robert Collins
Remove knit2 repository format- it has never been supported.
1102
        format.repository_format = knitrepo.RepositoryFormatKnit3()
1910.2.50 by Aaron Bentley
start work on format 0.9 serializer
1103
        return format
1104
1105
1910.2.59 by Aaron Bentley
Test 0.9 bundles for knit format1 and knit format2
1106
class V09BundleKnit1Tester(V08BundleTester):
1107
1108
    format = '0.9'
1109
1110
    def bzrdir_format(self):
1111
        format = bzrdir.BzrDirMetaFormat1()
2241.1.6 by Martin Pool
Move Knit repositories into the submodule bzrlib.repofmt.knitrepo and
1112
        format.repository_format = knitrepo.RepositoryFormatKnit1()
1910.2.59 by Aaron Bentley
Test 0.9 bundles for knit format1 and knit format2
1113
        return format
1114
1115
2520.4.72 by Aaron Bentley
Rename format to 4alpha
1116
class V4BundleTester(BundleTester, TestCaseWithTransport):
2520.4.14 by Aaron Bentley
Get most tests passing, use format header
1117
2520.4.72 by Aaron Bentley
Rename format to 4alpha
1118
    format = '4alpha'
2520.4.14 by Aaron Bentley
Get most tests passing, use format header
1119
1120
    def get_valid_bundle(self, base_rev_id, rev_id, checkout_dir=None):
1121
        """Create a bundle from base_rev_id -> rev_id in built-in branch.
1122
        Make sure that the text generated is valid, and that it
1123
        can be applied against the base, and generate the same information.
1124
        
1125
        :return: The in-memory bundle 
1126
        """
1127
        bundle_txt, rev_ids = self.create_bundle_text(base_rev_id, rev_id)
1128
1129
        # This should also validate the generated bundle 
1130
        bundle = read_bundle(bundle_txt)
1131
        repository = self.b1.repository
1132
        for bundle_rev in bundle.real_revisions:
1133
            # These really should have already been checked when we read the
1134
            # bundle, since it computes the sha1 hash for the revision, which
1135
            # only will match if everything is okay, but lets be explicit about
1136
            # it
1137
            branch_rev = repository.get_revision(bundle_rev.revision_id)
1138
            for a in ('inventory_sha1', 'revision_id', 'parent_ids',
1139
                      'timestamp', 'timezone', 'message', 'committer', 
1140
                      'parent_ids', 'properties'):
1141
                self.assertEqual(getattr(branch_rev, a), 
1142
                                 getattr(bundle_rev, a))
1143
            self.assertEqual(len(branch_rev.parent_ids), 
1144
                             len(bundle_rev.parent_ids))
2520.4.29 by Aaron Bentley
Reactivate some testing, fix topo_iter
1145
        self.assertEqual(set(rev_ids),
1146
                         set([r.revision_id for r in bundle.real_revisions]))
2520.4.14 by Aaron Bentley
Get most tests passing, use format header
1147
        self.valid_apply_bundle(base_rev_id, bundle,
1148
                                   checkout_dir=checkout_dir)
1149
1150
        return bundle
1151
2520.4.34 by Aaron Bentley
Add signature support
1152
    def get_invalid_bundle(self, base_rev_id, rev_id):
1153
        """Create a bundle from base_rev_id -> rev_id in built-in branch.
1154
        Munge the text so that it's invalid.
1155
1156
        :return: The in-memory bundle
1157
        """
1158
        from bzrlib.bundle import serializer
1159
        bundle_txt, rev_ids = self.create_bundle_text(base_rev_id, rev_id)
1160
        new_text = self.get_raw(StringIO(''.join(bundle_txt)))
1161
        new_text = new_text.replace('<file file_id="exe-1"',
1162
                                    '<file executable="y" file_id="exe-1"')
2520.4.70 by Aaron Bentley
Yank patch-handling functionality
1163
        new_text = new_text.replace('B407', 'B422')
2520.4.34 by Aaron Bentley
Add signature support
1164
        bundle_txt = StringIO()
2520.4.72 by Aaron Bentley
Rename format to 4alpha
1165
        bundle_txt.write(serializer._get_bundle_header('4alpha'))
2520.4.34 by Aaron Bentley
Add signature support
1166
        bundle_txt.write('\n')
1167
        bundle_txt.write(new_text.encode('bz2').encode('base-64'))
1168
        bundle_txt.seek(0)
1169
        bundle = read_bundle(bundle_txt)
1170
        self.valid_apply_bundle(base_rev_id, bundle)
1171
        return bundle
1172
2520.4.14 by Aaron Bentley
Get most tests passing, use format header
1173
    def create_bundle_text(self, base_rev_id, rev_id):
1174
        bundle_txt = StringIO()
1175
        rev_ids = write_bundle(self.b1.repository, rev_id, base_rev_id, 
1176
                               bundle_txt, format=self.format)
1177
        bundle_txt.seek(0)
1178
        self.assertEqual(bundle_txt.readline(), 
1179
                         '# Bazaar revision bundle v%s\n' % self.format)
1180
        self.assertEqual(bundle_txt.readline(), '#\n')
1181
1182
        rev = self.b1.repository.get_revision(rev_id)
1183
1184
        open(',,bundle', 'wb').write(bundle_txt.getvalue())
1185
        bundle_txt.seek(0)
1186
        return bundle_txt, rev_ids
2520.4.4 by Aaron Bentley
Get basis support for a new bundle format in place
1187
1188
    def test_creation(self):
1189
        tree = self.make_branch_and_tree('tree')
2520.4.8 by Aaron Bentley
Serialize inventory
1190
        self.build_tree_contents([('tree/file', 'contents1\nstatic\n')])
2520.4.6 by Aaron Bentley
Get installation started
1191
        tree.add('file', 'fileid-2')
2520.4.4 by Aaron Bentley
Get basis support for a new bundle format in place
1192
        tree.commit('added file', rev_id='rev1')
2520.4.8 by Aaron Bentley
Serialize inventory
1193
        self.build_tree_contents([('tree/file', 'contents2\nstatic\n')])
2520.4.10 by Aaron Bentley
Enable installation of revisions
1194
        tree.commit('changed file', rev_id='rev2')
2520.4.4 by Aaron Bentley
Get basis support for a new bundle format in place
1195
        s = StringIO()
2520.4.72 by Aaron Bentley
Rename format to 4alpha
1196
        serializer = BundleSerializerV4('1.0')
2520.4.8 by Aaron Bentley
Serialize inventory
1197
        serializer.write(tree.branch.repository, ['rev1', 'rev2'], {}, s)
2520.4.5 by Aaron Bentley
Start work on reading mpbundles
1198
        s.seek(0)
2520.4.6 by Aaron Bentley
Get installation started
1199
        tree2 = self.make_branch_and_tree('target')
1200
        target_repo = tree2.branch.repository
1201
        install_bundle(target_repo, serializer.read(s))
1202
        vf = target_repo.weave_store.get_weave('fileid-2',
1203
            target_repo.get_transaction())
2520.4.8 by Aaron Bentley
Serialize inventory
1204
        self.assertEqual('contents1\nstatic\n', vf.get_text('rev1'))
1205
        self.assertEqual('contents2\nstatic\n', vf.get_text('rev2'))
1206
        rtree = target_repo.revision_tree('rev2')
2520.4.9 by Aaron Bentley
Test inventory_vf parents
1207
        inventory_vf = target_repo.get_inventory_weave()
1208
        self.assertEqual(['rev1'], inventory_vf.get_parents('rev2'))
2520.4.10 by Aaron Bentley
Enable installation of revisions
1209
        self.assertEqual('changed file',
1210
                         target_repo.get_revision('rev2').message)
2520.4.6 by Aaron Bentley
Get installation started
1211
1212
    def test_name_encode(self):
2520.4.68 by Aaron Bentley
Change name separators to all-slash
1213
        self.assertEqual('revision/rev1',
2520.4.72 by Aaron Bentley
Rename format to 4alpha
1214
            v4.BundleWriter.encode_name('revision', 'rev1'))
2520.4.68 by Aaron Bentley
Change name separators to all-slash
1215
        self.assertEqual('file/rev1/file-id-1',
2520.4.72 by Aaron Bentley
Rename format to 4alpha
1216
            v4.BundleWriter.encode_name('file', 'rev1', 'file-id-1'))
2520.4.6 by Aaron Bentley
Get installation started
1217
1218
    def test_name_decode(self):
1219
        self.assertEqual(('revision', 'rev1', None),
2520.4.72 by Aaron Bentley
Rename format to 4alpha
1220
            v4.BundleReader.decode_name('revision/rev1'))
2520.4.6 by Aaron Bentley
Get installation started
1221
        self.assertEqual(('file', 'rev1', 'file-id-1'),
2520.4.72 by Aaron Bentley
Rename format to 4alpha
1222
            v4.BundleReader.decode_name('file/rev1/file-id-1'))
2520.4.4 by Aaron Bentley
Get basis support for a new bundle format in place
1223
2520.4.32 by Aaron Bentley
Fix test case
1224
    @staticmethod
1225
    def get_raw(bundle_file):
1226
        bundle_file.seek(0)
2520.4.70 by Aaron Bentley
Yank patch-handling functionality
1227
        line = bundle_file.readline()
1228
        line = bundle_file.readline()
2520.4.32 by Aaron Bentley
Fix test case
1229
        lines = bundle_file.readlines()
1230
        return ''.join(lines).decode('base-64').decode('bz2')
1231
2520.4.34 by Aaron Bentley
Add signature support
1232
    def test_copy_signatures(self):
1233
        tree_a = self.make_branch_and_tree('tree_a')
1234
        import bzrlib.gpg
1235
        import bzrlib.commit as commit
1236
        oldstrategy = bzrlib.gpg.GPGStrategy
1237
        branch = tree_a.branch
1238
        repo_a = branch.repository
1239
        tree_a.commit("base", allow_pointless=True, rev_id='A')
1240
        self.failIf(branch.repository.has_signature_for_revision_id('A'))
1241
        try:
1242
            from bzrlib.testament import Testament
1243
            # monkey patch gpg signing mechanism
1244
            bzrlib.gpg.GPGStrategy = bzrlib.gpg.LoopbackGPGStrategy
1245
            new_config = test_commit.MustSignConfig(branch)
1246
            commit.Commit(config=new_config).commit(message="base",
1247
                                                    allow_pointless=True,
1248
                                                    rev_id='B',
1249
                                                    working_tree=tree_a)
1250
            def sign(text):
1251
                return bzrlib.gpg.LoopbackGPGStrategy(None).sign(text)
1252
            self.assertTrue(repo_a.has_signature_for_revision_id('B'))
1253
        finally:
1254
            bzrlib.gpg.GPGStrategy = oldstrategy
1255
        tree_b = self.make_branch_and_tree('tree_b')
1256
        repo_b = tree_b.branch.repository
1257
        s = StringIO()
2520.4.72 by Aaron Bentley
Rename format to 4alpha
1258
        serializer = BundleSerializerV4('4alpha')
2520.4.34 by Aaron Bentley
Add signature support
1259
        serializer.write(tree_a.branch.repository, ['A', 'B'], {}, s)
1260
        s.seek(0)
1261
        install_bundle(repo_b, serializer.read(s))
1262
        self.assertTrue(repo_b.has_signature_for_revision_id('B'))
1263
        self.assertEqual(repo_b.get_signature_text('B'),
1264
                         repo_a.get_signature_text('B'))
1265
2520.4.4 by Aaron Bentley
Get basis support for a new bundle format in place
1266
1793.3.2 by John Arbash Meinel
(failing) add some tests which munge trailing whitespace
1267
class MungedBundleTester(TestCaseWithTransport):
1268
1269
    def build_test_bundle(self):
1270
        wt = self.make_branch_and_tree('b1')
1271
1272
        self.build_tree(['b1/one'])
1273
        wt.add('one')
1274
        wt.commit('add one', rev_id='a@cset-0-1')
1275
        self.build_tree(['b1/two'])
1276
        wt.add('two')
1793.3.14 by John Arbash Meinel
Actually fix the bug with missing trailing newline bug #49182
1277
        wt.commit('add two', rev_id='a@cset-0-2',
1278
                  revprops={'branch-nick':'test'})
1793.3.2 by John Arbash Meinel
(failing) add some tests which munge trailing whitespace
1279
1280
        bundle_txt = StringIO()
1281
        rev_ids = write_bundle(wt.branch.repository, 'a@cset-0-2',
1282
                               'a@cset-0-1', bundle_txt)
1283
        self.assertEqual(['a@cset-0-2'], rev_ids)
1284
        bundle_txt.seek(0, 0)
1285
        return bundle_txt
1286
1287
    def check_valid(self, bundle):
1288
        """Check that after whatever munging, the final object is valid."""
1793.3.14 by John Arbash Meinel
Actually fix the bug with missing trailing newline bug #49182
1289
        self.assertEqual(['a@cset-0-2'],
1793.3.4 by John Arbash Meinel
[merge] bzr.dev 1804 and fix conflicts.
1290
            [r.revision_id for r in bundle.real_revisions])
1793.3.2 by John Arbash Meinel
(failing) add some tests which munge trailing whitespace
1291
1292
    def test_extra_whitespace(self):
1293
        bundle_txt = self.build_test_bundle()
1294
1295
        # Seek to the end of the file
1296
        # Adding one extra newline used to give us
1297
        # TypeError: float() argument must be a string or a number
1298
        bundle_txt.seek(0, 2)
1299
        bundle_txt.write('\n')
1300
        bundle_txt.seek(0)
1301
1793.3.4 by John Arbash Meinel
[merge] bzr.dev 1804 and fix conflicts.
1302
        bundle = read_bundle(bundle_txt)
1793.3.2 by John Arbash Meinel
(failing) add some tests which munge trailing whitespace
1303
        self.check_valid(bundle)
1304
1305
    def test_extra_whitespace_2(self):
1306
        bundle_txt = self.build_test_bundle()
1307
1308
        # Seek to the end of the file
1309
        # Adding two extra newlines used to give us
1310
        # MalformedPatches: The first line of all patches should be ...
1311
        bundle_txt.seek(0, 2)
1312
        bundle_txt.write('\n\n')
1313
        bundle_txt.seek(0)
1314
1793.3.4 by John Arbash Meinel
[merge] bzr.dev 1804 and fix conflicts.
1315
        bundle = read_bundle(bundle_txt)
1793.3.2 by John Arbash Meinel
(failing) add some tests which munge trailing whitespace
1316
        self.check_valid(bundle)
1317
1318
    def test_missing_trailing_whitespace(self):
1319
        bundle_txt = self.build_test_bundle()
1320
1321
        # Remove a trailing newline, it shouldn't kill the parser
1322
        raw = bundle_txt.getvalue()
1323
        # The contents of the bundle don't have to be this, but this
1324
        # test is concerned with the exact case where the serializer
1325
        # creates a blank line at the end, and fails if that
1326
        # line is stripped
1327
        self.assertEqual('\n\n', raw[-2:])
1793.3.14 by John Arbash Meinel
Actually fix the bug with missing trailing newline bug #49182
1328
        bundle_txt = StringIO(raw[:-1])
1793.3.2 by John Arbash Meinel
(failing) add some tests which munge trailing whitespace
1329
1793.3.4 by John Arbash Meinel
[merge] bzr.dev 1804 and fix conflicts.
1330
        bundle = read_bundle(bundle_txt)
1793.3.2 by John Arbash Meinel
(failing) add some tests which munge trailing whitespace
1331
        self.check_valid(bundle)
1793.3.14 by John Arbash Meinel
Actually fix the bug with missing trailing newline bug #49182
1332
1793.3.16 by John Arbash Meinel
Add tests to ensure that we gracefully handle opening and trailing non-bundle text.
1333
    def test_opening_text(self):
1334
        bundle_txt = self.build_test_bundle()
1335
1336
        bundle_txt = StringIO("Some random\nemail comments\n"
1337
                              + bundle_txt.getvalue())
1338
1339
        bundle = read_bundle(bundle_txt)
1340
        self.check_valid(bundle)
1341
1342
    def test_trailing_text(self):
1343
        bundle_txt = self.build_test_bundle()
1344
1345
        bundle_txt = StringIO(bundle_txt.getvalue() +
1346
                              "Some trailing\nrandom\ntext\n")
1347
1348
        bundle = read_bundle(bundle_txt)
1349
        self.check_valid(bundle)
2520.4.56 by Aaron Bentley
Begin adding support for arbitrary metadata
1350
1351
1352
class TestBundleWriterReader(TestCase):
1353
1354
    def test_roundtrip_record(self):
1355
        fileobj = StringIO()
2520.4.72 by Aaron Bentley
Rename format to 4alpha
1356
        writer = v4.BundleWriter(fileobj)
2520.4.56 by Aaron Bentley
Begin adding support for arbitrary metadata
1357
        writer.begin()
1358
        writer._add_record("Record body", {'parents': ['1', '3']},
1359
                           'file', 'revid', 'fileid')
1360
        writer.end()
1361
        fileobj.seek(0)
2520.4.72 by Aaron Bentley
Rename format to 4alpha
1362
        reader = v4.BundleReader(fileobj)
2520.4.56 by Aaron Bentley
Begin adding support for arbitrary metadata
1363
        record = reader.iter_records().next()
2520.4.58 by Aaron Bentley
Propogate support for metadata to iter_revisions, add storage kind
1364
        self.assertEqual(("Record body", {'parents': ['1', '3']}, 'file',
2520.4.56 by Aaron Bentley
Begin adding support for arbitrary metadata
1365
                          'revid', 'fileid'), record)