/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
2052.3.2 by John Arbash Meinel
Change Copyright .. by Canonical to Copyright ... Canonical
1
# Copyright (C) 2005, 2006 Canonical Ltd
1563.2.4 by Robert Collins
First cut at including the knit implementation of versioned_file.
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
17
"""Tests for Knit data structure"""
18
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
19
from cStringIO import StringIO
1563.2.4 by Robert Collins
First cut at including the knit implementation of versioned_file.
20
import difflib
21
2196.2.5 by John Arbash Meinel
Add an exception class when the knit index storage method is unknown, and properly test for it
22
from bzrlib import (
23
    errors,
24
    )
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
25
from bzrlib.errors import (
26
    RevisionAlreadyPresent,
27
    KnitHeaderError,
28
    RevisionNotPresent,
29
    NoSuchFile,
30
    )
1684.3.3 by Robert Collins
Add a special cased weaves to knit converter.
31
from bzrlib.knit import (
2151.1.1 by John Arbash Meinel
(Dmitry Vasiliev) Tune KnitContent and add tests
32
    KnitContent,
1684.3.3 by Robert Collins
Add a special cased weaves to knit converter.
33
    KnitVersionedFile,
34
    KnitPlainFactory,
35
    KnitAnnotateFactory,
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
36
    _KnitIndex,
37
    WeaveToKnit,
38
    )
1563.2.4 by Robert Collins
First cut at including the knit implementation of versioned_file.
39
from bzrlib.osutils import split_lines
2151.1.1 by John Arbash Meinel
(Dmitry Vasiliev) Tune KnitContent and add tests
40
from bzrlib.tests import TestCase, TestCaseWithTransport
1685.1.39 by John Arbash Meinel
Updating test_knit to not instantiate a LocalTransport directly.
41
from bzrlib.transport import TransportLogger, get_transport
1563.2.13 by Robert Collins
InterVersionedFile implemented.
42
from bzrlib.transport.memory import MemoryTransport
1684.3.3 by Robert Collins
Add a special cased weaves to knit converter.
43
from bzrlib.weave import Weave
44
45
2151.1.1 by John Arbash Meinel
(Dmitry Vasiliev) Tune KnitContent and add tests
46
class KnitContentTests(TestCase):
47
48
    def test_constructor(self):
49
        content = KnitContent([])
50
51
    def test_text(self):
52
        content = KnitContent([])
53
        self.assertEqual(content.text(), [])
54
55
        content = KnitContent([("origin1", "text1"), ("origin2", "text2")])
56
        self.assertEqual(content.text(), ["text1", "text2"])
57
58
    def test_annotate(self):
59
        content = KnitContent([])
60
        self.assertEqual(content.annotate(), [])
61
62
        content = KnitContent([("origin1", "text1"), ("origin2", "text2")])
63
        self.assertEqual(content.annotate(),
64
            [("origin1", "text1"), ("origin2", "text2")])
65
66
    def test_annotate_iter(self):
67
        content = KnitContent([])
68
        it = content.annotate_iter()
69
        self.assertRaises(StopIteration, it.next)
70
71
        content = KnitContent([("origin1", "text1"), ("origin2", "text2")])
72
        it = content.annotate_iter()
73
        self.assertEqual(it.next(), ("origin1", "text1"))
74
        self.assertEqual(it.next(), ("origin2", "text2"))
75
        self.assertRaises(StopIteration, it.next)
76
77
    def test_copy(self):
78
        content = KnitContent([("origin1", "text1"), ("origin2", "text2")])
79
        copy = content.copy()
80
        self.assertIsInstance(copy, KnitContent)
81
        self.assertEqual(copy.annotate(),
82
            [("origin1", "text1"), ("origin2", "text2")])
83
84
    def test_line_delta(self):
85
        content1 = KnitContent([("", "a"), ("", "b")])
86
        content2 = KnitContent([("", "a"), ("", "a"), ("", "c")])
87
        self.assertEqual(content1.line_delta(content2),
88
            [(1, 2, 2, [("", "a"), ("", "c")])])
89
90
    def test_line_delta_iter(self):
91
        content1 = KnitContent([("", "a"), ("", "b")])
92
        content2 = KnitContent([("", "a"), ("", "a"), ("", "c")])
93
        it = content1.line_delta_iter(content2)
94
        self.assertEqual(it.next(), (1, 2, 2, [("", "a"), ("", "c")]))
95
        self.assertRaises(StopIteration, it.next)
96
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
97
98
class MockTransport(object):
99
100
    def __init__(self, file_lines=None):
101
        self.file_lines = file_lines
102
        self.calls = []
2196.2.3 by John Arbash Meinel
Update tests and code to pass after merging bzr.dev
103
        # We have no base directory for the MockTransport
104
        self.base = ''
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
105
106
    def get(self, filename):
107
        if self.file_lines is None:
108
            raise NoSuchFile(filename)
109
        else:
110
            return StringIO("\n".join(self.file_lines))
111
112
    def __getattr__(self, name):
113
        def queue_call(*args, **kwargs):
114
            self.calls.append((name, args, kwargs))
115
        return queue_call
116
117
118
class LowLevelKnitIndexTests(TestCase):
119
120
    def test_no_such_file(self):
121
        transport = MockTransport()
122
123
        self.assertRaises(NoSuchFile, _KnitIndex, transport, "filename", "r")
124
        self.assertRaises(NoSuchFile, _KnitIndex, transport,
125
            "filename", "w", create=False)
126
127
    def test_create_file(self):
128
        transport = MockTransport()
129
130
        index = _KnitIndex(transport, "filename", "w",
131
            file_mode="wb", create=True)
132
        self.assertEqual(
133
                ("put_bytes_non_atomic",
134
                    ("filename", index.HEADER), {"mode": "wb"}),
135
                transport.calls.pop(0))
136
137
    def test_delay_create_file(self):
138
        transport = MockTransport()
139
140
        index = _KnitIndex(transport, "filename", "w",
141
            create=True, file_mode="wb", create_parent_dir=True,
142
            delay_create=True, dir_mode=0777)
143
        self.assertEqual([], transport.calls)
144
145
        index.add_versions([])
146
        name, (filename, f), kwargs = transport.calls.pop(0)
147
        self.assertEqual("put_file_non_atomic", name)
148
        self.assertEqual(
149
            {"dir_mode": 0777, "create_parent_dir": True, "mode": "wb"},
150
            kwargs)
151
        self.assertEqual("filename", filename)
152
        self.assertEqual(index.HEADER, f.read())
153
154
        index.add_versions([])
155
        self.assertEqual(("append_bytes", ("filename", ""), {}),
156
            transport.calls.pop(0))
157
158
    def test_read_utf8_version_id(self):
2249.5.12 by John Arbash Meinel
Change the APIs for VersionedFile, Store, and some of Repository into utf-8
159
        unicode_revision_id = u"version-\N{CYRILLIC CAPITAL LETTER A}"
160
        utf8_revision_id = unicode_revision_id.encode('utf-8')
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
161
        transport = MockTransport([
162
            _KnitIndex.HEADER,
2249.5.12 by John Arbash Meinel
Change the APIs for VersionedFile, Store, and some of Repository into utf-8
163
            '%s option 0 1 :' % (utf8_revision_id,)
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
164
            ])
165
        index = _KnitIndex(transport, "filename", "r")
2249.5.12 by John Arbash Meinel
Change the APIs for VersionedFile, Store, and some of Repository into utf-8
166
        # _KnitIndex is a private class, and deals in utf8 revision_ids, not
167
        # Unicode revision_ids.
168
        self.assertTrue(index.has_version(utf8_revision_id))
169
        self.assertFalse(index.has_version(unicode_revision_id))
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
170
171
    def test_read_utf8_parents(self):
2249.5.12 by John Arbash Meinel
Change the APIs for VersionedFile, Store, and some of Repository into utf-8
172
        unicode_revision_id = u"version-\N{CYRILLIC CAPITAL LETTER A}"
173
        utf8_revision_id = unicode_revision_id.encode('utf-8')
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
174
        transport = MockTransport([
175
            _KnitIndex.HEADER,
2249.5.12 by John Arbash Meinel
Change the APIs for VersionedFile, Store, and some of Repository into utf-8
176
            "version option 0 1 .%s :" % (utf8_revision_id,)
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
177
            ])
178
        index = _KnitIndex(transport, "filename", "r")
2249.5.12 by John Arbash Meinel
Change the APIs for VersionedFile, Store, and some of Repository into utf-8
179
        self.assertEqual([utf8_revision_id],
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
180
            index.get_parents_with_ghosts("version"))
181
182
    def test_read_ignore_corrupted_lines(self):
183
        transport = MockTransport([
184
            _KnitIndex.HEADER,
185
            "corrupted",
186
            "corrupted options 0 1 .b .c ",
187
            "version options 0 1 :"
188
            ])
189
        index = _KnitIndex(transport, "filename", "r")
