~bzr-pqm/bzr/bzr.dev

0.1.55 by Martin Pool
doc
1
#! /usr/bin/python2.4
2
2052.3.2 by John Arbash Meinel
Change Copyright .. by Canonical to Copyright ... Canonical
3
# Copyright (C) 2005 Canonical Ltd
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
4
#
0.1.2 by Martin Pool
Import testsweet module adapted from bzr.
5
# This program is free software; you can redistribute it and/or modify
6
# it under the terms of the GNU General Public License as published by
7
# the Free Software Foundation; either version 2 of the License, or
8
# (at your option) any later version.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
9
#
0.1.2 by Martin Pool
Import testsweet module adapted from bzr.
10
# This program is distributed in the hope that it will be useful,
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
# GNU General Public License for more details.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
14
#
0.1.2 by Martin Pool
Import testsweet module adapted from bzr.
15
# You should have received a copy of the GNU General Public License
16
# along with this program; if not, write to the Free Software
17
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
19
1083 by Martin Pool
- add space to store revision-id in weave files
20
# TODO: tests regarding version names
1185.13.4 by Robert Collins
make reweave visible as a weave method, and quickly integrate into fetch
21
# TODO: rbc 20050108 test that join does not leave an inconsistent weave 
22
#       if it fails.
0.1.2 by Martin Pool
Import testsweet module adapted from bzr.
23
0.1.38 by Martin Pool
Rename knit to weave. (I don't think there's an existing module called weave.)
24
"""test suite for weave algorithm"""
0.1.2 by Martin Pool
Import testsweet module adapted from bzr.
25
1323 by Martin Pool
- caller can pass SHA-1 to Weave.add for efficiency
26
from pprint import pformat
0.1.2 by Martin Pool
Import testsweet module adapted from bzr.
27
2024.1.1 by John Arbash Meinel
When a weave file is empty, we should get WeaveFormatError, not StopIteration
28
from bzrlib import (
29
    errors,
30
    )
31
from bzrlib.osutils import sha_string
32
from bzrlib.tests import TestCase, TestCaseInTempDir
1393.1.68 by Martin Pool
- add reweave that joins with ghosts
33
from bzrlib.weave import Weave, WeaveFormatError, WeaveError, reweave
872 by Martin Pool
- update testweave
34
from bzrlib.weavefile import write_weave, read_weave
0.1.66 by Martin Pool
Cope without set/frozenset classes
35
36
0.1.2 by Martin Pool
Import testsweet module adapted from bzr.
37
# texts for use in testing
0.1.3 by Martin Pool
Change storage of texts for testing
38
TEXT_0 = ["Hello world"]
39
TEXT_1 = ["Hello world",
40
          "A second line"]
0.1.2 by Martin Pool
Import testsweet module adapted from bzr.
41
42
1233 by Martin Pool
- fix up weave tests for new test framework
43
class TestBase(TestCase):
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
44
    def check_read_write(self, k):
45
        """Check the weave k can be written & re-read."""
46
        from tempfile import TemporaryFile
47
        tf = TemporaryFile()
48
49
        write_weave(k, tf)
50
        tf.seek(0)
51
        k2 = read_weave(tf)
52
53
        if k != k2:
54
            tf.seek(0)
55
            self.log('serialized weave:')
56
            self.log(tf.read())
1083 by Martin Pool
- add space to store revision-id in weave files
57
58
            self.log('')
59
            self.log('parents: %s' % (k._parents == k2._parents))
60
            self.log('         %r' % k._parents)
61
            self.log('         %r' % k2._parents)
62
            self.log('')
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
63
            self.fail('read/write check failed')
1185.16.125 by Martin Pool
Test for 'name in weave'
64
65
66
class WeaveContains(TestBase):
67
    """Weave __contains__ operator"""
68
    def runTest(self):
69
        k = Weave()
70
        self.assertFalse('foo' in k)
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
71
        k.add_lines('foo', [], TEXT_1)
1185.16.125 by Martin Pool
Test for 'name in weave'
72
        self.assertTrue('foo' in k)
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
73
74
0.1.2 by Martin Pool
Import testsweet module adapted from bzr.
75
class Easy(TestBase):
76
    def runTest(self):
0.1.38 by Martin Pool
Rename knit to weave. (I don't think there's an existing module called weave.)
77
        k = Weave()
0.1.2 by Martin Pool
Import testsweet module adapted from bzr.
78
79
80
class StoreText(TestBase):
81
    """Store and retrieve a simple text."""
1594.2.24 by Robert Collins
Make use of the transaction finalisation warning support to implement in-knit caching.
82
83
    def test_storing_text(self):
0.1.38 by Martin Pool
Rename knit to weave. (I don't think there's an existing module called weave.)
84
        k = Weave()
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
85
        idx = k.add_lines('text0', [], TEXT_0)
86
        self.assertEqual(k.get_lines(idx), TEXT_0)
0.1.4 by Martin Pool
Start indexing knits by both integer and version string.
87
        self.assertEqual(idx, 0)
0.1.2 by Martin Pool
Import testsweet module adapted from bzr.
88
89
0.1.7 by Martin Pool
Add trivial annotate text
90
class AnnotateOne(TestBase):
91
    def runTest(self):
0.1.38 by Martin Pool
Rename knit to weave. (I don't think there's an existing module called weave.)
92
        k = Weave()
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
93
        k.add_lines('text0', [], TEXT_0)
94
        self.assertEqual(k.annotate('text0'),
95
                         [('text0', TEXT_0[0])])
0.1.7 by Martin Pool
Add trivial annotate text
96
97
0.1.5 by Martin Pool
Add test for storing two text versions.
98
class StoreTwo(TestBase):
99
    def runTest(self):
0.1.38 by Martin Pool
Rename knit to weave. (I don't think there's an existing module called weave.)
100
        k = Weave()
0.1.5 by Martin Pool
Add test for storing two text versions.
101
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
102
        idx = k.add_lines('text0', [], TEXT_0)
0.1.5 by Martin Pool
Add test for storing two text versions.
103
        self.assertEqual(idx, 0)
104
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
105
        idx = k.add_lines('text1', [], TEXT_1)
0.1.5 by Martin Pool
Add test for storing two text versions.
106
        self.assertEqual(idx, 1)
107
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
108
        self.assertEqual(k.get_lines(0), TEXT_0)
109
        self.assertEqual(k.get_lines(1), TEXT_1)
1323 by Martin Pool
- caller can pass SHA-1 to Weave.add for efficiency
110
111
1185.50.28 by John Arbash Meinel
Lots of updates for 'bzr check'
112
class GetSha1(TestBase):
113
    def test_get_sha1(self):
114
        k = Weave()
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
115
        k.add_lines('text0', [], 'text0')
1185.50.28 by John Arbash Meinel
Lots of updates for 'bzr check'
116
        self.assertEqual('34dc0e430c642a26c3dd1c2beb7a8b4f4445eb79',
117
                         k.get_sha1('text0'))
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
118
        self.assertRaises(errors.RevisionNotPresent,
1185.50.28 by John Arbash Meinel
Lots of updates for 'bzr check'
119
                          k.get_sha1, 0)
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
120
        self.assertRaises(errors.RevisionNotPresent,
1185.50.28 by John Arbash Meinel
Lots of updates for 'bzr check'
121
                          k.get_sha1, 'text1')
122
                        
1323 by Martin Pool
- caller can pass SHA-1 to Weave.add for efficiency
123
0.1.27 by Martin Pool
Check that version numbers passed in are reasonable
124
class InvalidAdd(TestBase):
125
    """Try to use invalid version number during add."""
126
    def runTest(self):
0.1.38 by Martin Pool
Rename knit to weave. (I don't think there's an existing module called weave.)
127
        k = Weave()
0.1.27 by Martin Pool
Check that version numbers passed in are reasonable
128
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
129
        self.assertRaises(errors.RevisionNotPresent,
130
                          k.add_lines,
1083 by Martin Pool
- add space to store revision-id in weave files
131
                          'text0',
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
132
                          ['69'],
0.1.27 by Martin Pool
Check that version numbers passed in are reasonable
133
                          ['new text!'])
134
135
1237 by Martin Pool
- allow the same version to be repeatedly added to a weave
136
class RepeatedAdd(TestBase):
137
    """Add the same version twice; harmless."""
138
    def runTest(self):
139
        k = Weave()
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
140
        idx = k.add_lines('text0', [], TEXT_0)
141
        idx2 = k.add_lines('text0', [], TEXT_0)
1237 by Martin Pool
- allow the same version to be repeatedly added to a weave
142
        self.assertEqual(idx, idx2)
143
144
145
class InvalidRepeatedAdd(TestBase):
146
    def runTest(self):
147
        k = Weave()
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
148
        k.add_lines('basis', [], TEXT_0)
149
        idx = k.add_lines('text0', [], TEXT_0)
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
150
        self.assertRaises(errors.RevisionAlreadyPresent,
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
151
                          k.add_lines,
1237 by Martin Pool
- allow the same version to be repeatedly added to a weave
152
                          'text0',
153
                          [],
154
                          ['not the same text'])
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
155
        self.assertRaises(errors.RevisionAlreadyPresent,
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
156
                          k.add_lines,
1237 by Martin Pool
- allow the same version to be repeatedly added to a weave
157
                          'text0',
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
158
                          ['basis'],         # not the right parents
1237 by Martin Pool
- allow the same version to be repeatedly added to a weave
159
                          TEXT_0)
160
        
161
0.1.26 by Martin Pool
Refactor parameters to add command
162
class InsertLines(TestBase):
0.1.13 by Martin Pool
Knit structure now allows for versions to include the lines present in other
163
    """Store a revision that adds one line to the original.
164
165
    Look at the annotations to make sure that the first line is matched
166
    and not stored repeatedly."""
167
    def runTest(self):
0.1.38 by Martin Pool
Rename knit to weave. (I don't think there's an existing module called weave.)
168
        k = Weave()
0.1.13 by Martin Pool
Knit structure now allows for versions to include the lines present in other
169
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
170
        k.add_lines('text0', [], ['line 1'])
171
        k.add_lines('text1', ['text0'], ['line 1', 'line 2'])
172
173
        self.assertEqual(k.annotate('text0'),
174
                         [('text0', 'line 1')])
175
176
        self.assertEqual(k.get_lines(1),
0.1.25 by Martin Pool
Handle insertion of new weave layers that insert text on top of the basis
177
                         ['line 1',
178
                          'line 2'])
179
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
180
        self.assertEqual(k.annotate('text1'),
181
                         [('text0', 'line 1'),
182
                          ('text1', 'line 2')])
183
184
        k.add_lines('text2', ['text0'], ['line 1', 'diverged line'])
185
186
        self.assertEqual(k.annotate('text2'),
187
                         [('text0', 'line 1'),
188
                          ('text2', 'diverged line')])
0.1.28 by Martin Pool
More tests for insertion of lines in new versions.
189
0.1.54 by Martin Pool
Fix weave line calculation when making deltas
190
        text3 = ['line 1', 'middle line', 'line 2']
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
191
        k.add_lines('text3',
192
              ['text0', 'text1'],
0.1.54 by Martin Pool
Fix weave line calculation when making deltas
193
              text3)
194
937 by Martin Pool
- weave raises IndexError when an invalid revision is given
195
        # self.log("changes to text3: " + pformat(list(k._delta(set([0, 1]), text3))))
0.1.54 by Martin Pool
Fix weave line calculation when making deltas
196
944 by Martin Pool
- refactor member names in Weave code
197
        self.log("k._weave=" + pformat(k._weave))
0.1.28 by Martin Pool
More tests for insertion of lines in new versions.
198
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
199
        self.assertEqual(k.annotate('text3'),
200
                         [('text0', 'line 1'),
201
                          ('text3', 'middle line'),
202
                          ('text1', 'line 2')])
0.1.28 by Martin Pool
More tests for insertion of lines in new versions.
203
0.1.31 by Martin Pool
Fix insertion of multiple regions, calculating the right line offset as we go.
204
        # now multiple insertions at different places
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
205
        k.add_lines('text4',
206
              ['text0', 'text1', 'text3'],
0.1.31 by Martin Pool
Fix insertion of multiple regions, calculating the right line offset as we go.
207
              ['line 1', 'aaa', 'middle line', 'bbb', 'line 2', 'ccc'])