190
        self.assertEqual(1, index.num_versions())
2249.5.12 by John Arbash Meinel
Change the APIs for VersionedFile, Store, and some of Repository into utf-8
191
        self.assertTrue(index.has_version("version"))
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
192
193
    def test_read_corrupted_header(self):
2196.2.3 by John Arbash Meinel
Update tests and code to pass after merging bzr.dev
194
        transport = MockTransport(['not a bzr knit index header\n'])
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
195
        self.assertRaises(KnitHeaderError,
196
            _KnitIndex, transport, "filename", "r")
197
198
    def test_read_duplicate_entries(self):
199
        transport = MockTransport([
200
            _KnitIndex.HEADER,
201
            "parent options 0 1 :",
202
            "version options1 0 1 0 :",
203
            "version options2 1 2 .other :",
204
            "version options3 3 4 0 .other :"
205
            ])
206
        index = _KnitIndex(transport, "filename", "r")
207
        self.assertEqual(2, index.num_versions())
2249.5.12 by John Arbash Meinel
Change the APIs for VersionedFile, Store, and some of Repository into utf-8
208
        self.assertEqual(1, index.lookup("version"))
209
        self.assertEqual((3, 4), index.get_position("version"))
210
        self.assertEqual(["options3"], index.get_options("version"))
211
        self.assertEqual(["parent", "other"],
212
            index.get_parents_with_ghosts("version"))
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
213
214
    def test_read_compressed_parents(self):
215
        transport = MockTransport([
216
            _KnitIndex.HEADER,
217
            "a option 0 1 :",
218
            "b option 0 1 0 :",
219
            "c option 0 1 1 0 :",
220
            ])
221
        index = _KnitIndex(transport, "filename", "r")
2249.5.12 by John Arbash Meinel
Change the APIs for VersionedFile, Store, and some of Repository into utf-8
222
        self.assertEqual(["a"], index.get_parents("b"))
223
        self.assertEqual(["b", "a"], index.get_parents("c"))
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
224
225
    def test_write_utf8_version_id(self):
2249.5.12 by John Arbash Meinel
Change the APIs for VersionedFile, Store, and some of Repository into utf-8
226
        unicode_revision_id = u"version-\N{CYRILLIC CAPITAL LETTER A}"
227
        utf8_revision_id = unicode_revision_id.encode('utf-8')
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
228
        transport = MockTransport([
229
            _KnitIndex.HEADER
230
            ])
231
        index = _KnitIndex(transport, "filename", "r")
2249.5.12 by John Arbash Meinel
Change the APIs for VersionedFile, Store, and some of Repository into utf-8
232
        index.add_version(utf8_revision_id, ["option"], 0, 1, [])
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
233
        self.assertEqual(("append_bytes", ("filename",
2249.5.12 by John Arbash Meinel
Change the APIs for VersionedFile, Store, and some of Repository into utf-8
234
            "\n%s option 0 1  :" % (utf8_revision_id,)),
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
235
            {}),
236
            transport.calls.pop(0))
237
238
    def test_write_utf8_parents(self):
2249.5.12 by John Arbash Meinel
Change the APIs for VersionedFile, Store, and some of Repository into utf-8
239
        unicode_revision_id = u"version-\N{CYRILLIC CAPITAL LETTER A}"
240
        utf8_revision_id = unicode_revision_id.encode('utf-8')
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
241
        transport = MockTransport([
242
            _KnitIndex.HEADER
243
            ])
244
        index = _KnitIndex(transport, "filename", "r")
2249.5.12 by John Arbash Meinel
Change the APIs for VersionedFile, Store, and some of Repository into utf-8
245
        index.add_version("version", ["option"], 0, 1, [utf8_revision_id])
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
246
        self.assertEqual(("append_bytes", ("filename",
2249.5.12 by John Arbash Meinel
Change the APIs for VersionedFile, Store, and some of Repository into utf-8
247
            "\nversion option 0 1 .%s :" % (utf8_revision_id,)),
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
248
            {}),
249
            transport.calls.pop(0))
250
251
    def test_get_graph(self):
252
        transport = MockTransport()
253
        index = _KnitIndex(transport, "filename", "w", create=True)
254
        self.assertEqual([], index.get_graph())
255
2249.5.12 by John Arbash Meinel
Change the APIs for VersionedFile, Store, and some of Repository into utf-8
256
        index.add_version("a", ["option"], 0, 1, ["b"])
257
        self.assertEqual([("a", ["b"])], index.get_graph())
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
258
2249.5.12 by John Arbash Meinel
Change the APIs for VersionedFile, Store, and some of Repository into utf-8
259
        index.add_version("c", ["option"], 0, 1, ["d"])
260
        self.assertEqual([("a", ["b"]), ("c", ["d"])],
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
261
            sorted(index.get_graph()))
262
263
    def test_get_ancestry(self):
264
        transport = MockTransport([
265
            _KnitIndex.HEADER,
266
            "a option 0 1 :",
267
            "b option 0 1 0 .e :",
268
            "c option 0 1 1 0 :",
269
            "d option 0 1 2 .f :"
270
            ])
271
        index = _KnitIndex(transport, "filename", "r")
272
273
        self.assertEqual([], index.get_ancestry([]))
2249.5.12 by John Arbash Meinel
Change the APIs for VersionedFile, Store, and some of Repository into utf-8
274
        self.assertEqual(["a"], index.get_ancestry(["a"]))
275
        self.assertEqual(["a", "b"], index.get_ancestry(["b"]))
276
        self.assertEqual(["a", "b", "c"], index.get_ancestry(["c"]))
277
        self.assertEqual(["a", "b", "c", "d"], index.get_ancestry(["d"]))
278
        self.assertEqual(["a", "b"], index.get_ancestry(["a", "b"]))
279
        self.assertEqual(["a", "b", "c"], index.get_ancestry(["a", "c"]))
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
280
2249.5.12 by John Arbash Meinel
Change the APIs for VersionedFile, Store, and some of Repository into utf-8
281
        self.assertRaises(RevisionNotPresent, index.get_ancestry, ["e"])
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
282
283
    def test_get_ancestry_with_ghosts(self):
284
        transport = MockTransport([
285
            _KnitIndex.HEADER,
286
            "a option 0 1 :",
287
            "b option 0 1 0 .e :",
288
            "c option 0 1 0 .f .g :",
289
            "d option 0 1 2 .h .j .k :"
290
            ])
291
        index = _KnitIndex(transport, "filename", "r")
292
293
        self.assertEqual([], index.get_ancestry_with_ghosts([]))
2249.5.12 by John Arbash Meinel
Change the APIs for VersionedFile, Store, and some of Repository into utf-8
294
        self.assertEqual(["a"], index.get_ancestry_with_ghosts(["a"]))
295
        self.assertEqual(["a", "e", "b"],
296
            index.get_ancestry_with_ghosts(["b"]))
297
        self.assertEqual(["a", "g", "f", "c"],
298
            index.get_ancestry_with_ghosts(["c"]))
299
        self.assertEqual(["a", "g", "f", "c", "k", "j", "h", "d"],
300
            index.get_ancestry_with_ghosts(["d"]))
301
        self.assertEqual(["a", "e", "b"],
302
            index.get_ancestry_with_ghosts(["a", "b"]))
303
        self.assertEqual(["a", "g", "f", "c"],
304
            index.get_ancestry_with_ghosts(["a", "c"]))
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
305
        self.assertEqual(
2249.5.12 by John Arbash Meinel
Change the APIs for VersionedFile, Store, and some of Repository into utf-8
306
            ["a", "g", "f", "c", "e", "b", "k", "j", "h", "d"],
307
            index.get_ancestry_with_ghosts(["b", "d"]))
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
308
309
        self.assertRaises(RevisionNotPresent,
2249.5.12 by John Arbash Meinel
Change the APIs for VersionedFile, Store, and some of Repository into utf-8
310
            index.get_ancestry_with_ghosts, ["e"])
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
311
312
    def test_num_versions(self):
313
        transport = MockTransport([
314
            _KnitIndex.HEADER
315
            ])
316
        index = _KnitIndex(transport, "filename", "r")
317
318
        self.assertEqual(0, index.num_versions())
319
        self.assertEqual(0, len(index))
320
2249.5.12 by John Arbash Meinel
Change the APIs for VersionedFile, Store, and some of Repository into utf-8
321
        index.add_version("a", ["option"], 0, 1, [])
322
        self.assertEqual(1, index.num_versions())
323
        self.assertEqual(1, len(index))
324
325
        index.add_version("a", ["option2"], 1, 2, [])
326
        self.assertEqual(1, index.num_versions())
327
        self.assertEqual(1, len(index))
328
329
        index.add_version("b", ["option"], 0, 1, [])
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
330
        self.assertEqual(2, index.num_versions())
331
        self.assertEqual(2, len(index))
332
333
    def test_get_versions(self):
334
        transport = MockTransport([
335
            _KnitIndex.HEADER
336
            ])