208
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
209
        self.assertEqual(k.annotate('text4'), 
210
                         [('text0', 'line 1'),
211
                          ('text4', 'aaa'),
212
                          ('text3', 'middle line'),
213
                          ('text4', 'bbb'),
214
                          ('text1', 'line 2'),
215
                          ('text4', 'ccc')])
0.1.13 by Martin Pool
Knit structure now allows for versions to include the lines present in other
216
0.1.40 by Martin Pool
Add test for extracting from weave with nested insertions
217
0.1.56 by Martin Pool
Handle deletion of lines by marking the region with a deletion
218
class DeleteLines(TestBase):
219
    """Deletion of lines from existing text.
220
221
    Try various texts all based on a common ancestor."""
222
    def runTest(self):
223
        k = Weave()
224
225
        base_text = ['one', 'two', 'three', 'four']
226
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
227
        k.add_lines('text0', [], base_text)
0.1.56 by Martin Pool
Handle deletion of lines by marking the region with a deletion
228
        
229
        texts = [['one', 'two', 'three'],
230
                 ['two', 'three', 'four'],
231
                 ['one', 'four'],
232
                 ['one', 'two', 'three', 'four'],
233
                 ]
234
1083 by Martin Pool
- add space to store revision-id in weave files
235
        i = 1
0.1.56 by Martin Pool
Handle deletion of lines by marking the region with a deletion
236
        for t in texts:
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
237
            ver = k.add_lines('text%d' % i,
238
                        ['text0'], t)
1083 by Martin Pool
- add space to store revision-id in weave files
239
            i += 1
0.1.56 by Martin Pool
Handle deletion of lines by marking the region with a deletion
240
241
        self.log('final weave:')
944 by Martin Pool
- refactor member names in Weave code
242
        self.log('k._weave=' + pformat(k._weave))
0.1.56 by Martin Pool
Handle deletion of lines by marking the region with a deletion
243
244
        for i in range(len(texts)):
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
245
            self.assertEqual(k.get_lines(i+1),
0.1.56 by Martin Pool
Handle deletion of lines by marking the region with a deletion
246
                             texts[i])
247
248
0.1.49 by Martin Pool
Add another constraint: revisions should not delete text that they
249
class SuicideDelete(TestBase):
0.1.55 by Martin Pool
doc
250
    """Invalid weave which tries to add and delete simultaneously."""
0.1.49 by Martin Pool
Add another constraint: revisions should not delete text that they
251
    def runTest(self):
252
        k = Weave()
253
944 by Martin Pool
- refactor member names in Weave code
254
        k._parents = [(),
0.1.49 by Martin Pool
Add another constraint: revisions should not delete text that they
255
                ]
944 by Martin Pool
- refactor member names in Weave code
256
        k._weave = [('{', 0),
0.1.49 by Martin Pool
Add another constraint: revisions should not delete text that they
257
                'first line',
258
                ('[', 0),
259
                'deleted in 0',
260
                (']', 0),
261
                ('}', 0),
262
                ]
891 by Martin Pool
- fix up refactoring of weave
263
        ################################### SKIPPED
264
        # Weave.get doesn't trap this anymore
265
        return 
0.1.49 by Martin Pool
Add another constraint: revisions should not delete text that they
266
267
        self.assertRaises(WeaveFormatError,
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
268
                          k.get_lines,
0.1.49 by Martin Pool
Add another constraint: revisions should not delete text that they
269
                          0)        
270
271
0.1.48 by Martin Pool
Basic parsing of delete instructions.
272
class CannedDelete(TestBase):
273
    """Unpack canned weave with deleted lines."""
274
    def runTest(self):
275
        k = Weave()
276
944 by Martin Pool
- refactor member names in Weave code
277
        k._parents = [(),
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
278
                frozenset([0]),
0.1.48 by Martin Pool
Basic parsing of delete instructions.
279
                ]
944 by Martin Pool
- refactor member names in Weave code
280
        k._weave = [('{', 0),
0.1.48 by Martin Pool
Basic parsing of delete instructions.
281
                'first line',
282
                ('[', 1),
283
                'line to be deleted',
284
                (']', 1),
285
                'last line',
286
                ('}', 0),
287
                ]
1185.50.23 by John Arbash Meinel
Adding sha1 check when weave extracts a text.
288
        k._sha1s = [sha_string('first lineline to be deletedlast line')
289
                  , sha_string('first linelast line')]
0.1.48 by Martin Pool
Basic parsing of delete instructions.
290
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
291
        self.assertEqual(k.get_lines(0),
0.1.48 by Martin Pool
Basic parsing of delete instructions.
292
                         ['first line',
293
                          'line to be deleted',
294
                          'last line',
295
                          ])
296
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
297
        self.assertEqual(k.get_lines(1),
0.1.50 by Martin Pool
Basic implementation of deletion markers
298
                         ['first line',
299
                          'last line',
300
                          ])
301
0.1.48 by Martin Pool
Basic parsing of delete instructions.
302
0.1.51 by Martin Pool
Add test for replacement lines
303
class CannedReplacement(TestBase):
304
    """Unpack canned weave with deleted lines."""
305
    def runTest(self):
306
        k = Weave()
307
944 by Martin Pool
- refactor member names in Weave code
308
        k._parents = [frozenset(),
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
309
                frozenset([0]),
0.1.51 by Martin Pool
Add test for replacement lines
310
                ]
944 by Martin Pool
- refactor member names in Weave code
311
        k._weave = [('{', 0),
0.1.51 by Martin Pool
Add test for replacement lines
312
                'first line',
313
                ('[', 1),
314
                'line to be deleted',
315
                (']', 1),
316
                ('{', 1),
317
                'replacement line',                
318
                ('}', 1),
319
                'last line',
320
                ('}', 0),
321
                ]
1185.50.23 by John Arbash Meinel
Adding sha1 check when weave extracts a text.
322
        k._sha1s = [sha_string('first lineline to be deletedlast line')
323
                  , sha_string('first linereplacement linelast line')]
0.1.51 by Martin Pool
Add test for replacement lines
324
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
325
        self.assertEqual(k.get_lines(0),
0.1.51 by Martin Pool
Add test for replacement lines
326
                         ['first line',
327
                          'line to be deleted',
328
                          'last line',
329
                          ])
330
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
331
        self.assertEqual(k.get_lines(1),
0.1.51 by Martin Pool
Add test for replacement lines
332
                         ['first line',
333
                          'replacement line',
334
                          'last line',
335
                          ])