337
        index = _KnitIndex(transport, "filename", "r")
338
339
        self.assertEqual([], index.get_versions())
340
2249.5.12 by John Arbash Meinel
Change the APIs for VersionedFile, Store, and some of Repository into utf-8
341
        index.add_version("a", ["option"], 0, 1, [])
342
        self.assertEqual(["a"], index.get_versions())
343
344
        index.add_version("a", ["option"], 0, 1, [])
345
        self.assertEqual(["a"], index.get_versions())
346
347
        index.add_version("b", ["option"], 0, 1, [])
348
        self.assertEqual(["a", "b"], index.get_versions())
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
349
350
    def test_idx_to_name(self):
351
        transport = MockTransport([
352
            _KnitIndex.HEADER,
353
            "a option 0 1 :",
354
            "b option 0 1 :"
355
            ])
356
        index = _KnitIndex(transport, "filename", "r")
357
2249.5.12 by John Arbash Meinel
Change the APIs for VersionedFile, Store, and some of Repository into utf-8
358
        self.assertEqual("a", index.idx_to_name(0))
359
        self.assertEqual("b", index.idx_to_name(1))
360
        self.assertEqual("b", index.idx_to_name(-1))
361
        self.assertEqual("a", index.idx_to_name(-2))
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
362
363
    def test_lookup(self):
364
        transport = MockTransport([
365
            _KnitIndex.HEADER,
366
            "a option 0 1 :",
367
            "b option 0 1 :"
368
            ])
369
        index = _KnitIndex(transport, "filename", "r")
370
2249.5.12 by John Arbash Meinel
Change the APIs for VersionedFile, Store, and some of Repository into utf-8
371
        self.assertEqual(0, index.lookup("a"))
372
        self.assertEqual(1, index.lookup("b"))
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
373
374
    def test_add_version(self):
375
        transport = MockTransport([
376
            _KnitIndex.HEADER
377
            ])
378
        index = _KnitIndex(transport, "filename", "r")
379
2249.5.12 by John Arbash Meinel
Change the APIs for VersionedFile, Store, and some of Repository into utf-8
380
        index.add_version("a", ["option"], 0, 1, ["b"])
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
381
        self.assertEqual(("append_bytes",
382
            ("filename", "\na option 0 1 .b :"),
383
            {}), transport.calls.pop(0))
2249.5.12 by John Arbash Meinel
Change the APIs for VersionedFile, Store, and some of Repository into utf-8
384
        self.assertTrue(index.has_version("a"))
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
385
        self.assertEqual(1, index.num_versions())
2249.5.12 by John Arbash Meinel
Change the APIs for VersionedFile, Store, and some of Repository into utf-8
386
        self.assertEqual((0, 1), index.get_position("a"))
387
        self.assertEqual(["option"], index.get_options("a"))
388
        self.assertEqual(["b"], index.get_parents_with_ghosts("a"))
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
389
2249.5.12 by John Arbash Meinel
Change the APIs for VersionedFile, Store, and some of Repository into utf-8
390
        index.add_version("a", ["opt"], 1, 2, ["c"])
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
391
        self.assertEqual(("append_bytes",
392
            ("filename", "\na opt 1 2 .c :"),
393
            {}), transport.calls.pop(0))
2249.5.12 by John Arbash Meinel
Change the APIs for VersionedFile, Store, and some of Repository into utf-8
394
        self.assertTrue(index.has_version("a"))
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
395
        self.assertEqual(1, index.num_versions())
2249.5.12 by John Arbash Meinel
Change the APIs for VersionedFile, Store, and some of Repository into utf-8
396
        self.assertEqual((1, 2), index.get_position("a"))
397
        self.assertEqual(["opt"], index.get_options("a"))
398
        self.assertEqual(["c"], index.get_parents_with_ghosts("a"))
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
399
2249.5.12 by John Arbash Meinel
Change the APIs for VersionedFile, Store, and some of Repository into utf-8
400
        index.add_version("b", ["option"], 2, 3, ["a"])
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
401
        self.assertEqual(("append_bytes",
402
            ("filename", "\nb option 2 3 0 :"),
403
            {}), transport.calls.pop(0))
2249.5.12 by John Arbash Meinel
Change the APIs for VersionedFile, Store, and some of Repository into utf-8
404
        self.assertTrue(index.has_version("b"))
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
405
        self.assertEqual(2, index.num_versions())
2249.5.12 by John Arbash Meinel
Change the APIs for VersionedFile, Store, and some of Repository into utf-8
406
        self.assertEqual((2, 3), index.get_position("b"))
407
        self.assertEqual(["option"], index.get_options("b"))
408
        self.assertEqual(["a"], index.get_parents_with_ghosts("b"))
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
409
410
    def test_add_versions(self):
411
        transport = MockTransport([
412
            _KnitIndex.HEADER
413
            ])
414
        index = _KnitIndex(transport, "filename", "r")
415
416
        index.add_versions([
2249.5.12 by John Arbash Meinel
Change the APIs for VersionedFile, Store, and some of Repository into utf-8
417
            ("a", ["option"], 0, 1, ["b"]),
418
            ("a", ["opt"], 1, 2, ["c"]),
419
            ("b", ["option"], 2, 3, ["a"])
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
420
            ])
421
        self.assertEqual(("append_bytes", ("filename",
422
            "\na option 0 1 .b :"
423
            "\na opt 1 2 .c :"
424
            "\nb option 2 3 0 :"
425
            ), {}), transport.calls.pop(0))
2249.5.12 by John Arbash Meinel
Change the APIs for VersionedFile, Store, and some of Repository into utf-8
426
        self.assertTrue(index.has_version("a"))
427
        self.assertTrue(index.has_version("b"))
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
428
        self.assertEqual(2, index.num_versions())
2249.5.12 by John Arbash Meinel
Change the APIs for VersionedFile, Store, and some of Repository into utf-8
429
        self.assertEqual((1, 2), index.get_position("a"))
430
        self.assertEqual((2, 3), index.get_position("b"))
431
        self.assertEqual(["opt"], index.get_options("a"))
432
        self.assertEqual(["option"], index.get_options("b"))
433
        self.assertEqual(["c"], index.get_parents_with_ghosts("a"))
434
        self.assertEqual(["a"], index.get_parents_with_ghosts("b"))
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
435
436
    def test_delay_create_and_add_versions(self):
437
        transport = MockTransport()
438
439
        index = _KnitIndex(transport, "filename", "w",
440
            create=True, file_mode="wb", create_parent_dir=True,
441
            delay_create=True, dir_mode=0777)
442
        self.assertEqual([], transport.calls)
443
444
        index.add_versions([
2249.5.12 by John Arbash Meinel
Change the APIs for VersionedFile, Store, and some of Repository into utf-8
445
            ("a", ["option"], 0, 1, ["b"]),
446
            ("a", ["opt"], 1, 2, ["c"]),
447
            ("b", ["option"], 2, 3, ["a"])
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
448
            ])
449
        name, (filename, f), kwargs = transport.calls.pop(0)
450
        self.assertEqual("put_file_non_atomic", name)
451
        self.assertEqual(
452
            {"dir_mode": 0777, "create_parent_dir": True, "mode": "wb"},
453
            kwargs)
454
        self.assertEqual("filename", filename)
455
        self.assertEqual(
456
            index.HEADER +
457
            "\na option 0 1 .b :"
458
            "\na opt 1 2 .c :"
459
            "\nb option 2 3 0 :",
460
            f.read())
461
462
    def test_has_version(self):
463
        transport = MockTransport([
464
            _KnitIndex.HEADER,
465
            "a option 0 1 :"
466
            ])
467
        index = _KnitIndex(transport, "filename", "r")
468
2249.5.12 by John Arbash Meinel
Change the APIs for VersionedFile, Store, and some of Repository into utf-8
469
        self.assertTrue(index.has_version("a"))
470
        self.assertFalse(index.has_version("b"))
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
471
472
    def test_get_position(self):
473
        transport = MockTransport([
474
            _KnitIndex.HEADER,
475
            "a option 0 1 :",
476
            "b option 1 2 :"
477
            ])
478
        index = _KnitIndex(transport, "filename", "r")
479
2249.5.12 by John Arbash Meinel
Change the APIs for VersionedFile, Store, and some of Repository into utf-8
480
        self.assertEqual((0, 1), index.get_position("a"))
481
        self.assertEqual((1, 2), index.get_position("b"))
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
482
483
    def test_get_method(self):
484
        transport = MockTransport([
485
            _KnitIndex.HEADER,
486
            "a fulltext,unknown 0 1 :",
487
            "b unknown,line-delta 1 2 :",
488
            "c bad 3 4 :"
489
            ])
490
        index = _KnitIndex(transport, "filename", "r")
491
2249.5.12 by John Arbash Meinel
Change the APIs for VersionedFile, Store, and some of Repository into utf-8
492
        self.assertEqual("fulltext", index.get_method("a"))