336
337
0.1.46 by Martin Pool
More constraints on structure of weave, and checks that they work
338
class BadWeave(TestBase):
339
    """Test that we trap an insert which should not occur."""
340
    def runTest(self):
341
        k = Weave()
342
944 by Martin Pool
- refactor member names in Weave code
343
        k._parents = [frozenset(),
0.1.46 by Martin Pool
More constraints on structure of weave, and checks that they work
344
                ]
944 by Martin Pool
- refactor member names in Weave code
345
        k._weave = ['bad line',
0.1.46 by Martin Pool
More constraints on structure of weave, and checks that they work
346
                ('{', 0),
347
                'foo {',
348
                ('{', 1),
349
                '  added in version 1',
350
                ('{', 2),
351
                '  added in v2',
352
                ('}', 2),
353
                '  also from v1',
354
                ('}', 1),
355
                '}',
356
                ('}', 0)]
357
891 by Martin Pool
- fix up refactoring of weave
358
        ################################### SKIPPED
359
        # Weave.get doesn't trap this anymore
360
        return 
361
362
0.1.47 by Martin Pool
New WeaveError and WeaveFormatError rather than assertions.
363
        self.assertRaises(WeaveFormatError,
0.1.46 by Martin Pool
More constraints on structure of weave, and checks that they work
364
                          k.get,
365
                          0)
366
367
368
class BadInsert(TestBase):
369
    """Test that we trap an insert which should not occur."""
370
    def runTest(self):
371
        k = Weave()
372
944 by Martin Pool
- refactor member names in Weave code
373
        k._parents = [frozenset(),
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
374
                frozenset([0]),
375
                frozenset([0]),
376
                frozenset([0,1,2]),
0.1.46 by Martin Pool
More constraints on structure of weave, and checks that they work
377
                ]
944 by Martin Pool
- refactor member names in Weave code
378
        k._weave = [('{', 0),
0.1.46 by Martin Pool
More constraints on structure of weave, and checks that they work
379
                'foo {',
380
                ('{', 1),
381
                '  added in version 1',
382
                ('{', 1),
383
                '  more in 1',
384
                ('}', 1),
385
                ('}', 1),
386
                ('}', 0)]
387
891 by Martin Pool
- fix up refactoring of weave
388
389
        # this is not currently enforced by get
390
        return  ##########################################
391
0.1.47 by Martin Pool
New WeaveError and WeaveFormatError rather than assertions.
392
        self.assertRaises(WeaveFormatError,
0.1.46 by Martin Pool
More constraints on structure of weave, and checks that they work
393
                          k.get,
394
                          0)
395
0.1.47 by Martin Pool
New WeaveError and WeaveFormatError rather than assertions.
396
        self.assertRaises(WeaveFormatError,
0.1.46 by Martin Pool
More constraints on structure of weave, and checks that they work
397
                          k.get,
398
                          1)
399
0.1.40 by Martin Pool
Add test for extracting from weave with nested insertions
400
401
class InsertNested(TestBase):
402
    """Insertion with nested instructions."""
403
    def runTest(self):
404
        k = Weave()
405
944 by Martin Pool
- refactor member names in Weave code
406
        k._parents = [frozenset(),
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
407
                frozenset([0]),
408
                frozenset([0]),
409
                frozenset([0,1,2]),
0.1.40 by Martin Pool
Add test for extracting from weave with nested insertions
410
                ]
944 by Martin Pool
- refactor member names in Weave code
411
        k._weave = [('{', 0),
0.1.40 by Martin Pool
Add test for extracting from weave with nested insertions
412
                'foo {',
413
                ('{', 1),
414
                '  added in version 1',
0.1.42 by Martin Pool
More tests for nested insert instructions
415
                ('{', 2),
416
                '  added in v2',
417
                ('}', 2),
418
                '  also from v1',
0.1.40 by Martin Pool
Add test for extracting from weave with nested insertions
419
                ('}', 1),
420
                '}',
421
                ('}', 0)]
422
1185.50.23 by John Arbash Meinel
Adding sha1 check when weave extracts a text.
423
        k._sha1s = [sha_string('foo {}')
424
                  , sha_string('foo {  added in version 1  also from v1}')
425
                  , sha_string('foo {  added in v2}')
426
                  , sha_string('foo {  added in version 1  added in v2  also from v1}')
427
                  ]
428
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
429
        self.assertEqual(k.get_lines(0),
0.1.40 by Martin Pool
Add test for extracting from weave with nested insertions
430
                         ['foo {',
431
                          '}'])
432
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
433
        self.assertEqual(k.get_lines(1),
0.1.40 by Martin Pool
Add test for extracting from weave with nested insertions
434
                         ['foo {',
435
                          '  added in version 1',
0.1.42 by Martin Pool
More tests for nested insert instructions
436
                          '  also from v1',
0.1.40 by Martin Pool
Add test for extracting from weave with nested insertions
437
                          '}'])
438
                       
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
439
        self.assertEqual(k.get_lines(2),
0.1.44 by Martin Pool
More tests for nested insert instructions
440
                         ['foo {',
441
                          '  added in v2',
442
                          '}'])
443
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
444
        self.assertEqual(k.get_lines(3),
0.1.44 by Martin Pool
More tests for nested insert instructions
445
                         ['foo {',
446
                          '  added in version 1',
447
                          '  added in v2',
448
                          '  also from v1',
449
                          '}'])
450
                         
0.1.45 by Martin Pool
doc
451
0.1.56 by Martin Pool
Handle deletion of lines by marking the region with a deletion
452
class DeleteLines2(TestBase):
0.1.30 by Martin Pool
Start adding tests for line deletion
453
    """Test recording revisions that delete lines.
454
455
    This relies on the weave having a way to represent lines knocked
456
    out by a later revision."""
457
    def runTest(self):
0.1.38 by Martin Pool
Rename knit to weave. (I don't think there's an existing module called weave.)
458
        k = Weave()
0.1.30 by Martin Pool
Start adding tests for line deletion
459
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
460
        k.add_lines('text0', [], ["line the first",
0.1.30 by Martin Pool
Start adding tests for line deletion
461
                   "line 2",
462
                   "line 3",
463
                   "fine"])
464
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
465
        self.assertEqual(len(k.get_lines(0)), 4)
0.1.30 by Martin Pool
Start adding tests for line deletion
466
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
467
        k.add_lines('text1', ['text0'], ["line the first",
0.1.30 by Martin Pool
Start adding tests for line deletion
468
                   "fine"])
469
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
470
        self.assertEqual(k.get_lines(1),
0.1.30 by Martin Pool
Start adding tests for line deletion
471
                         ["line the first",
472
                          "fine"])
473
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
474
        self.assertEqual(k.annotate('text1'),
475
                         [('text0', "line the first"),
476
                          ('text0', "fine")])
0.1.56 by Martin Pool
Handle deletion of lines by marking the region with a deletion
477
0.1.30 by Martin Pool
Start adding tests for line deletion
478
0.1.13 by Martin Pool
Knit structure now allows for versions to include the lines present in other
479
class IncludeVersions(TestBase):
480
    """Check texts that are stored across multiple revisions.
481
0.1.38 by Martin Pool
Rename knit to weave. (I don't think there's an existing module called weave.)
482
    Here we manually create a weave with particular encoding and make
0.1.13 by Martin Pool
Knit structure now allows for versions to include the lines present in other
483
    sure it unpacks properly.
484
485
    Text 0 includes nothing; text 1 includes text 0 and adds some
486
    lines.
487
    """
488
489
    def runTest(self):
0.1.38 by Martin Pool
Rename knit to weave. (I don't think there's an existing module called weave.)
490
        k = Weave()
0.1.13 by Martin Pool
Knit structure now allows for versions to include the lines present in other
491
944 by Martin Pool
- refactor member names in Weave code
492
        k._parents = [frozenset(), frozenset([0])]
493
        k._weave = [('{', 0),
0.1.39 by Martin Pool
Change to a more realistic weave structure which can represent insertions and
494
                "first line",
495
                ('}', 0),
496
                ('{', 1),
497
                "second line",
498
                ('}', 1)]
0.1.13 by Martin Pool
Knit structure now allows for versions to include the lines present in other
499
1185.50.23 by John Arbash Meinel
Adding sha1 check when weave extracts a text.
500
        k._sha1s = [sha_string('first line')
501
                  , sha_string('first linesecond line')]
502
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
503
        self.assertEqual(k.get_lines(1),
0.1.13 by Martin Pool
Knit structure now allows for versions to include the lines present in other
504
                         ["first line",
505
                          "second line"])
506
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
507
        self.assertEqual(k.get_lines(0),
0.1.13 by Martin Pool
Knit structure now allows for versions to include the lines present in other
508
                         ["first line"])
509
0.1.5 by Martin Pool
Add test for storing two text versions.
510
0.1.14 by Martin Pool
Another test for version inclusion
511
class DivergedIncludes(TestBase):
0.1.38 by Martin Pool
Rename knit to weave. (I don't think there's an existing module called weave.)
512
    """Weave with two diverged texts based on version 0.
0.1.14 by Martin Pool
Another test for version inclusion
513
    """
514
    def runTest(self):
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
515
        # FIXME make the weave, dont poke at it.
0.1.38 by Martin Pool
Rename knit to weave. (I don't think there's an existing module called weave.)
516
        k = Weave()
0.1.14 by Martin Pool
Another test for version inclusion
517
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
518
        k._names = ['0', '1', '2']
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
519
        k._name_map = {'0':0, '1':1, '2':2}
944 by Martin Pool
- refactor member names in Weave code
520
        k._parents = [frozenset(),
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
521
                frozenset([0]),
522
                frozenset([0]),
0.1.17 by Martin Pool
Use objects rather than tuples for tracking VerInfo for
523
                ]
944 by Martin Pool
- refactor member names in Weave code
524
        k._weave = [('{', 0),
0.1.39 by Martin Pool
Change to a more realistic weave structure which can represent insertions and
525
                "first line",
526
                ('}', 0),
527
                ('{', 1),
528
                "second line",
529
                ('}', 1),
530
                ('{', 2),
531
                "alternative second line",
532
                ('}', 2),                
533
                ]
0.1.14 by Martin Pool
Another test for version inclusion
534
1185.50.23 by John Arbash Meinel
Adding sha1 check when weave extracts a text.
535
        k._sha1s = [sha_string('first line')
536
                  , sha_string('first linesecond line')
537
                  , sha_string('first linealternative second line')]
538
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
539
        self.assertEqual(k.get_lines(0),
0.1.14 by Martin Pool
Another test for version inclusion
540
                         ["first line"])
541
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
542
        self.assertEqual(k.get_lines(1),
0.1.14 by Martin Pool
Another test for version inclusion
543
                         ["first line",
544
                          "second line"])
545
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
546
        self.assertEqual(k.get_lines('2'),
0.1.14 by Martin Pool
Another test for version inclusion
547
                         ["first line",
548
                          "alternative second line"])
549
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
550
        self.assertEqual(list(k.get_ancestry(['2'])),
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
551
                         ['0', '2'])
0.1.77 by Martin Pool
New Weave.get_included() does transitive expansion
552
0.1.57 by Martin Pool
Fix bug in an update edit that both deletes and inserts -- previously
553
554
class ReplaceLine(TestBase):
555
    def runTest(self):
556
        k = Weave()
557
558
        text0 = ['cheddar', 'stilton', 'gruyere']
559
        text1 = ['cheddar', 'blue vein', 'neufchatel', 'chevre']
560
        
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
561
        k.add_lines('text0', [], text0)
562
        k.add_lines('text1', ['text0'], text1)
0.1.57 by Martin Pool
Fix bug in an update edit that both deletes and inserts -- previously
563
944 by Martin Pool
- refactor member names in Weave code
564
        self.log('k._weave=' + pformat(k._weave))
0.1.57 by Martin Pool
Fix bug in an update edit that both deletes and inserts -- previously
565
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
566
        self.assertEqual(k.get_lines(0), text0)
567
        self.assertEqual(k.get_lines(1), text1)
0.1.57 by Martin Pool
Fix bug in an update edit that both deletes and inserts -- previously
568
0.1.64 by Martin Pool
Add test for merging versions
569
570
class Merge(TestBase):
0.1.95 by Martin Pool
- preliminary merge conflict detection
571
    """Storage of versions that merge diverged parents"""
0.1.64 by Martin Pool
Add test for merging versions
572
    def runTest(self):