493
        self.assertEqual("line-delta", index.get_method("b"))
494
        self.assertRaises(errors.KnitIndexUnknownMethod, index.get_method, "c")
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
495
496
    def test_get_options(self):
497
        transport = MockTransport([
498
            _KnitIndex.HEADER,
499
            "a opt1 0 1 :",
500
            "b opt2,opt3 1 2 :"
501
            ])
502
        index = _KnitIndex(transport, "filename", "r")
503
2249.5.12 by John Arbash Meinel
Change the APIs for VersionedFile, Store, and some of Repository into utf-8
504
        self.assertEqual(["opt1"], index.get_options("a"))
505
        self.assertEqual(["opt2", "opt3"], index.get_options("b"))
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
506
507
    def test_get_parents(self):
508
        transport = MockTransport([
509
            _KnitIndex.HEADER,
510
            "a option 0 1 :",
511
            "b option 1 2 0 .c :",
512
            "c option 1 2 1 0 .e :"
513
            ])
514
        index = _KnitIndex(transport, "filename", "r")
515
2249.5.12 by John Arbash Meinel
Change the APIs for VersionedFile, Store, and some of Repository into utf-8
516
        self.assertEqual([], index.get_parents("a"))
517
        self.assertEqual(["a", "c"], index.get_parents("b"))
518
        self.assertEqual(["b", "a"], index.get_parents("c"))
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
519
520
    def test_get_parents_with_ghosts(self):
521
        transport = MockTransport([
522
            _KnitIndex.HEADER,
523
            "a option 0 1 :",
524
            "b option 1 2 0 .c :",
525
            "c option 1 2 1 0 .e :"
526
            ])
527
        index = _KnitIndex(transport, "filename", "r")
528
2249.5.12 by John Arbash Meinel
Change the APIs for VersionedFile, Store, and some of Repository into utf-8
529
        self.assertEqual([], index.get_parents_with_ghosts("a"))
530
        self.assertEqual(["a", "c"], index.get_parents_with_ghosts("b"))
531
        self.assertEqual(["b", "a", "e"],
532
            index.get_parents_with_ghosts("c"))
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
533
534
    def test_check_versions_present(self):
535
        transport = MockTransport([
536
            _KnitIndex.HEADER,
537
            "a option 0 1 :",
538
            "b option 0 1 :"
539
            ])
540
        index = _KnitIndex(transport, "filename", "r")
541
542
        check = index.check_versions_present
543
544
        check([])
2249.5.12 by John Arbash Meinel
Change the APIs for VersionedFile, Store, and some of Repository into utf-8
545
        check(["a"])
546
        check(["b"])
547
        check(["a", "b"])
548
        self.assertRaises(RevisionNotPresent, check, ["c"])
549
        self.assertRaises(RevisionNotPresent, check, ["a", "b", "c"])
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
550
551
1684.3.3 by Robert Collins
Add a special cased weaves to knit converter.
552
class KnitTests(TestCaseWithTransport):
553
    """Class containing knit test helper routines."""
1563.2.16 by Robert Collins
Change WeaveStore into VersionedFileStore and make its versoined file class parameterisable.
554
1946.2.1 by John Arbash Meinel
2 changes to knits. Delay creating the .knit or .kndx file until we have actually tried to write data. Because of this, we must allow the Knit to create the prefix directories
555
    def make_test_knit(self, annotate=False, delay_create=False):
1563.2.16 by Robert Collins
Change WeaveStore into VersionedFileStore and make its versoined file class parameterisable.
556
        if not annotate:
557
            factory = KnitPlainFactory()
558
        else:
559
            factory = None
1946.2.1 by John Arbash Meinel
2 changes to knits. Delay creating the .knit or .kndx file until we have actually tried to write data. Because of this, we must allow the Knit to create the prefix directories
560
        return KnitVersionedFile('test', get_transport('.'), access_mode='w',
561
                                 factory=factory, create=True,
562
                                 delay_create=delay_create)
1563.2.4 by Robert Collins
First cut at including the knit implementation of versioned_file.
563
1684.3.3 by Robert Collins
Add a special cased weaves to knit converter.
564
565
class BasicKnitTests(KnitTests):
566
567
    def add_stock_one_and_one_a(self, k):
568
        k.add_lines('text-1', [], split_lines(TEXT_1))
569
        k.add_lines('text-1a', ['text-1'], split_lines(TEXT_1A))
570
571
    def test_knit_constructor(self):
572
        """Construct empty k"""
573
        self.make_test_knit()
574
1563.2.4 by Robert Collins
First cut at including the knit implementation of versioned_file.
575
    def test_knit_add(self):
576
        """Store one text in knit and retrieve"""
1563.2.16 by Robert Collins
Change WeaveStore into VersionedFileStore and make its versoined file class parameterisable.
577
        k = self.make_test_knit()
1563.2.4 by Robert Collins
First cut at including the knit implementation of versioned_file.
578
        k.add_lines('text-1', [], split_lines(TEXT_1))
579
        self.assertTrue(k.has_version('text-1'))
580
        self.assertEqualDiff(''.join(k.get_lines('text-1')), TEXT_1)
581
582
    def test_knit_reload(self):
1641.1.2 by Robert Collins
Change knit index files to be robust in the presence of partial writes.
583
        # test that the content in a reloaded knit is correct
1563.2.16 by Robert Collins
Change WeaveStore into VersionedFileStore and make its versoined file class parameterisable.
584
        k = self.make_test_knit()
1563.2.4 by Robert Collins
First cut at including the knit implementation of versioned_file.
585
        k.add_lines('text-1', [], split_lines(TEXT_1))
586
        del k
1685.1.39 by John Arbash Meinel
Updating test_knit to not instantiate a LocalTransport directly.
587
        k2 = KnitVersionedFile('test', get_transport('.'), access_mode='r', factory=KnitPlainFactory(), create=True)
1563.2.4 by Robert Collins
First cut at including the knit implementation of versioned_file.
588
        self.assertTrue(k2.has_version('text-1'))
589
        self.assertEqualDiff(''.join(k2.get_lines('text-1')), TEXT_1)
590
591
    def test_knit_several(self):
592
        """Store several texts in a knit"""
1563.2.16 by Robert Collins
Change WeaveStore into VersionedFileStore and make its versoined file class parameterisable.
593
        k = self.make_test_knit()
1563.2.4 by Robert Collins
First cut at including the knit implementation of versioned_file.
594
        k.add_lines('text-1', [], split_lines(TEXT_1))
595
        k.add_lines('text-2', [], split_lines(TEXT_2))
596
        self.assertEqualDiff(''.join(k.get_lines('text-1')), TEXT_1)
597
        self.assertEqualDiff(''.join(k.get_lines('text-2')), TEXT_2)
598
        
599
    def test_repeated_add(self):
600
        """Knit traps attempt to replace existing version"""
1563.2.16 by Robert Collins
Change WeaveStore into VersionedFileStore and make its versoined file class parameterisable.
601
        k = self.make_test_knit()
1563.2.4 by Robert Collins
First cut at including the knit implementation of versioned_file.
602
        k.add_lines('text-1', [], split_lines(TEXT_1))
603
        self.assertRaises(RevisionAlreadyPresent, 
604
                k.add_lines,
605
                'text-1', [], split_lines(TEXT_1))
606
607
    def test_empty(self):
1563.2.16 by Robert Collins
Change WeaveStore into VersionedFileStore and make its versoined file class parameterisable.
608
        k = self.make_test_knit(True)
1563.2.4 by Robert Collins
First cut at including the knit implementation of versioned_file.
609
        k.add_lines('text-1', [], [])
610
        self.assertEquals(k.get_lines('text-1'), [])
611
612
    def test_incomplete(self):
613
        """Test if texts without a ending line-end can be inserted and
614
        extracted."""
1685.1.39 by John Arbash Meinel
Updating test_knit to not instantiate a LocalTransport directly.
615
        k = KnitVersionedFile('test', get_transport('.'), delta=False, create=True)
1563.2.4 by Robert Collins
First cut at including the knit implementation of versioned_file.
616
        k.add_lines('text-1', [], ['a\n',    'b'  ])
617
        k.add_lines('text-2', ['text-1'], ['a\rb\n', 'b\n'])
1666.1.6 by Robert Collins
Make knit the default format.
618
        # reopening ensures maximum room for confusion
1685.1.39 by John Arbash Meinel
Updating test_knit to not instantiate a LocalTransport directly.
619
        k = KnitVersionedFile('test', get_transport('.'), delta=False, create=True)
1563.2.4 by Robert Collins
First cut at including the knit implementation of versioned_file.
620
        self.assertEquals(k.get_lines('text-1'), ['a\n',    'b'  ])
621
        self.assertEquals(k.get_lines('text-2'), ['a\rb\n', 'b\n'])
622
623
    def test_delta(self):
624
        """Expression of knit delta as lines"""
1563.2.16 by Robert Collins
Change WeaveStore into VersionedFileStore and make its versoined file class parameterisable.
625
        k = self.make_test_knit()
1563.2.4 by Robert Collins
First cut at including the knit implementation of versioned_file.
626
        td = list(line_delta(TEXT_1.splitlines(True),
627
                             TEXT_1A.splitlines(True)))
628
        self.assertEqualDiff(''.join(td), delta_1_1a)
629
        out = apply_line_delta(TEXT_1.splitlines(True), td)
630
        self.assertEqualDiff(''.join(out), TEXT_1A)
631
632
    def test_add_with_parents(self):
633
        """Store in knit with parents"""
1563.2.16 by Robert Collins
Change WeaveStore into VersionedFileStore and make its versoined file class parameterisable.
634
        k = self.make_test_knit()
1563.2.4 by Robert Collins
First cut at including the knit implementation of versioned_file.
635
        self.add_stock_one_and_one_a(k)
636
        self.assertEquals(k.get_parents('text-1'), [])
637
        self.assertEquals(k.get_parents('text-1a'), ['text-1'])
638
639
    def test_ancestry(self):
640
        """Store in knit with parents"""
1563.2.16 by Robert Collins
Change WeaveStore into VersionedFileStore and make its versoined file class parameterisable.
641
        k = self.make_test_knit()
1563.2.4 by Robert Collins
First cut at including the knit implementation of versioned_file.
642
        self.add_stock_one_and_one_a(k)
643
        self.assertEquals(set(k.get_ancestry(['text-1a'])), set(['text-1a', 'text-1']))
644
645
    def test_add_delta(self):
646
        """Store in knit with parents"""
1685.1.39 by John Arbash Meinel
Updating test_knit to not instantiate a LocalTransport directly.
647
        k = KnitVersionedFile('test', get_transport('.'), factory=KnitPlainFactory(),
1563.2.25 by Robert Collins
Merge in upstream.
648
            delta=True, create=True)
1563.2.4 by Robert Collins
First cut at including the knit implementation of versioned_file.
649
        self.add_stock_one_and_one_a(k)
1596.2.7 by Robert Collins
Remove the requirement for reannotation in knit joins.
650
        k.clear_cache()
1563.2.4 by Robert Collins
First cut at including the knit implementation of versioned_file.
651
        self.assertEqualDiff(''.join(k.get_lines('text-1a')), TEXT_1A)
652
653
    def test_annotate(self):
654
        """Annotations"""
1685.1.39 by John Arbash Meinel
Updating test_knit to not instantiate a LocalTransport directly.
655
        k = KnitVersionedFile('knit', get_transport('.'), factory=KnitAnnotateFactory(),
1563.2.25 by Robert Collins
Merge in upstream.
656
            delta=True, create=True)
1563.2.4 by Robert Collins
First cut at including the knit implementation of versioned_file.
657
        self.insert_and_test_small_annotate(k)
658
659
    def insert_and_test_small_annotate(self, k):
660
        """test annotation with k works correctly."""
661
        k.add_lines('text-1', [], ['a\n', 'b\n'])
662
        k.add_lines('text-2', ['text-1'], ['a\n', 'c\n'])
663
664
        origins = k.annotate('text-2')
665
        self.assertEquals(origins[0], ('text-1', 'a\n'))
666
        self.assertEquals(origins[1], ('text-2', 'c\n'))
667
668
    def test_annotate_fulltext(self):
669
        """Annotations"""
1685.1.39 by John Arbash Meinel
Updating test_knit to not instantiate a LocalTransport directly.
670
        k = KnitVersionedFile('knit', get_transport('.'), factory=KnitAnnotateFactory(),
1563.2.25 by Robert Collins
Merge in upstream.
671
            delta=False, create=True)
1563.2.4 by Robert Collins
First cut at including the knit implementation of versioned_file.
672
        self.insert_and_test_small_annotate(k)
673
674
    def test_annotate_merge_1(self):
1563.2.16 by Robert Collins
Change WeaveStore into VersionedFileStore and make its versoined file class parameterisable.
675
        k = self.make_test_knit(True)
1563.2.4 by Robert Collins
First cut at including the knit implementation of versioned_file.
676
        k.add_lines('text-a1', [], ['a\n', 'b\n'])
677
        k.add_lines('text-a2', [], ['d\n', 'c\n'])
678
        k.add_lines('text-am', ['text-a1', 'text-a2'], ['d\n', 'b\n'])
679
        origins = k.annotate('text-am')
680
        self.assertEquals(origins[0], ('text-a2', 'd\n'))
681
        self.assertEquals(origins[1], ('text-a1', 'b\n'))
682
683
    def test_annotate_merge_2(self):
1563.2.16 by Robert Collins
Change WeaveStore into VersionedFileStore and make its versoined file class parameterisable.
684
        k = self.make_test_knit(True)
1563.2.4 by Robert Collins
First cut at including the knit implementation of versioned_file.
685
        k.add_lines('text-a1', [], ['a\n', 'b\n', 'c\n'])
686
        k.add_lines('text-a2', [], ['x\n', 'y\n', 'z\n'])
687
        k.add_lines('text-am', ['text-a1', 'text-a2'], ['a\n', 'y\n', 'c\n'])
688
        origins = k.annotate('text-am')
689
        self.assertEquals(origins[0], ('text-a1', 'a\n'))
690
        self.assertEquals(origins[1], ('text-a2', 'y\n'))
691
        self.assertEquals(origins[2], ('text-a1', 'c\n'))
692
693
    def test_annotate_merge_9(self):
1563.2.16 by Robert Collins
Change WeaveStore into VersionedFileStore and make its versoined file class parameterisable.
694
        k = self.make_test_knit(True)
1563.2.4 by Robert Collins
First cut at including the knit implementation of versioned_file.
695
        k.add_lines('text-a1', [], ['a\n', 'b\n', 'c\n'])
696
        k.add_lines('text-a2', [], ['x\n', 'y\n', 'z\n'])
697
        k.add_lines('text-am', ['text-a1', 'text-a2'], ['k\n', 'y\n', 'c\n'])
698
        origins = k.annotate('text-am')
699
        self.assertEquals(origins[0], ('text-am', 'k\n'))
700
        self.assertEquals(origins[1], ('text-a2', 'y\n'))
701
        self.assertEquals(origins[2], ('text-a1', 'c\n'))
702
703
    def test_annotate_merge_3(self):
1563.2.16 by Robert Collins
Change WeaveStore into VersionedFileStore and make its versoined file class parameterisable.
704
        k = self.make_test_knit(True)
1563.2.4 by Robert Collins
First cut at including the knit implementation of versioned_file.
705
        k.add_lines('text-a1', [], ['a\n', 'b\n', 'c\n'])
706
        k.add_lines('text-a2', [] ,['x\n', 'y\n', 'z\n'])
707
        k.add_lines('text-am', ['text-a1', 'text-a2'], ['k\n', 'y\n', 'z\n'])
708
        origins = k.annotate('text-am')
709
        self.assertEquals(origins[0], ('text-am', 'k\n'))
710
        self.assertEquals(origins[1], ('text-a2', 'y\n'))
711
        self.assertEquals(origins[2], ('text-a2', 'z\n'))
712
713
    def test_annotate_merge_4(self):
1563.2.16 by Robert Collins
Change WeaveStore into VersionedFileStore and make its versoined file class parameterisable.
714
        k = self.make_test_knit(True)
1563.2.4 by Robert Collins
First cut at including the knit implementation of versioned_file.
715
        k.add_lines('text-a1', [], ['a\n', 'b\n', 'c\n'])
716
        k.add_lines('text-a2', [], ['x\n', 'y\n', 'z\n'])
717
        k.add_lines('text-a3', ['text-a1'], ['a\n', 'b\n', 'p\n'])
718
        k.add_lines('text-am', ['text-a2', 'text-a3'], ['a\n', 'b\n', 'z\n'])
719
        origins = k.annotate('text-am')
720
        self.assertEquals(origins[0], ('text-a1', 'a\n'))
721
        self.assertEquals(origins[1], ('text-a1', 'b\n'))
722
        self.assertEquals(origins[2], ('text-a2', 'z\n'))
723
724
    def test_annotate_merge_5(self):
1563.2.16 by Robert Collins
Change WeaveStore into VersionedFileStore and make its versoined file class parameterisable.
725
        k = self.make_test_knit(True)
1563.2.4 by Robert Collins
First cut at including the knit implementation of versioned_file.
726
        k.add_lines('text-a1', [], ['a\n', 'b\n', 'c\n'])
727
        k.add_lines('text-a2', [], ['d\n', 'e\n', 'f\n'])
728
        k.add_lines('text-a3', [], ['x\n', 'y\n', 'z\n'])
729
        k.add_lines('text-am',
730
                    ['text-a1', 'text-a2', 'text-a3'],
731
                    ['a\n', 'e\n', 'z\n'])