573
        k = Weave()
574
575
        texts = [['header'],
576
                 ['header', '', 'line from 1'],
577
                 ['header', '', 'line from 2', 'more from 2'],
578
                 ['header', '', 'line from 1', 'fixup line', 'line from 2'],
579
                 ]
580
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
581
        k.add_lines('text0', [], texts[0])
582
        k.add_lines('text1', ['text0'], texts[1])
583
        k.add_lines('text2', ['text0'], texts[2])
584
        k.add_lines('merge', ['text0', 'text1', 'text2'], texts[3])
0.1.64 by Martin Pool
Add test for merging versions
585
586
        for i, t in enumerate(texts):
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
587
            self.assertEqual(k.get_lines(i), t)
0.1.64 by Martin Pool
Add test for merging versions
588
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
589
        self.assertEqual(k.annotate('merge'),
590
                         [('text0', 'header'),
591
                          ('text1', ''),
592
                          ('text1', 'line from 1'),
593
                          ('merge', 'fixup line'),
594
                          ('text2', 'line from 2'),
0.1.64 by Martin Pool
Add test for merging versions
595
                          ])
596
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
597
        self.assertEqual(list(k.get_ancestry(['merge'])),
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
598
                         ['text0', 'text1', 'text2', 'merge'])
0.1.77 by Martin Pool
New Weave.get_included() does transitive expansion
599
944 by Martin Pool
- refactor member names in Weave code
600
        self.log('k._weave=' + pformat(k._weave))
0.1.64 by Martin Pool
Add test for merging versions
601
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
602
        self.check_read_write(k)
0.1.65 by Martin Pool
Add Weave.merge_iter to get automerged lines
603
604
0.1.95 by Martin Pool
- preliminary merge conflict detection
605
class Conflicts(TestBase):
606
    """Test detection of conflicting regions during a merge.
607
608
    A base version is inserted, then two descendents try to
609
    insert different lines in the same place.  These should be
610
    reported as a possible conflict and forwarded to the user."""
611
    def runTest(self):
612
        return  # NOT RUN
613
        k = Weave()
614
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
615
        k.add_lines([], ['aaa', 'bbb'])
616
        k.add_lines([0], ['aaa', '111', 'bbb'])
617
        k.add_lines([1], ['aaa', '222', 'bbb'])
0.1.95 by Martin Pool
- preliminary merge conflict detection
618
619
        merged = k.merge([1, 2])
620
621
        self.assertEquals([[['aaa']],
622
                           [['111'], ['222']],
623
                           [['bbb']]])
624
625
626
class NonConflict(TestBase):
627
    """Two descendants insert compatible changes.
628
629
    No conflict should be reported."""
630
    def runTest(self):
631
        return  # NOT RUN
632
        k = Weave()
633
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
634
        k.add_lines([], ['aaa', 'bbb'])
635
        k.add_lines([0], ['111', 'aaa', 'ccc', 'bbb'])
636
        k.add_lines([1], ['aaa', 'ccc', 'bbb', '222'])
0.1.95 by Martin Pool
- preliminary merge conflict detection
637
638
0.1.57 by Martin Pool
Fix bug in an update edit that both deletes and inserts -- previously
639
class Khayyam(TestBase):
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
640
    """Test changes to multi-line texts, and read/write"""
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
641
642
    def test_multi_line_merge(self):
0.1.57 by Martin Pool
Fix bug in an update edit that both deletes and inserts -- previously
643
        rawtexts = [
644
            """A Book of Verses underneath the Bough,
645
            A Jug of Wine, a Loaf of Bread, -- and Thou
646
            Beside me singing in the Wilderness --
647
            Oh, Wilderness were Paradise enow!""",
648
            
649
            """A Book of Verses underneath the Bough,
650
            A Jug of Wine, a Loaf of Bread, -- and Thou
651
            Beside me singing in the Wilderness --
652
            Oh, Wilderness were Paradise now!""",
0.1.59 by Martin Pool
More modification tests
653
654
            """A Book of poems underneath the tree,
655
            A Jug of Wine, a Loaf of Bread,
656
            and Thou
657
            Beside me singing in the Wilderness --
658
            Oh, Wilderness were Paradise now!
659
660
            -- O. Khayyam""",
661
662
            """A Book of Verses underneath the Bough,
663
            A Jug of Wine, a Loaf of Bread,
664
            and Thou
665
            Beside me singing in the Wilderness --
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
666
            Oh, Wilderness were Paradise now!""",
0.1.57 by Martin Pool
Fix bug in an update edit that both deletes and inserts -- previously
667
            ]
668
        texts = [[l.strip() for l in t.split('\n')] for t in rawtexts]
669
670
        k = Weave()
671
        parents = set()
1083 by Martin Pool
- add space to store revision-id in weave files
672
        i = 0
0.1.57 by Martin Pool
Fix bug in an update edit that both deletes and inserts -- previously
673
        for t in texts:
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
674
            ver = k.add_lines('text%d' % i,
1083 by Martin Pool
- add space to store revision-id in weave files
675
                        list(parents), t)
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
676
            parents.add('text%d' % i)
1083 by Martin Pool
- add space to store revision-id in weave files
677
            i += 1
0.1.57 by Martin Pool
Fix bug in an update edit that both deletes and inserts -- previously
678
944 by Martin Pool
- refactor member names in Weave code
679
        self.log("k._weave=" + pformat(k._weave))
0.1.59 by Martin Pool
More modification tests
680
0.1.57 by Martin Pool
Fix bug in an update edit that both deletes and inserts -- previously
681
        for i, t in enumerate(texts):
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
682
            self.assertEqual(k.get_lines(i), t)
0.1.57 by Martin Pool
Fix bug in an update edit that both deletes and inserts -- previously
683
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
684
        self.check_read_write(k)
0.1.57 by Martin Pool
Fix bug in an update edit that both deletes and inserts -- previously
685
686
1393.1.48 by Martin Pool
- Add stub Weave.join() method
687
class JoinWeavesTests(TestBase):
1393.1.50 by Martin Pool
- more development of Weave.join()
688
    def setUp(self):
689
        super(JoinWeavesTests, self).setUp()
690
        self.weave1 = Weave()
691
        self.lines1 = ['hello\n']
692
        self.lines3 = ['hello\n', 'cruel\n', 'world\n']
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
693
        self.weave1.add_lines('v1', [], self.lines1)