732
        origins = k.annotate('text-am')
733
        self.assertEquals(origins[0], ('text-a1', 'a\n'))
734
        self.assertEquals(origins[1], ('text-a2', 'e\n'))
735
        self.assertEquals(origins[2], ('text-a3', 'z\n'))
736
737
    def test_annotate_file_cherry_pick(self):
1563.2.16 by Robert Collins
Change WeaveStore into VersionedFileStore and make its versoined file class parameterisable.
738
        k = self.make_test_knit(True)
1563.2.4 by Robert Collins
First cut at including the knit implementation of versioned_file.
739
        k.add_lines('text-1', [], ['a\n', 'b\n', 'c\n'])
740
        k.add_lines('text-2', ['text-1'], ['d\n', 'e\n', 'f\n'])
741
        k.add_lines('text-3', ['text-2', 'text-1'], ['a\n', 'b\n', 'c\n'])
742
        origins = k.annotate('text-3')
743
        self.assertEquals(origins[0], ('text-1', 'a\n'))
744
        self.assertEquals(origins[1], ('text-1', 'b\n'))
745
        self.assertEquals(origins[2], ('text-1', 'c\n'))
746
747
    def test_knit_join(self):
748
        """Store in knit with parents"""
1685.1.39 by John Arbash Meinel
Updating test_knit to not instantiate a LocalTransport directly.
749
        k1 = KnitVersionedFile('test1', get_transport('.'), factory=KnitPlainFactory(), create=True)
1563.2.4 by Robert Collins
First cut at including the knit implementation of versioned_file.
750
        k1.add_lines('text-a', [], split_lines(TEXT_1))
751
        k1.add_lines('text-b', ['text-a'], split_lines(TEXT_1))
752
753
        k1.add_lines('text-c', [], split_lines(TEXT_1))
754
        k1.add_lines('text-d', ['text-c'], split_lines(TEXT_1))
755
756
        k1.add_lines('text-m', ['text-b', 'text-d'], split_lines(TEXT_1))
757
1685.1.39 by John Arbash Meinel
Updating test_knit to not instantiate a LocalTransport directly.
758
        k2 = KnitVersionedFile('test2', get_transport('.'), factory=KnitPlainFactory(), create=True)
1563.2.4 by Robert Collins
First cut at including the knit implementation of versioned_file.
759
        count = k2.join(k1, version_ids=['text-m'])
760
        self.assertEquals(count, 5)
761
        self.assertTrue(k2.has_version('text-a'))
762
        self.assertTrue(k2.has_version('text-c'))
763
764
    def test_reannotate(self):
1685.1.39 by John Arbash Meinel
Updating test_knit to not instantiate a LocalTransport directly.
765
        k1 = KnitVersionedFile('knit1', get_transport('.'),
1563.2.25 by Robert Collins
Merge in upstream.
766
                               factory=KnitAnnotateFactory(), create=True)
1563.2.4 by Robert Collins
First cut at including the knit implementation of versioned_file.
767
        # 0
768
        k1.add_lines('text-a', [], ['a\n', 'b\n'])
769
        # 1
770
        k1.add_lines('text-b', ['text-a'], ['a\n', 'c\n'])
771
1685.1.39 by John Arbash Meinel
Updating test_knit to not instantiate a LocalTransport directly.
772
        k2 = KnitVersionedFile('test2', get_transport('.'),
1563.2.25 by Robert Collins
Merge in upstream.
773
                               factory=KnitAnnotateFactory(), create=True)
1563.2.4 by Robert Collins
First cut at including the knit implementation of versioned_file.
774
        k2.join(k1, version_ids=['text-b'])
775
776
        # 2
777
        k1.add_lines('text-X', ['text-b'], ['a\n', 'b\n'])
778
        # 2
779
        k2.add_lines('text-c', ['text-b'], ['z\n', 'c\n'])
780
        # 3
781
        k2.add_lines('text-Y', ['text-b'], ['b\n', 'c\n'])
782
783
        # test-c will have index 3
784
        k1.join(k2, version_ids=['text-c'])
785
786
        lines = k1.get_lines('text-c')
787
        self.assertEquals(lines, ['z\n', 'c\n'])
788
789
        origins = k1.annotate('text-c')
1594.2.24 by Robert Collins
Make use of the transaction finalisation warning support to implement in-knit caching.
790
        self.assertEquals(origins[0], ('text-c', 'z\n'))
791
        self.assertEquals(origins[1], ('text-b', 'c\n'))
792
1756.3.4 by Aaron Bentley
Fix bug getting texts when line deltas were reused
793
    def test_get_line_delta_texts(self):
794
        """Make sure we can call get_texts on text with reused line deltas"""
795
        k1 = KnitVersionedFile('test1', get_transport('.'), 
796
                               factory=KnitPlainFactory(), create=True)
797
        for t in range(3):
798
            if t == 0:
799
                parents = []
800
            else:
801
                parents = ['%d' % (t-1)]
802
            k1.add_lines('%d' % t, parents, ['hello\n'] * t)
803
        k1.get_texts(('%d' % t) for t in range(3))
1594.3.1 by Robert Collins
Merge transaction finalisation and ensure iter_lines_added_or_present in knits does a old-to-new read in the knit.
804
        
805
    def test_iter_lines_reads_in_order(self):
806
        t = MemoryTransport()
807
        instrumented_t = TransportLogger(t)
808
        k1 = KnitVersionedFile('id', instrumented_t, create=True, delta=True)
809
        self.assertEqual([('id.kndx',)], instrumented_t._calls)
810
        # add texts with no required ordering
811
        k1.add_lines('base', [], ['text\n'])
812
        k1.add_lines('base2', [], ['text2\n'])
813
        k1.clear_cache()
814
        instrumented_t._calls = []
815
        # request a last-first iteration
816
        results = list(k1.iter_lines_added_or_present_in_versions(['base2', 'base']))
1628.1.2 by Robert Collins
More knit micro-optimisations.
817
        self.assertEqual([('id.knit', [(0, 87), (87, 89)])], instrumented_t._calls)
1594.3.1 by Robert Collins
Merge transaction finalisation and ensure iter_lines_added_or_present in knits does a old-to-new read in the knit.
818
        self.assertEqual(['text\n', 'text2\n'], results)
1563.2.4 by Robert Collins
First cut at including the knit implementation of versioned_file.
819
1563.2.13 by Robert Collins
InterVersionedFile implemented.
820
    def test_create_empty_annotated(self):
1563.2.16 by Robert Collins
Change WeaveStore into VersionedFileStore and make its versoined file class parameterisable.
821
        k1 = self.make_test_knit(True)
1563.2.13 by Robert Collins
InterVersionedFile implemented.
822
        # 0
823
        k1.add_lines('text-a', [], ['a\n', 'b\n'])
824
        k2 = k1.create_empty('t', MemoryTransport())
825
        self.assertTrue(isinstance(k2.factory, KnitAnnotateFactory))
826
        self.assertEqual(k1.delta, k2.delta)
827
        # the generic test checks for empty content and file class
828
1641.1.2 by Robert Collins
Change knit index files to be robust in the presence of partial writes.
829
    def test_knit_format(self):
830
        # this tests that a new knit index file has the expected content
831
        # and that is writes the data we expect as records are added.
832
        knit = self.make_test_knit(True)
1946.2.1 by John Arbash Meinel
2 changes to knits. Delay creating the .knit or .kndx file until we have actually tried to write data. Because of this, we must allow the Knit to create the prefix directories
833
        # Now knit files are not created until we first add data to them
1666.1.6 by Robert Collins
Make knit the default format.
834
        self.assertFileEqual("# bzr knit index 8\n", 'test.kndx')
1641.1.2 by Robert Collins
Change knit index files to be robust in the presence of partial writes.
835
        knit.add_lines_with_ghosts('revid', ['a_ghost'], ['a\n'])
836
        self.assertFileEqual(
1666.1.6 by Robert Collins
Make knit the default format.
837
            "# bzr knit index 8\n"
1641.1.2 by Robert Collins
Change knit index files to be robust in the presence of partial writes.
838
            "\n"
839
            "revid fulltext 0 84 .a_ghost :",
840
            'test.kndx')
841
        knit.add_lines_with_ghosts('revid2', ['revid'], ['a\n'])
842
        self.assertFileEqual(
1666.1.6 by Robert Collins
Make knit the default format.
843
            "# bzr knit index 8\n"
1641.1.2 by Robert Collins
Change knit index files to be robust in the presence of partial writes.
844
            "\nrevid fulltext 0 84 .a_ghost :"
845
            "\nrevid2 line-delta 84 82 0 :",
846
            'test.kndx')
847
        # we should be able to load this file again
1685.1.39 by John Arbash Meinel
Updating test_knit to not instantiate a LocalTransport directly.
848
        knit = KnitVersionedFile('test', get_transport('.'), access_mode='r')
1641.1.2 by Robert Collins
Change knit index files to be robust in the presence of partial writes.
849
        self.assertEqual(['revid', 'revid2'], knit.versions())