694
        self.weave1.add_lines('v2', ['v1'], ['hello\n', 'world\n'])
695
        self.weave1.add_lines('v3', ['v2'], self.lines3)
1393.1.50 by Martin Pool
- more development of Weave.join()
696
        
1393.1.48 by Martin Pool
- Add stub Weave.join() method
697
    def test_join_empty(self):
698
        """Join two empty weaves."""
699
        eq = self.assertEqual
700
        w1 = Weave()
701
        w2 = Weave()
702
        w1.join(w2)
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
703
        eq(len(w1), 0)
1393.1.48 by Martin Pool
- Add stub Weave.join() method
704
        
1393.1.50 by Martin Pool
- more development of Weave.join()
705
    def test_join_empty_to_nonempty(self):
706
        """Join empty weave onto nonempty."""
707
        self.weave1.join(Weave())
708
        self.assertEqual(len(self.weave1), 3)
709
710
    def test_join_unrelated(self):
711
        """Join two weaves with no history in common."""
712
        wb = Weave()
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
713
        wb.add_lines('b1', [], ['line from b\n'])
1393.1.50 by Martin Pool
- more development of Weave.join()
714
        w1 = self.weave1
715
        w1.join(wb)
716
        eq = self.assertEqual
717
        eq(len(w1), 4)
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
718
        eq(sorted(w1.versions()),
1393.1.50 by Martin Pool
- more development of Weave.join()
719
           ['b1', 'v1', 'v2', 'v3'])
920 by Martin Pool
- add more test cases for weave_merge
720
1393.1.51 by Martin Pool
- new Weave.copy()
721
    def test_join_related(self):
722
        wa = self.weave1.copy()
723
        wb = self.weave1.copy()
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
724
        wa.add_lines('a1', ['v3'], ['hello\n', 'sweet\n', 'world\n'])
725
        wb.add_lines('b1', ['v3'], ['hello\n', 'pale blue\n', 'world\n'])
1393.1.51 by Martin Pool
- new Weave.copy()
726
        eq = self.assertEquals
727
        eq(len(wa), 4)
728
        eq(len(wb), 4)
729
        wa.join(wb)
730
        eq(len(wa), 5)
731
        eq(wa.get_lines('b1'),
732
           ['hello\n', 'pale blue\n', 'world\n'])
733
1393.1.67 by Martin Pool
- test that we cannot join weaves with different ancestry
734
    def test_join_parent_disagreement(self):
1563.2.11 by Robert Collins
Consolidate reweave and join as we have no separate usage, make reweave tests apply to all versionedfile implementations and deprecate the old reweave apis.
735
        #join reconciles differening parents into a union.
1393.1.67 by Martin Pool
- test that we cannot join weaves with different ancestry
736
        wa = Weave()
737
        wb = Weave()
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
738
        wa.add_lines('v1', [], ['hello\n'])
739
        wb.add_lines('v0', [], [])
740
        wb.add_lines('v1', ['v0'], ['hello\n'])
1563.2.11 by Robert Collins
Consolidate reweave and join as we have no separate usage, make reweave tests apply to all versionedfile implementations and deprecate the old reweave apis.
741
        wa.join(wb)
742
        self.assertEqual(['v0'], wa.get_parents('v1'))
1393.1.67 by Martin Pool
- test that we cannot join weaves with different ancestry
743
744
    def test_join_text_disagreement(self):
745
        """Cannot join weaves with different texts for a version."""
746
        wa = Weave()
747
        wb = Weave()
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
748
        wa.add_lines('v1', [], ['hello\n'])
749
        wb.add_lines('v1', [], ['not\n', 'hello\n'])
1393.1.67 by Martin Pool
- test that we cannot join weaves with different ancestry
750
        self.assertRaises(WeaveError,
751
                          wa.join, wb)
752
1393.1.66 by Martin Pool
- fix join of weaves where parents occur at different offsets
753
    def test_join_unordered(self):
754
        """Join weaves where indexes differ.
755
        
756
        The source weave contains a different version at index 0."""
757
        wa = self.weave1.copy()
758
        wb = Weave()
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
759
        wb.add_lines('x1', [], ['line from x1\n'])
760
        wb.add_lines('v1', [], ['hello\n'])
761
        wb.add_lines('v2', ['v1'], ['hello\n', 'world\n'])
1393.1.66 by Martin Pool
- fix join of weaves where parents occur at different offsets
762
        wa.join(wb)
763
        eq = self.assertEquals
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
764
        eq(sorted(wa.versions()), ['v1', 'v2', 'v3', 'x1',])
1393.1.66 by Martin Pool
- fix join of weaves where parents occur at different offsets
765
        eq(wa.get_text('x1'), 'line from x1\n')
1185.50.23 by John Arbash Meinel
Adding sha1 check when weave extracts a text.
766
767
    def test_written_detection(self):
1185.50.29 by John Arbash Meinel
Whitespace and other formatting cleanups suggested by Robert.
768
        # Test detection of weave file corruption.
769
        #
770
        # Make sure that we can detect if a weave file has
771
        # been corrupted. This doesn't test all forms of corruption,
772
        # but it at least helps verify the data you get, is what you want.
1185.50.23 by John Arbash Meinel
Adding sha1 check when weave extracts a text.
773
        from cStringIO import StringIO
774
775
        w = Weave()
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
776
        w.add_lines('v1', [], ['hello\n'])
777
        w.add_lines('v2', ['v1'], ['hello\n', 'there\n'])
1185.50.23 by John Arbash Meinel
Adding sha1 check when weave extracts a text.
778
779
        tmpf = StringIO()
780
        write_weave(w, tmpf)
781
782
        # Because we are corrupting, we need to make sure we have the exact text
783
        self.assertEquals('# bzr weave file v5\n'
784
                          'i\n1 f572d396fae9206628714fb2ce00f72e94f2258f\nn v1\n\n'
785
                          'i 0\n1 90f265c6e75f1c8f9ab76dcf85528352c5f215ef\nn v2\n\n'
786
                          'w\n{ 0\n. hello\n}\n{ 1\n. there\n}\nW\n',
787
                          tmpf.getvalue())
788
789
        # Change a single letter