850
        # write a short write to the file and ensure that its ignored
851
        indexfile = file('test.kndx', 'at')
852
        indexfile.write('\nrevid3 line-delta 166 82 1 2 3 4 5 .phwoar:demo ')
853
        indexfile.close()
854
        # we should be able to load this file again
1685.1.39 by John Arbash Meinel
Updating test_knit to not instantiate a LocalTransport directly.
855
        knit = KnitVersionedFile('test', get_transport('.'), access_mode='w')
1654.1.5 by Robert Collins
Merge partial index write support for knits, adding a test case per review comments.
856
        self.assertEqual(['revid', 'revid2'], knit.versions())
857
        # and add a revision with the same id the failed write had
858
        knit.add_lines('revid3', ['revid2'], ['a\n'])
859
        # and when reading it revid3 should now appear.
1685.1.39 by John Arbash Meinel
Updating test_knit to not instantiate a LocalTransport directly.
860
        knit = KnitVersionedFile('test', get_transport('.'), access_mode='r')
1654.1.5 by Robert Collins
Merge partial index write support for knits, adding a test case per review comments.
861
        self.assertEqual(['revid', 'revid2', 'revid3'], knit.versions())
862
        self.assertEqual(['revid2'], knit.get_parents('revid3'))
863
1946.2.1 by John Arbash Meinel
2 changes to knits. Delay creating the .knit or .kndx file until we have actually tried to write data. Because of this, we must allow the Knit to create the prefix directories
864
    def test_delay_create(self):
865
        """Test that passing delay_create=True creates files late"""
866
        knit = self.make_test_knit(annotate=True, delay_create=True)
867
        self.failIfExists('test.knit')
868
        self.failIfExists('test.kndx')
869
        knit.add_lines_with_ghosts('revid', ['a_ghost'], ['a\n'])
870
        self.failUnlessExists('test.knit')
871
        self.assertFileEqual(
872
            "# bzr knit index 8\n"
873
            "\n"
874
            "revid fulltext 0 84 .a_ghost :",
875
            'test.kndx')
876
1946.2.2 by John Arbash Meinel
test delay_create does the right thing
877
    def test_create_parent_dir(self):
878
        """create_parent_dir can create knits in nonexistant dirs"""
879
        # Has no effect if we don't set 'delay_create'
880
        trans = get_transport('.')
881
        self.assertRaises(NoSuchFile, KnitVersionedFile, 'dir/test',
882
                          trans, access_mode='w', factory=None,
883
                          create=True, create_parent_dir=True)
884
        # Nothing should have changed yet
885
        knit = KnitVersionedFile('dir/test', trans, access_mode='w',
886
                                 factory=None, create=True,
887
                                 create_parent_dir=True,
888
                                 delay_create=True)
889
        self.failIfExists('dir/test.knit')
890
        self.failIfExists('dir/test.kndx')
891
        self.failIfExists('dir')
892
        knit.add_lines('revid', [], ['a\n'])
893
        self.failUnlessExists('dir')
894
        self.failUnlessExists('dir/test.knit')
895
        self.assertFileEqual(
896
            "# bzr knit index 8\n"
897
            "\n"
898
            "revid fulltext 0 84  :",
899
            'dir/test.kndx')
900
1946.2.13 by John Arbash Meinel
Test that passing modes does the right thing for knits.
901
    def test_create_mode_700(self):
902
        trans = get_transport('.')
903
        if not trans._can_roundtrip_unix_modebits():
904
            # Can't roundtrip, so no need to run this test
905
            return
906
        knit = KnitVersionedFile('dir/test', trans, access_mode='w',
907
                                 factory=None, create=True,
908
                                 create_parent_dir=True,
909
                                 delay_create=True,
910
                                 file_mode=0600,
911
                                 dir_mode=0700)
912
        knit.add_lines('revid', [], ['a\n'])
913
        self.assertTransportMode(trans, 'dir', 0700)
914
        self.assertTransportMode(trans, 'dir/test.knit', 0600)
915
        self.assertTransportMode(trans, 'dir/test.kndx', 0600)
916
917
    def test_create_mode_770(self):
918
        trans = get_transport('.')
919
        if not trans._can_roundtrip_unix_modebits():
920
            # Can't roundtrip, so no need to run this test
921
            return
922
        knit = KnitVersionedFile('dir/test', trans, access_mode='w',
923
                                 factory=None, create=True,
924
                                 create_parent_dir=True,
925
                                 delay_create=True,
926
                                 file_mode=0660,
927
                                 dir_mode=0770)
928
        knit.add_lines('revid', [], ['a\n'])
929
        self.assertTransportMode(trans, 'dir', 0770)
930
        self.assertTransportMode(trans, 'dir/test.knit', 0660)
931
        self.assertTransportMode(trans, 'dir/test.kndx', 0660)
932
933
    def test_create_mode_777(self):
934
        trans = get_transport('.')
935
        if not trans._can_roundtrip_unix_modebits():
936
            # Can't roundtrip, so no need to run this test
937
            return
938
        knit = KnitVersionedFile('dir/test', trans, access_mode='w',
939
                                 factory=None, create=True,
940
                                 create_parent_dir=True,
941
                                 delay_create=True,
942
                                 file_mode=0666,
943
                                 dir_mode=0777)
944
        knit.add_lines('revid', [], ['a\n'])
945
        self.assertTransportMode(trans, 'dir', 0777)
946
        self.assertTransportMode(trans, 'dir/test.knit', 0666)
947
        self.assertTransportMode(trans, 'dir/test.kndx', 0666)
948
1664.2.1 by Aaron Bentley
Start work on plan_merge test
949
    def test_plan_merge(self):
950
        my_knit = self.make_test_knit(annotate=True)
951
        my_knit.add_lines('text1', [], split_lines(TEXT_1))
952
        my_knit.add_lines('text1a', ['text1'], split_lines(TEXT_1A))
953
        my_knit.add_lines('text1b', ['text1'], split_lines(TEXT_1B))
1664.2.3 by Aaron Bentley
Add failing test case
954
        plan = list(my_knit.plan_merge('text1a', 'text1b'))
1664.2.6 by Aaron Bentley
Got plan-merge passing tests
955
        for plan_line, expected_line in zip(plan, AB_MERGE):
956
            self.assertEqual(plan_line, expected_line)
1641.1.2 by Robert Collins
Change knit index files to be robust in the presence of partial writes.
957
1563.2.4 by Robert Collins
First cut at including the knit implementation of versioned_file.
958
959
TEXT_1 = """\
960
Banana cup cakes:
961
962
- bananas
963
- eggs
964
- broken tea cups
965
"""
966
967
TEXT_1A = """\
968
Banana cup cake recipe
969
(serves 6)
970
971
- bananas
972
- eggs
973
- broken tea cups
974
- self-raising flour
975
"""
976
1664.2.1 by Aaron Bentley
Start work on plan_merge test
977
TEXT_1B = """\
978
Banana cup cake recipe
979
980
- bananas (do not use plantains!!!)
981
- broken tea cups
982
- flour
983
"""
984
1563.2.4 by Robert Collins
First cut at including the knit implementation of versioned_file.
985
delta_1_1a = """\
986
0,1,2
987
Banana cup cake recipe
988
(serves 6)
989
5,5,1
990
- self-raising flour
991
"""
992
993
TEXT_2 = """\
994
Boeuf bourguignon
995
996
- beef
997
- red wine
998
- small onions
999
- carrot
1000
- mushrooms
1001
"""
1002
1664.2.3 by Aaron Bentley
Add failing test case
1003
AB_MERGE_TEXT="""unchanged|Banana cup cake recipe
1004
new-a|(serves 6)
1005
unchanged|
1006
killed-b|- bananas
1007
killed-b|- eggs
1008
new-b|- bananas (do not use plantains!!!)
1009
unchanged|- broken tea cups
1010
new-a|- self-raising flour
1664.2.6 by Aaron Bentley
Got plan-merge passing tests
1011
new-b|- flour
1012
"""
1664.2.3 by Aaron Bentley
Add failing test case
1013
AB_MERGE=[tuple(l.split('|')) for l in AB_MERGE_TEXT.splitlines(True)]
1014
1015
1563.2.4 by Robert Collins
First cut at including the knit implementation of versioned_file.
1016
def line_delta(from_lines, to_lines):
1017
    """Generate line-based delta from one text to another"""
1018
    s = difflib.SequenceMatcher(None, from_lines, to_lines)
1019
    for op in s.get_opcodes():
1020
        if op[0] == 'equal':
1021
            continue
1022
        yield '%d,%d,%d\n' % (op[1], op[2], op[4]-op[3])
1023
        for i in range(op[3], op[4]):
1024
            yield to_lines[i]
1025
1026
1027
def apply_line_delta(basis_lines, delta_lines):
1028
    """Apply a line-based perfect diff
1029
    
1030
    basis_lines -- text to apply the patch to
1031
    delta_lines -- diff instructions and content
1032
    """
1033
    out = basis_lines[:]
1034
    i = 0
1035
    offset = 0
1036
    while i < len(delta_lines):
1037
        l = delta_lines[i]
1038
        a, b, c = map(long, l.split(','))
1039
        i = i + 1
1040
        out[offset+a:offset+b] = delta_lines[i:i+c]
1041
        i = i + c
1042
        offset = offset + (b - a) + c
1043
    return out
1684.3.3 by Robert Collins
Add a special cased weaves to knit converter.
1044
1045
1046
class TestWeaveToKnit(KnitTests):
1047
1048
    def test_weave_to_knit_matches(self):
1049
        # check that the WeaveToKnit is_compatible function
1050
        # registers True for a Weave to a Knit.
1051
        w = Weave()
1052
        k = self.make_test_knit()
1053
        self.failUnless(WeaveToKnit.is_compatible(w, k))
1054
        self.failIf(WeaveToKnit.is_compatible(k, w))
1055
        self.failIf(WeaveToKnit.is_compatible(w, w))
1056
        self.failIf(WeaveToKnit.is_compatible(k, k))
1863.1.1 by John Arbash Meinel
Allow Versioned files to do caching if explicitly asked, and implement for Knit
1057
1058
1059
class TestKnitCaching(KnitTests):
1060
    
1061
    def create_knit(self, cache_add=False):
1062
        k = self.make_test_knit(True)
1063
        if cache_add:
1064
            k.enable_cache()
1065
1066
        k.add_lines('text-1', [], split_lines(TEXT_1))
1067
        k.add_lines('text-2', [], split_lines(TEXT_2))
1068
        return k
1069
1070
    def test_no_caching(self):
1071
        k = self.create_knit()
1072
        # Nothing should be cached without setting 'enable_cache'
1073
        self.assertEqual({}, k._data._cache)
1074
1075
    def test_cache_add_and_clear(self):
1076
        k = self.create_knit(True)
1077
1078
        self.assertEqual(['text-1', 'text-2'], sorted(k._data._cache.keys()))
1079
1080
        k.clear_cache()
1081
        self.assertEqual({}, k._data._cache)
1082
1083
    def test_cache_data_read_raw(self):
1084
        k = self.create_knit()
1085
1086
        # Now cache and read
1087
        k.enable_cache()
1088
1089
        def read_one_raw(version):
1090
            pos_map = k._get_components_positions([version])
1091
            method, pos, size, next = pos_map[version]
1092
            lst = list(k._data.read_records_iter_raw([(version, pos, size)]))
1093
            self.assertEqual(1, len(lst))
1094
            return lst[0]
1095
1096
        val = read_one_raw('text-1')
1863.1.8 by John Arbash Meinel
Removing disk-backed-cache
1097
        self.assertEqual({'text-1':val[1]}, k._data._cache)
1863.1.1 by John Arbash Meinel
Allow Versioned files to do caching if explicitly asked, and implement for Knit
1098
1099
        k.clear_cache()
1100
        # After clear, new reads are not cached
1101
        self.assertEqual({}, k._data._cache)
1102
1103
        val2 = read_one_raw('text-1')
1104
        self.assertEqual(val, val2)
1105
        self.assertEqual({}, k._data._cache)
1106
1107
    def test_cache_data_read(self):
1108
        k = self.create_knit()
1109
1110
        def read_one(version):
1111
            pos_map = k._get_components_positions([version])
1112
            method, pos, size, next = pos_map[version]
1113
            lst = list(k._data.read_records_iter([(version, pos, size)]))
1114
            self.assertEqual(1, len(lst))
1115
            return lst[0]
1116
1117
        # Now cache and read
1118
        k.enable_cache()
1119
1120
        val = read_one('text-2')
1121
        self.assertEqual(['text-2'], k._data._cache.keys())
1122
        self.assertEqual('text-2', val[0])
1123
        content, digest = k._data._parse_record('text-2',
1124
                                                k._data._cache['text-2'])
1125
        self.assertEqual(content, val[1])
1126
        self.assertEqual(digest, val[2])
1127
1128
        k.clear_cache()
1129
        self.assertEqual({}, k._data._cache)
1130
1131
        val2 = read_one('text-2')
1132
        self.assertEqual(val, val2)
1133
        self.assertEqual({}, k._data._cache)
1134
1135
    def test_cache_read(self):
1136
        k = self.create_knit()
1137
        k.enable_cache()
1138
1139
        text = k.get_text('text-1')
1140
        self.assertEqual(TEXT_1, text)
1141
        self.assertEqual(['text-1'], k._data._cache.keys())
1142
1143
        k.clear_cache()
1144
        self.assertEqual({}, k._data._cache)
1145
1146
        text = k.get_text('text-1')
1147
        self.assertEqual(TEXT_1, text)
1148
        self.assertEqual({}, k._data._cache)
2102.2.1 by John Arbash Meinel
Fix bug #64789 _KnitIndex.add_versions() should dict compress new revisions
1149
1150
1151
class TestKnitIndex(KnitTests):
1152
1153
    def test_add_versions_dictionary_compresses(self):
1154
        """Adding versions to the index should update the lookup dict"""
1155
        knit = self.make_test_knit()
1156
        idx = knit._index
1157
        idx.add_version('a-1', ['fulltext'], 0, 0, [])
1158
        self.check_file_contents('test.kndx',
1159
            '# bzr knit index 8\n'
1160
            '\n'
1161
            'a-1 fulltext 0 0  :'
1162
            )
1163
        idx.add_versions([('a-2', ['fulltext'], 0, 0, ['a-1']),
1164
                          ('a-3', ['fulltext'], 0, 0, ['a-2']),
1165
                         ])
1166
        self.check_file_contents('test.kndx',
1167
            '# bzr knit index 8\n'
1168
            '\n'
1169
            'a-1 fulltext 0 0  :\n'
1170
            'a-2 fulltext 0 0 0 :\n'
1171
            'a-3 fulltext 0 0 1 :'
1172
            )
1173
        self.assertEqual(['a-1', 'a-2', 'a-3'], idx._history)
1174
        self.assertEqual({'a-1':('a-1', ['fulltext'], 0, 0, [], 0),
1175
                          'a-2':('a-2', ['fulltext'], 0, 0, ['a-1'], 1),
1176
                          'a-3':('a-3', ['fulltext'], 0, 0, ['a-2'], 2),
1177
                         }, idx._cache)
1178
1179
    def test_add_versions_fails_clean(self):
1180
        """If add_versions fails in the middle, it restores a pristine state.
1181
1182
        Any modifications that are made to the index are reset if all versions
1183
        cannot be added.
1184
        """
1185
        # This cheats a little bit by passing in a generator which will
1186
        # raise an exception before the processing finishes
1187
        # Other possibilities would be to have an version with the wrong number
1188
        # of entries, or to make the backing transport unable to write any
1189
        # files.
1190
1191
        knit = self.make_test_knit()
1192
        idx = knit._index
1193
        idx.add_version('a-1', ['fulltext'], 0, 0, [])
1194
1195
        class StopEarly(Exception):
1196
            pass
1197
1198
        def generate_failure():
1199
            """Add some entries and then raise an exception"""
1200
            yield ('a-2', ['fulltext'], 0, 0, ['a-1'])
1201
            yield ('a-3', ['fulltext'], 0, 0, ['a-2'])
1202
            raise StopEarly()
1203
1204
        # Assert the pre-condition
1205
        self.assertEqual(['a-1'], idx._history)
1206
        self.assertEqual({'a-1':('a-1', ['fulltext'], 0, 0, [], 0)}, idx._cache)
1207
1208
        self.assertRaises(StopEarly, idx.add_versions, generate_failure())
1209
1210
        # And it shouldn't be modified
1211
        self.assertEqual(['a-1'], idx._history)
1212
        self.assertEqual({'a-1':('a-1', ['fulltext'], 0, 0, [], 0)}, idx._cache)
2171.1.1 by John Arbash Meinel
Knit index files should ignore empty indexes rather than consider them corrupt.
1213
1214
    def test_knit_index_ignores_empty_files(self):
1215
        # There was a race condition in older bzr, where a ^C at the right time
1216
        # could leave an empty .kndx file, which bzr would later claim was a
1217
        # corrupted file since the header was not present. In reality, the file
1218
        # just wasn't created, so it should be ignored.
1219
        t = get_transport('.')
1220
        t.put_bytes('test.kndx', '')
1221
1222
        knit = self.make_test_knit()
1223
1224
    def test_knit_index_checks_header(self):
1225
        t = get_transport('.')
1226
        t.put_bytes('test.kndx', '# not really a knit header\n\n')
1227
2196.2.1 by John Arbash Meinel
Merge Dmitry's optimizations and minimize the actual diff.
1228
        self.assertRaises(KnitHeaderError, self.make_test_knit)