790
        tmpf = StringIO('# bzr weave file v5\n'
791
                        'i\n1 f572d396fae9206628714fb2ce00f72e94f2258f\nn v1\n\n'
792
                        'i 0\n1 90f265c6e75f1c8f9ab76dcf85528352c5f215ef\nn v2\n\n'
793
                        'w\n{ 0\n. hello\n}\n{ 1\n. There\n}\nW\n')
794
795
        w = read_weave(tmpf)
796
797
        self.assertEqual('hello\n', w.get_text('v1'))
798
        self.assertRaises(errors.WeaveInvalidChecksum, w.get_text, 'v2')
799
        self.assertRaises(errors.WeaveInvalidChecksum, w.get_lines, 'v2')
1185.50.26 by John Arbash Meinel
Change Weave.check() so that it checks all revisions in parallel.
800
        self.assertRaises(errors.WeaveInvalidChecksum, w.check)
1185.50.23 by John Arbash Meinel
Adding sha1 check when weave extracts a text.
801
802
        # Change the sha checksum
803
        tmpf = StringIO('# bzr weave file v5\n'
804
                        'i\n1 f572d396fae9206628714fb2ce00f72e94f2258f\nn v1\n\n'
805
                        'i 0\n1 f0f265c6e75f1c8f9ab76dcf85528352c5f215ef\nn v2\n\n'
806
                        'w\n{ 0\n. hello\n}\n{ 1\n. there\n}\nW\n')
807
808
        w = read_weave(tmpf)
809
810
        self.assertEqual('hello\n', w.get_text('v1'))
811
        self.assertRaises(errors.WeaveInvalidChecksum, w.get_text, 'v2')
812
        self.assertRaises(errors.WeaveInvalidChecksum, w.get_lines, 'v2')
1185.50.26 by John Arbash Meinel
Change Weave.check() so that it checks all revisions in parallel.
813
        self.assertRaises(errors.WeaveInvalidChecksum, w.check)
1185.50.23 by John Arbash Meinel
Adding sha1 check when weave extracts a text.
814
815
1551.3.11 by Aaron Bentley
Merge from Robert
816
class InstrumentedWeave(Weave):
817
    """Keep track of how many times functions are called."""
818
    
819
    def __init__(self, weave_name=None):
820
        self._extract_count = 0
821
        Weave.__init__(self, weave_name=weave_name)
822
823
    def _extract(self, versions):
824
        self._extract_count += 1
825
        return Weave._extract(self, versions)
826
827
828
class JoinOptimization(TestCase):
829
    """Test that Weave.join() doesn't extract all texts, only what must be done."""
830
831
    def test_join(self):
832
        w1 = InstrumentedWeave()
833
        w2 = InstrumentedWeave()
834
835
        txt0 = ['a\n']
836
        txt1 = ['a\n', 'b\n']
837
        txt2 = ['a\n', 'c\n']
838
        txt3 = ['a\n', 'b\n', 'c\n']
839
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
840
        w1.add_lines('txt0', [], txt0) # extract 1a
841
        w2.add_lines('txt0', [], txt0) # extract 1b
842
        w1.add_lines('txt1', ['txt0'], txt1)# extract 2a
843
        w2.add_lines('txt2', ['txt0'], txt2)# extract 2b
1551.3.11 by Aaron Bentley
Merge from Robert
844
        w1.join(w2) # extract 3a to add txt2 
845
        w2.join(w1) # extract 3b to add txt1 
846
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
847
        w1.add_lines('txt3', ['txt1', 'txt2'], txt3) # extract 4a 
848
        w2.add_lines('txt3', ['txt2', 'txt1'], txt3) # extract 4b
1551.3.11 by Aaron Bentley
Merge from Robert
849
        # These secretly have inverted parents
850
851
        # This should not have to do any extractions
852
        w1.join(w2) # NO extract, texts already present with same parents
853
        w2.join(w1) # NO extract, texts already present with same parents
854
855
        self.assertEqual(4, w1._extract_count)
856
        self.assertEqual(4, w2._extract_count)
857
858
    def test_double_parent(self):
859
        # It should not be considered illegal to add
860
        # a revision with the same parent twice
861
        w1 = InstrumentedWeave()
862
        w2 = InstrumentedWeave()
863
864
        txt0 = ['a\n']
865
        txt1 = ['a\n', 'b\n']
866
        txt2 = ['a\n', 'c\n']
867
        txt3 = ['a\n', 'b\n', 'c\n']
868
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
869
        w1.add_lines('txt0', [], txt0)
870
        w2.add_lines('txt0', [], txt0)
871
        w1.add_lines('txt1', ['txt0'], txt1)
872
        w2.add_lines('txt1', ['txt0', 'txt0'], txt1)
1551.3.11 by Aaron Bentley
Merge from Robert
873
        # Same text, effectively the same, because the
874
        # parent is only repeated
875
        w1.join(w2) # extract 3a to add txt2 
876
        w2.join(w1) # extract 3b to add txt1 
877
878
1616.1.18 by Martin Pool
(weave-merge) don't treat killed-both lines as points of agreement;
879
class TestNeedsReweave(TestCase):
1563.2.24 by Robert Collins
Make join cheaper for compatibly inconsistent parents.
880
    """Internal corner cases for when reweave is needed."""
881
882
    def test_compatible_parents(self):
883
        w1 = Weave('a')
884
        my_parents = set([1, 2, 3])
885
        # subsets are ok
886
        self.assertTrue(w1._compatible_parents(my_parents, set([3])))
887
        # same sets
888
        self.assertTrue(w1._compatible_parents(my_parents, set(my_parents)))
889
        # same empty corner case
890
        self.assertTrue(w1._compatible_parents(set(), set()))
891
        # other cannot contain stuff my_parents does not
892
        self.assertFalse(w1._compatible_parents(set(), set([1])))
893
        self.assertFalse(w1._compatible_parents(my_parents, set([1, 2, 3, 4])))
894
        self.assertFalse(w1._compatible_parents(my_parents, set([4])))
2024.1.1 by John Arbash Meinel
When a weave file is empty, we should get WeaveFormatError, not StopIteration
895
896
897
class TestWeaveFile(TestCaseInTempDir):
898
    
899
    def test_empty_file(self):
900
        f = open('empty.weave', 'wb+')
901
        try:
902
            self.assertRaises(errors.WeaveFormatError,
903
                              read_weave, f)
904
        finally:
905
            f.close()