/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
0.1.55 by Martin Pool
doc
1
#! /usr/bin/python2.4
2
0.1.2 by Martin Pool
Import testsweet module adapted from bzr.
3
# Copyright (C) 2005 by Canonical Ltd
4
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.
9
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.
14
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
1185.13.4 by Robert Collins
make reweave visible as a weave method, and quickly integrate into fetch
28
import bzrlib.errors as errors
1393.1.68 by Martin Pool
- add reweave that joins with ghosts
29
from bzrlib.weave import Weave, WeaveFormatError, WeaveError, reweave
872 by Martin Pool
- update testweave
30
from bzrlib.weavefile import write_weave, read_weave
1185.31.25 by John Arbash Meinel
Renamed all of the tests from selftest/foo.py to tests/test_foo.py
31
from bzrlib.tests import TestCase
1323 by Martin Pool
- caller can pass SHA-1 to Weave.add for efficiency
32
from bzrlib.osutils import sha_string
0.1.66 by Martin Pool
Cope without set/frozenset classes
33
34
0.1.2 by Martin Pool
Import testsweet module adapted from bzr.
35
# texts for use in testing
0.1.3 by Martin Pool
Change storage of texts for testing
36
TEXT_0 = ["Hello world"]
37
TEXT_1 = ["Hello world",
38
          "A second line"]
0.1.2 by Martin Pool
Import testsweet module adapted from bzr.
39
40
1233 by Martin Pool
- fix up weave tests for new test framework
41
class TestBase(TestCase):
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
42
    def check_read_write(self, k):
43
        """Check the weave k can be written & re-read."""
44
        from tempfile import TemporaryFile
45
        tf = TemporaryFile()
46
47
        write_weave(k, tf)
48
        tf.seek(0)
49
        k2 = read_weave(tf)
50
51
        if k != k2:
52
            tf.seek(0)
53
            self.log('serialized weave:')
54
            self.log(tf.read())
1083 by Martin Pool
- add space to store revision-id in weave files
55
56
            self.log('')
57
            self.log('parents: %s' % (k._parents == k2._parents))
58
            self.log('         %r' % k._parents)
59
            self.log('         %r' % k2._parents)
60
            self.log('')
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
61
            self.fail('read/write check failed')
1185.16.125 by Martin Pool
Test for 'name in weave'
62
63
64
class WeaveContains(TestBase):
65
    """Weave __contains__ operator"""
66
    def runTest(self):
67
        k = Weave()
68
        self.assertFalse('foo' in k)
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
69
        k.add_lines('foo', [], TEXT_1)
1185.16.125 by Martin Pool
Test for 'name in weave'
70
        self.assertTrue('foo' in k)
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
71
72
0.1.2 by Martin Pool
Import testsweet module adapted from bzr.
73
class Easy(TestBase):
74
    def runTest(self):
0.1.38 by Martin Pool
Rename knit to weave. (I don't think there's an existing module called weave.)
75
        k = Weave()
0.1.2 by Martin Pool
Import testsweet module adapted from bzr.
76
77
78
class StoreText(TestBase):
79
    """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.
80
81
    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.)
82
        k = Weave()
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
83
        idx = k.add_lines('text0', [], TEXT_0)
84
        self.assertEqual(k.get_lines(idx), TEXT_0)
0.1.4 by Martin Pool
Start indexing knits by both integer and version string.
85
        self.assertEqual(idx, 0)
0.1.2 by Martin Pool
Import testsweet module adapted from bzr.
86
87
0.1.7 by Martin Pool
Add trivial annotate text
88
class AnnotateOne(TestBase):
89
    def runTest(self):
0.1.38 by Martin Pool
Rename knit to weave. (I don't think there's an existing module called weave.)
90
        k = Weave()
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
91
        k.add_lines('text0', [], TEXT_0)
92
        self.assertEqual(k.annotate('text0'),
93
                         [('text0', TEXT_0[0])])
0.1.7 by Martin Pool
Add trivial annotate text
94
95
0.1.5 by Martin Pool
Add test for storing two text versions.
96
class StoreTwo(TestBase):
97
    def runTest(self):
0.1.38 by Martin Pool
Rename knit to weave. (I don't think there's an existing module called weave.)
98
        k = Weave()
0.1.5 by Martin Pool
Add test for storing two text versions.
99
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
100
        idx = k.add_lines('text0', [], TEXT_0)
0.1.5 by Martin Pool
Add test for storing two text versions.
101
        self.assertEqual(idx, 0)
102
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
103
        idx = k.add_lines('text1', [], TEXT_1)
0.1.5 by Martin Pool
Add test for storing two text versions.
104
        self.assertEqual(idx, 1)
105
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
106
        self.assertEqual(k.get_lines(0), TEXT_0)
107
        self.assertEqual(k.get_lines(1), TEXT_1)
1323 by Martin Pool
- caller can pass SHA-1 to Weave.add for efficiency
108
109
1185.50.28 by John Arbash Meinel
Lots of updates for 'bzr check'
110
class GetSha1(TestBase):
111
    def test_get_sha1(self):
112
        k = Weave()
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
113
        k.add_lines('text0', [], 'text0')
1185.50.28 by John Arbash Meinel
Lots of updates for 'bzr check'
114
        self.assertEqual('34dc0e430c642a26c3dd1c2beb7a8b4f4445eb79',
115
                         k.get_sha1('text0'))
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
116
        self.assertRaises(errors.RevisionNotPresent,
1185.50.28 by John Arbash Meinel
Lots of updates for 'bzr check'
117
                          k.get_sha1, 0)
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, 'text1')
120
                        
1323 by Martin Pool
- caller can pass SHA-1 to Weave.add for efficiency
121
0.1.27 by Martin Pool
Check that version numbers passed in are reasonable
122
class InvalidAdd(TestBase):
123
    """Try to use invalid version number during add."""
124
    def runTest(self):
0.1.38 by Martin Pool
Rename knit to weave. (I don't think there's an existing module called weave.)
125
        k = Weave()
0.1.27 by Martin Pool
Check that version numbers passed in are reasonable
126
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
127
        self.assertRaises(errors.RevisionNotPresent,
128
                          k.add_lines,
1083 by Martin Pool
- add space to store revision-id in weave files
129
                          'text0',
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
130
                          ['69'],
0.1.27 by Martin Pool
Check that version numbers passed in are reasonable
131
                          ['new text!'])
132
133
1237 by Martin Pool
- allow the same version to be repeatedly added to a weave
134
class RepeatedAdd(TestBase):
135
    """Add the same version twice; harmless."""
136
    def runTest(self):
137
        k = Weave()
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
138
        idx = k.add_lines('text0', [], TEXT_0)
139
        idx2 = k.add_lines('text0', [], TEXT_0)
1237 by Martin Pool
- allow the same version to be repeatedly added to a weave
140
        self.assertEqual(idx, idx2)
141
142
143
class InvalidRepeatedAdd(TestBase):
144
    def runTest(self):
145
        k = Weave()
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
146
        k.add_lines('basis', [], TEXT_0)
147
        idx = k.add_lines('text0', [], TEXT_0)
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
148
        self.assertRaises(errors.RevisionAlreadyPresent,
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
149
                          k.add_lines,
1237 by Martin Pool
- allow the same version to be repeatedly added to a weave
150
                          'text0',
151
                          [],
152
                          ['not the same text'])
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
153
        self.assertRaises(errors.RevisionAlreadyPresent,
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
154
                          k.add_lines,
1237 by Martin Pool
- allow the same version to be repeatedly added to a weave
155
                          'text0',
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
156
                          ['basis'],         # not the right parents
1237 by Martin Pool
- allow the same version to be repeatedly added to a weave
157
                          TEXT_0)
158
        
159
0.1.26 by Martin Pool
Refactor parameters to add command
160
class InsertLines(TestBase):
0.1.13 by Martin Pool
Knit structure now allows for versions to include the lines present in other
161
    """Store a revision that adds one line to the original.
162
163
    Look at the annotations to make sure that the first line is matched
164
    and not stored repeatedly."""
165
    def runTest(self):
0.1.38 by Martin Pool
Rename knit to weave. (I don't think there's an existing module called weave.)
166
        k = Weave()
0.1.13 by Martin Pool
Knit structure now allows for versions to include the lines present in other
167
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
168
        k.add_lines('text0', [], ['line 1'])
169
        k.add_lines('text1', ['text0'], ['line 1', 'line 2'])
170
171
        self.assertEqual(k.annotate('text0'),
172
                         [('text0', 'line 1')])
173
174
        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
175
                         ['line 1',
176
                          'line 2'])
177
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
178
        self.assertEqual(k.annotate('text1'),
179
                         [('text0', 'line 1'),
180
                          ('text1', 'line 2')])
181
182
        k.add_lines('text2', ['text0'], ['line 1', 'diverged line'])
183
184
        self.assertEqual(k.annotate('text2'),
185
                         [('text0', 'line 1'),
186
                          ('text2', 'diverged line')])
0.1.28 by Martin Pool
More tests for insertion of lines in new versions.
187
0.1.54 by Martin Pool
Fix weave line calculation when making deltas
188
        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.
189
        k.add_lines('text3',
190
              ['text0', 'text1'],
0.1.54 by Martin Pool
Fix weave line calculation when making deltas
191
              text3)
192
937 by Martin Pool
- weave raises IndexError when an invalid revision is given
193
        # 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
194
944 by Martin Pool
- refactor member names in Weave code
195
        self.log("k._weave=" + pformat(k._weave))
0.1.28 by Martin Pool
More tests for insertion of lines in new versions.
196
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
197
        self.assertEqual(k.annotate('text3'),
198
                         [('text0', 'line 1'),
199
                          ('text3', 'middle line'),
200
                          ('text1', 'line 2')])
0.1.28 by Martin Pool
More tests for insertion of lines in new versions.
201
0.1.31 by Martin Pool
Fix insertion of multiple regions, calculating the right line offset as we go.
202
        # 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.
203
        k.add_lines('text4',
204
              ['text0', 'text1', 'text3'],
0.1.31 by Martin Pool
Fix insertion of multiple regions, calculating the right line offset as we go.
205
              ['line 1', 'aaa', 'middle line', 'bbb', 'line 2', 'ccc'])
206
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
207
        self.assertEqual(k.annotate('text4'), 
208
                         [('text0', 'line 1'),
209
                          ('text4', 'aaa'),
210
                          ('text3', 'middle line'),
211
                          ('text4', 'bbb'),
212
                          ('text1', 'line 2'),
213
                          ('text4', 'ccc')])
0.1.13 by Martin Pool
Knit structure now allows for versions to include the lines present in other
214
0.1.40 by Martin Pool
Add test for extracting from weave with nested insertions
215
0.1.56 by Martin Pool
Handle deletion of lines by marking the region with a deletion
216
class DeleteLines(TestBase):
217
    """Deletion of lines from existing text.
218
219
    Try various texts all based on a common ancestor."""
220
    def runTest(self):
221
        k = Weave()
222
223
        base_text = ['one', 'two', 'three', 'four']
224
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
225
        k.add_lines('text0', [], base_text)
0.1.56 by Martin Pool
Handle deletion of lines by marking the region with a deletion
226
        
227
        texts = [['one', 'two', 'three'],
228
                 ['two', 'three', 'four'],
229
                 ['one', 'four'],
230
                 ['one', 'two', 'three', 'four'],
231
                 ]
232
1083 by Martin Pool
- add space to store revision-id in weave files
233
        i = 1
0.1.56 by Martin Pool
Handle deletion of lines by marking the region with a deletion
234
        for t in texts:
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
235
            ver = k.add_lines('text%d' % i,
236
                        ['text0'], t)
1083 by Martin Pool
- add space to store revision-id in weave files
237
            i += 1
0.1.56 by Martin Pool
Handle deletion of lines by marking the region with a deletion
238
239
        self.log('final weave:')
944 by Martin Pool
- refactor member names in Weave code
240
        self.log('k._weave=' + pformat(k._weave))
0.1.56 by Martin Pool
Handle deletion of lines by marking the region with a deletion
241
242
        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.
243
            self.assertEqual(k.get_lines(i+1),
0.1.56 by Martin Pool
Handle deletion of lines by marking the region with a deletion
244
                             texts[i])
245
246
0.1.49 by Martin Pool
Add another constraint: revisions should not delete text that they
247
class SuicideDelete(TestBase):
0.1.55 by Martin Pool
doc
248
    """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
249
    def runTest(self):
250
        k = Weave()
251
944 by Martin Pool
- refactor member names in Weave code
252
        k._parents = [(),
0.1.49 by Martin Pool
Add another constraint: revisions should not delete text that they
253
                ]
944 by Martin Pool
- refactor member names in Weave code
254
        k._weave = [('{', 0),
0.1.49 by Martin Pool
Add another constraint: revisions should not delete text that they
255
                'first line',
256
                ('[', 0),
257
                'deleted in 0',
258
                (']', 0),
259
                ('}', 0),
260
                ]
891 by Martin Pool
- fix up refactoring of weave
261
        ################################### SKIPPED
262
        # Weave.get doesn't trap this anymore
263
        return 
0.1.49 by Martin Pool
Add another constraint: revisions should not delete text that they
264
265
        self.assertRaises(WeaveFormatError,
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
266
                          k.get_lines,
0.1.49 by Martin Pool
Add another constraint: revisions should not delete text that they
267
                          0)        
268
269
0.1.48 by Martin Pool
Basic parsing of delete instructions.
270
class CannedDelete(TestBase):
271
    """Unpack canned weave with deleted lines."""
272
    def runTest(self):
273
        k = Weave()
274
944 by Martin Pool
- refactor member names in Weave code
275
        k._parents = [(),
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
276
                frozenset([0]),
0.1.48 by Martin Pool
Basic parsing of delete instructions.
277
                ]
944 by Martin Pool
- refactor member names in Weave code
278
        k._weave = [('{', 0),
0.1.48 by Martin Pool
Basic parsing of delete instructions.
279
                'first line',
280
                ('[', 1),
281
                'line to be deleted',
282
                (']', 1),
283
                'last line',
284
                ('}', 0),
285
                ]
1185.50.23 by John Arbash Meinel
Adding sha1 check when weave extracts a text.
286
        k._sha1s = [sha_string('first lineline to be deletedlast line')
287
                  , sha_string('first linelast line')]
0.1.48 by Martin Pool
Basic parsing of delete instructions.
288
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
289
        self.assertEqual(k.get_lines(0),
0.1.48 by Martin Pool
Basic parsing of delete instructions.
290
                         ['first line',
291
                          'line to be deleted',
292
                          'last line',
293
                          ])
294
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
295
        self.assertEqual(k.get_lines(1),
0.1.50 by Martin Pool
Basic implementation of deletion markers
296
                         ['first line',
297
                          'last line',
298
                          ])
299
0.1.48 by Martin Pool
Basic parsing of delete instructions.
300
0.1.51 by Martin Pool
Add test for replacement lines
301
class CannedReplacement(TestBase):
302
    """Unpack canned weave with deleted lines."""
303
    def runTest(self):
304
        k = Weave()
305
944 by Martin Pool
- refactor member names in Weave code
306
        k._parents = [frozenset(),
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
307
                frozenset([0]),
0.1.51 by Martin Pool
Add test for replacement lines
308
                ]
944 by Martin Pool
- refactor member names in Weave code
309
        k._weave = [('{', 0),
0.1.51 by Martin Pool
Add test for replacement lines
310
                'first line',
311
                ('[', 1),
312
                'line to be deleted',
313
                (']', 1),
314
                ('{', 1),
315
                'replacement line',                
316
                ('}', 1),
317
                'last line',
318
                ('}', 0),
319
                ]
1185.50.23 by John Arbash Meinel
Adding sha1 check when weave extracts a text.
320
        k._sha1s = [sha_string('first lineline to be deletedlast line')
321
                  , sha_string('first linereplacement linelast line')]
0.1.51 by Martin Pool
Add test for replacement lines
322
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
323
        self.assertEqual(k.get_lines(0),
0.1.51 by Martin Pool
Add test for replacement lines
324
                         ['first line',
325
                          'line to be deleted',
326
                          'last line',
327
                          ])
328
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
329
        self.assertEqual(k.get_lines(1),
0.1.51 by Martin Pool
Add test for replacement lines
330
                         ['first line',
331
                          'replacement line',
332
                          'last line',
333
                          ])
334
335
0.1.46 by Martin Pool
More constraints on structure of weave, and checks that they work
336
class BadWeave(TestBase):
337
    """Test that we trap an insert which should not occur."""
338
    def runTest(self):
339
        k = Weave()
340
944 by Martin Pool
- refactor member names in Weave code
341
        k._parents = [frozenset(),
0.1.46 by Martin Pool
More constraints on structure of weave, and checks that they work
342
                ]
944 by Martin Pool
- refactor member names in Weave code
343
        k._weave = ['bad line',
0.1.46 by Martin Pool
More constraints on structure of weave, and checks that they work
344
                ('{', 0),
345
                'foo {',
346
                ('{', 1),
347
                '  added in version 1',
348
                ('{', 2),
349
                '  added in v2',
350
                ('}', 2),
351
                '  also from v1',
352
                ('}', 1),
353
                '}',
354
                ('}', 0)]
355
891 by Martin Pool
- fix up refactoring of weave
356
        ################################### SKIPPED
357
        # Weave.get doesn't trap this anymore
358
        return 
359
360
0.1.47 by Martin Pool
New WeaveError and WeaveFormatError rather than assertions.
361
        self.assertRaises(WeaveFormatError,
0.1.46 by Martin Pool
More constraints on structure of weave, and checks that they work
362
                          k.get,
363
                          0)
364
365
366
class BadInsert(TestBase):
367
    """Test that we trap an insert which should not occur."""
368
    def runTest(self):
369
        k = Weave()
370
944 by Martin Pool
- refactor member names in Weave code
371
        k._parents = [frozenset(),
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
372
                frozenset([0]),
373
                frozenset([0]),
374
                frozenset([0,1,2]),
0.1.46 by Martin Pool
More constraints on structure of weave, and checks that they work
375
                ]
944 by Martin Pool
- refactor member names in Weave code
376
        k._weave = [('{', 0),
0.1.46 by Martin Pool
More constraints on structure of weave, and checks that they work
377
                'foo {',
378
                ('{', 1),
379
                '  added in version 1',
380
                ('{', 1),
381
                '  more in 1',
382
                ('}', 1),
383
                ('}', 1),
384
                ('}', 0)]
385
891 by Martin Pool
- fix up refactoring of weave
386
387
        # this is not currently enforced by get
388
        return  ##########################################
389
0.1.47 by Martin Pool
New WeaveError and WeaveFormatError rather than assertions.
390
        self.assertRaises(WeaveFormatError,
0.1.46 by Martin Pool
More constraints on structure of weave, and checks that they work
391
                          k.get,
392
                          0)
393
0.1.47 by Martin Pool
New WeaveError and WeaveFormatError rather than assertions.
394
        self.assertRaises(WeaveFormatError,
0.1.46 by Martin Pool
More constraints on structure of weave, and checks that they work
395
                          k.get,
396
                          1)
397
0.1.40 by Martin Pool
Add test for extracting from weave with nested insertions
398
399
class InsertNested(TestBase):
400
    """Insertion with nested instructions."""
401
    def runTest(self):
402
        k = Weave()
403
944 by Martin Pool
- refactor member names in Weave code
404
        k._parents = [frozenset(),
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
405
                frozenset([0]),
406
                frozenset([0]),
407
                frozenset([0,1,2]),
0.1.40 by Martin Pool
Add test for extracting from weave with nested insertions
408
                ]
944 by Martin Pool
- refactor member names in Weave code
409
        k._weave = [('{', 0),
0.1.40 by Martin Pool
Add test for extracting from weave with nested insertions
410
                'foo {',
411
                ('{', 1),
412
                '  added in version 1',
0.1.42 by Martin Pool
More tests for nested insert instructions
413
                ('{', 2),
414
                '  added in v2',
415
                ('}', 2),
416
                '  also from v1',
0.1.40 by Martin Pool
Add test for extracting from weave with nested insertions
417
                ('}', 1),
418
                '}',
419
                ('}', 0)]
420
1185.50.23 by John Arbash Meinel
Adding sha1 check when weave extracts a text.
421
        k._sha1s = [sha_string('foo {}')
422
                  , sha_string('foo {  added in version 1  also from v1}')
423
                  , sha_string('foo {  added in v2}')
424
                  , sha_string('foo {  added in version 1  added in v2  also from v1}')
425
                  ]
426
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
427
        self.assertEqual(k.get_lines(0),
0.1.40 by Martin Pool
Add test for extracting from weave with nested insertions
428
                         ['foo {',
429
                          '}'])
430
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
431
        self.assertEqual(k.get_lines(1),
0.1.40 by Martin Pool
Add test for extracting from weave with nested insertions
432
                         ['foo {',
433
                          '  added in version 1',
0.1.42 by Martin Pool
More tests for nested insert instructions
434
                          '  also from v1',
0.1.40 by Martin Pool
Add test for extracting from weave with nested insertions
435
                          '}'])
436
                       
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
437
        self.assertEqual(k.get_lines(2),
0.1.44 by Martin Pool
More tests for nested insert instructions
438
                         ['foo {',
439
                          '  added in v2',
440
                          '}'])
441
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
442
        self.assertEqual(k.get_lines(3),
0.1.44 by Martin Pool
More tests for nested insert instructions
443
                         ['foo {',
444
                          '  added in version 1',
445
                          '  added in v2',
446
                          '  also from v1',
447
                          '}'])
448
                         
0.1.45 by Martin Pool
doc
449
0.1.56 by Martin Pool
Handle deletion of lines by marking the region with a deletion
450
class DeleteLines2(TestBase):
0.1.30 by Martin Pool
Start adding tests for line deletion
451
    """Test recording revisions that delete lines.
452
453
    This relies on the weave having a way to represent lines knocked
454
    out by a later revision."""
455
    def runTest(self):
0.1.38 by Martin Pool
Rename knit to weave. (I don't think there's an existing module called weave.)
456
        k = Weave()
0.1.30 by Martin Pool
Start adding tests for line deletion
457
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
458
        k.add_lines('text0', [], ["line the first",
0.1.30 by Martin Pool
Start adding tests for line deletion
459
                   "line 2",
460
                   "line 3",
461
                   "fine"])
462
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
463
        self.assertEqual(len(k.get_lines(0)), 4)
0.1.30 by Martin Pool
Start adding tests for line deletion
464
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
465
        k.add_lines('text1', ['text0'], ["line the first",
0.1.30 by Martin Pool
Start adding tests for line deletion
466
                   "fine"])
467
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
468
        self.assertEqual(k.get_lines(1),
0.1.30 by Martin Pool
Start adding tests for line deletion
469
                         ["line the first",
470
                          "fine"])
471
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
472
        self.assertEqual(k.annotate('text1'),
473
                         [('text0', "line the first"),
474
                          ('text0', "fine")])
0.1.56 by Martin Pool
Handle deletion of lines by marking the region with a deletion
475
0.1.30 by Martin Pool
Start adding tests for line deletion
476
0.1.13 by Martin Pool
Knit structure now allows for versions to include the lines present in other
477
class IncludeVersions(TestBase):
478
    """Check texts that are stored across multiple revisions.
479
0.1.38 by Martin Pool
Rename knit to weave. (I don't think there's an existing module called weave.)
480
    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
481
    sure it unpacks properly.
482
483
    Text 0 includes nothing; text 1 includes text 0 and adds some
484
    lines.
485
    """
486
487
    def runTest(self):
0.1.38 by Martin Pool
Rename knit to weave. (I don't think there's an existing module called weave.)
488
        k = Weave()
0.1.13 by Martin Pool
Knit structure now allows for versions to include the lines present in other
489
944 by Martin Pool
- refactor member names in Weave code
490
        k._parents = [frozenset(), frozenset([0])]
491
        k._weave = [('{', 0),
0.1.39 by Martin Pool
Change to a more realistic weave structure which can represent insertions and
492
                "first line",
493
                ('}', 0),
494
                ('{', 1),
495
                "second line",
496
                ('}', 1)]
0.1.13 by Martin Pool
Knit structure now allows for versions to include the lines present in other
497
1185.50.23 by John Arbash Meinel
Adding sha1 check when weave extracts a text.
498
        k._sha1s = [sha_string('first line')
499
                  , sha_string('first linesecond line')]
500
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
501
        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
502
                         ["first line",
503
                          "second line"])
504
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
505
        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
506
                         ["first line"])
507
0.1.5 by Martin Pool
Add test for storing two text versions.
508
0.1.14 by Martin Pool
Another test for version inclusion
509
class DivergedIncludes(TestBase):
0.1.38 by Martin Pool
Rename knit to weave. (I don't think there's an existing module called weave.)
510
    """Weave with two diverged texts based on version 0.
0.1.14 by Martin Pool
Another test for version inclusion
511
    """
512
    def runTest(self):
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
513
        # 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.)
514
        k = Weave()
0.1.14 by Martin Pool
Another test for version inclusion
515
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
516
        k._names = ['0', '1', '2']
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
517
        k._name_map = {'0':0, '1':1, '2':2}
944 by Martin Pool
- refactor member names in Weave code
518
        k._parents = [frozenset(),
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
519
                frozenset([0]),
520
                frozenset([0]),
0.1.17 by Martin Pool
Use objects rather than tuples for tracking VerInfo for
521
                ]
944 by Martin Pool
- refactor member names in Weave code
522
        k._weave = [('{', 0),
0.1.39 by Martin Pool
Change to a more realistic weave structure which can represent insertions and
523
                "first line",
524
                ('}', 0),
525
                ('{', 1),
526
                "second line",
527
                ('}', 1),
528
                ('{', 2),
529
                "alternative second line",
530
                ('}', 2),                
531
                ]
0.1.14 by Martin Pool
Another test for version inclusion
532
1185.50.23 by John Arbash Meinel
Adding sha1 check when weave extracts a text.
533
        k._sha1s = [sha_string('first line')
534
                  , sha_string('first linesecond line')
535
                  , sha_string('first linealternative second line')]
536
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
537
        self.assertEqual(k.get_lines(0),
0.1.14 by Martin Pool
Another test for version inclusion
538
                         ["first line"])
539
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
540
        self.assertEqual(k.get_lines(1),
0.1.14 by Martin Pool
Another test for version inclusion
541
                         ["first line",
542
                          "second line"])
543
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
544
        self.assertEqual(k.get_lines('2'),
0.1.14 by Martin Pool
Another test for version inclusion
545
                         ["first line",
546
                          "alternative second line"])
547
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
548
        self.assertEqual(list(k.get_ancestry(['2'])),
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
549
                         ['0', '2'])
0.1.77 by Martin Pool
New Weave.get_included() does transitive expansion
550
0.1.57 by Martin Pool
Fix bug in an update edit that both deletes and inserts -- previously
551
552
class ReplaceLine(TestBase):
553
    def runTest(self):
554
        k = Weave()
555
556
        text0 = ['cheddar', 'stilton', 'gruyere']
557
        text1 = ['cheddar', 'blue vein', 'neufchatel', 'chevre']
558
        
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
559
        k.add_lines('text0', [], text0)
560
        k.add_lines('text1', ['text0'], text1)
0.1.57 by Martin Pool
Fix bug in an update edit that both deletes and inserts -- previously
561
944 by Martin Pool
- refactor member names in Weave code
562
        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
563
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
564
        self.assertEqual(k.get_lines(0), text0)
565
        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
566
0.1.64 by Martin Pool
Add test for merging versions
567
568
class Merge(TestBase):
0.1.95 by Martin Pool
- preliminary merge conflict detection
569
    """Storage of versions that merge diverged parents"""
0.1.64 by Martin Pool
Add test for merging versions
570
    def runTest(self):
571
        k = Weave()
572
573
        texts = [['header'],
574
                 ['header', '', 'line from 1'],
575
                 ['header', '', 'line from 2', 'more from 2'],
576
                 ['header', '', 'line from 1', 'fixup line', 'line from 2'],
577
                 ]
578
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
579
        k.add_lines('text0', [], texts[0])
580
        k.add_lines('text1', ['text0'], texts[1])
581
        k.add_lines('text2', ['text0'], texts[2])
582
        k.add_lines('merge', ['text0', 'text1', 'text2'], texts[3])
0.1.64 by Martin Pool
Add test for merging versions
583
584
        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.
585
            self.assertEqual(k.get_lines(i), t)
0.1.64 by Martin Pool
Add test for merging versions
586
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
587
        self.assertEqual(k.annotate('merge'),
588
                         [('text0', 'header'),
589
                          ('text1', ''),
590
                          ('text1', 'line from 1'),
591
                          ('merge', 'fixup line'),
592
                          ('text2', 'line from 2'),
0.1.64 by Martin Pool
Add test for merging versions
593
                          ])
594
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
595
        self.assertEqual(list(k.get_ancestry(['merge'])),
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
596
                         ['text0', 'text1', 'text2', 'merge'])
0.1.77 by Martin Pool
New Weave.get_included() does transitive expansion
597
944 by Martin Pool
- refactor member names in Weave code
598
        self.log('k._weave=' + pformat(k._weave))
0.1.64 by Martin Pool
Add test for merging versions
599
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
600
        self.check_read_write(k)
0.1.65 by Martin Pool
Add Weave.merge_iter to get automerged lines
601
602
0.1.95 by Martin Pool
- preliminary merge conflict detection
603
class Conflicts(TestBase):
604
    """Test detection of conflicting regions during a merge.
605
606
    A base version is inserted, then two descendents try to
607
    insert different lines in the same place.  These should be
608
    reported as a possible conflict and forwarded to the user."""
609
    def runTest(self):
610
        return  # NOT RUN
611
        k = Weave()
612
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
613
        k.add_lines([], ['aaa', 'bbb'])
614
        k.add_lines([0], ['aaa', '111', 'bbb'])
615
        k.add_lines([1], ['aaa', '222', 'bbb'])
0.1.95 by Martin Pool
- preliminary merge conflict detection
616
617
        merged = k.merge([1, 2])
618
619
        self.assertEquals([[['aaa']],
620
                           [['111'], ['222']],
621
                           [['bbb']]])
622
623
624
class NonConflict(TestBase):
625
    """Two descendants insert compatible changes.
626
627
    No conflict should be reported."""
628
    def runTest(self):
629
        return  # NOT RUN
630
        k = Weave()
631
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
632
        k.add_lines([], ['aaa', 'bbb'])
633
        k.add_lines([0], ['111', 'aaa', 'ccc', 'bbb'])
634
        k.add_lines([1], ['aaa', 'ccc', 'bbb', '222'])
0.1.95 by Martin Pool
- preliminary merge conflict detection
635
636
0.1.57 by Martin Pool
Fix bug in an update edit that both deletes and inserts -- previously
637
class Khayyam(TestBase):
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
638
    """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.
639
640
    def test_multi_line_merge(self):
0.1.57 by Martin Pool
Fix bug in an update edit that both deletes and inserts -- previously
641
        rawtexts = [
642
            """A Book of Verses underneath the Bough,
643
            A Jug of Wine, a Loaf of Bread, -- and Thou
644
            Beside me singing in the Wilderness --
645
            Oh, Wilderness were Paradise enow!""",
646
            
647
            """A Book of Verses underneath the Bough,
648
            A Jug of Wine, a Loaf of Bread, -- and Thou
649
            Beside me singing in the Wilderness --
650
            Oh, Wilderness were Paradise now!""",
0.1.59 by Martin Pool
More modification tests
651
652
            """A Book of poems underneath the tree,
653
            A Jug of Wine, a Loaf of Bread,
654
            and Thou
655
            Beside me singing in the Wilderness --
656
            Oh, Wilderness were Paradise now!
657
658
            -- O. Khayyam""",
659
660
            """A Book of Verses underneath the Bough,
661
            A Jug of Wine, a Loaf of Bread,
662
            and Thou
663
            Beside me singing in the Wilderness --
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
664
            Oh, Wilderness were Paradise now!""",
0.1.57 by Martin Pool
Fix bug in an update edit that both deletes and inserts -- previously
665
            ]
666
        texts = [[l.strip() for l in t.split('\n')] for t in rawtexts]
667
668
        k = Weave()
669
        parents = set()
1083 by Martin Pool
- add space to store revision-id in weave files
670
        i = 0
0.1.57 by Martin Pool
Fix bug in an update edit that both deletes and inserts -- previously
671
        for t in texts:
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
672
            ver = k.add_lines('text%d' % i,
1083 by Martin Pool
- add space to store revision-id in weave files
673
                        list(parents), t)
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
674
            parents.add('text%d' % i)
1083 by Martin Pool
- add space to store revision-id in weave files
675
            i += 1
0.1.57 by Martin Pool
Fix bug in an update edit that both deletes and inserts -- previously
676
944 by Martin Pool
- refactor member names in Weave code
677
        self.log("k._weave=" + pformat(k._weave))
0.1.59 by Martin Pool
More modification tests
678
0.1.57 by Martin Pool
Fix bug in an update edit that both deletes and inserts -- previously
679
        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.
680
            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
681
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
682
        self.check_read_write(k)
0.1.57 by Martin Pool
Fix bug in an update edit that both deletes and inserts -- previously
683
684
920 by Martin Pool
- add more test cases for weave_merge
685
class MergeCases(TestBase):
686
    def doMerge(self, base, a, b, mp):
687
        from cStringIO import StringIO
688
        from textwrap import dedent
689
690
        def addcrlf(x):
691
            return x + '\n'
692
        
693
        w = Weave()
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
694
        w.add_lines('text0', [], map(addcrlf, base))
695
        w.add_lines('text1', ['text0'], map(addcrlf, a))
696
        w.add_lines('text2', ['text0'], map(addcrlf, b))
920 by Martin Pool
- add more test cases for weave_merge
697
935 by Martin Pool
- log weave for merge tests to help debugging
698
        self.log('weave is:')
699
        tmpf = StringIO()
700
        write_weave(w, tmpf)
701
        self.log(tmpf.getvalue())
702
920 by Martin Pool
- add more test cases for weave_merge
703
        self.log('merge plan:')
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
704
        p = list(w.plan_merge('text1', 'text2'))
920 by Martin Pool
- add more test cases for weave_merge
705
        for state, line in p:
706
            if line:
707
                self.log('%12s | %s' % (state, line[:-1]))
708
709
        self.log('merge:')
710
        mt = StringIO()
711
        mt.writelines(w.weave_merge(p))
712
        mt.seek(0)
713
        self.log(mt.getvalue())
714
715
        mp = map(addcrlf, mp)
716
        self.assertEqual(mt.readlines(), mp)
717
        
718
        
719
    def testOneInsert(self):
720
        self.doMerge([],
721
                     ['aa'],
722
                     [],
723
                     ['aa'])
724
725
    def testSeparateInserts(self):
726
        self.doMerge(['aaa', 'bbb', 'ccc'],
727
                     ['aaa', 'xxx', 'bbb', 'ccc'],
728
                     ['aaa', 'bbb', 'yyy', 'ccc'],
729
                     ['aaa', 'xxx', 'bbb', 'yyy', 'ccc'])
730
731
    def testSameInsert(self):
732
        self.doMerge(['aaa', 'bbb', 'ccc'],
733
                     ['aaa', 'xxx', 'bbb', 'ccc'],
734
                     ['aaa', 'xxx', 'bbb', 'yyy', 'ccc'],
735
                     ['aaa', 'xxx', 'bbb', 'yyy', 'ccc'])
736
737
    def testOverlappedInsert(self):
738
        self.doMerge(['aaa', 'bbb'],
739
                     ['aaa', 'xxx', 'yyy', 'bbb'],
740
                     ['aaa', 'xxx', 'bbb'],
1534.7.186 by Aaron Bentley
Made weave conflict markers customizable, standardized defaults
741
                     ['aaa', '<<<<<<< ', 'xxx', 'yyy', '=======', 'xxx', 
742
                      '>>>>>>> ', 'bbb'])
920 by Martin Pool
- add more test cases for weave_merge
743
744
        # really it ought to reduce this to 
745
        # ['aaa', 'xxx', 'yyy', 'bbb']
746
747
748
    def testClashReplace(self):
749
        self.doMerge(['aaa'],
750
                     ['xxx'],
751
                     ['yyy', 'zzz'],
1534.7.186 by Aaron Bentley
Made weave conflict markers customizable, standardized defaults
752
                     ['<<<<<<< ', 'xxx', '=======', 'yyy', 'zzz', 
753
                      '>>>>>>> '])
920 by Martin Pool
- add more test cases for weave_merge
754
755
    def testNonClashInsert(self):
756
        self.doMerge(['aaa'],
757
                     ['xxx', 'aaa'],
758
                     ['yyy', 'zzz'],
1534.7.186 by Aaron Bentley
Made weave conflict markers customizable, standardized defaults
759
                     ['<<<<<<< ', 'xxx', 'aaa', '=======', 'yyy', 'zzz', 
760
                      '>>>>>>> '])
920 by Martin Pool
- add more test cases for weave_merge
761
762
        self.doMerge(['aaa'],
763
                     ['aaa'],
764
                     ['yyy', 'zzz'],
765
                     ['yyy', 'zzz'])
945 by Martin Pool
- add stubbed-out test for clashing replace and delete
766
767
768
    def testDeleteAndModify(self):
769
        """Clashing delete and modification.
770
771
        If one side modifies a region and the other deletes it then
772
        there should be a conflict with one side blank.
773
        """
774
775
        #######################################
776
        # skippd, not working yet
777
        return
778
        
779
        self.doMerge(['aaa', 'bbb', 'ccc'],
780
                     ['aaa', 'ddd', 'ccc'],
781
                     ['aaa', 'ccc'],
1534.7.186 by Aaron Bentley
Made weave conflict markers customizable, standardized defaults
782
                     ['<<<<<<<< ', 'aaa', '=======', '>>>>>>> ', 'ccc'])
1393.1.48 by Martin Pool
- Add stub Weave.join() method
783
1616.1.18 by Martin Pool
(weave-merge) don't treat killed-both lines as points of agreement;
784
    def _test_merge_from_strings(self, base, a, b, expected):
785
        w = Weave()
786
        w.add_lines('text0', [], base.splitlines(True))
787
        w.add_lines('text1', ['text0'], a.splitlines(True))
788
        w.add_lines('text2', ['text0'], b.splitlines(True))
789
        self.log('merge plan:')
790
        p = list(w.plan_merge('text1', 'text2'))
791
        for state, line in p:
792
            if line:
793
                self.log('%12s | %s' % (state, line[:-1]))
794
        self.log('merge result:')
795
        result_text = ''.join(w.weave_merge(p))
796
        self.log(result_text)
797
        self.assertEqualDiff(result_text, expected)
798
799
    def test_deletion_extended(self):
800
        """One side deletes, the other deletes more.
801
        """
802
        base = """\
803
            line 1
804
            line 2
805
            line 3
806
            """
807
        a = """\
808
            line 1
809
            line 2
810
            """
811
        b = """\
812
            line 1
813
            """
814
        result = """\
815
            line 1
816
            """
817
        self._test_merge_from_strings(base, a, b, result)
818
819
    def test_deletion_overlap(self):
820
        """Delete overlapping regions with no other conflict.
821
822
        Arguably it'd be better to treat these as agreement, rather than 
823
        conflict, but for now conflict is safer.
824
        """
825
        base = """\
826
            start context
827
            int a() {}
828
            int b() {}
829
            int c() {}
830
            end context
831
            """
832
        a = """\
833
            start context
834
            int a() {}
835
            end context
836
            """
837
        b = """\
838
            start context
839
            int c() {}
840
            end context
841
            """
842
        result = """\
843
            start context
844
<<<<<<< 
845
            int a() {}
846
=======
847
            int c() {}
848
>>>>>>> 
849
            end context
850
            """
851
        self._test_merge_from_strings(base, a, b, result)
852
853
    def test_agreement_deletion(self):
854
        """Agree to delete some lines, without conflicts."""
855
        base = """\
856
            start context
857
            base line 1
858
            base line 2
859
            end context
860
            """
861
        a = """\
862
            start context
863
            base line 1
864
            end context
865
            """
866
        b = """\
867
            start context
868
            base line 1
869
            end context
870
            """
871
        result = """\
872
            start context
873
            base line 1
874
            end context
875
            """
876
        self._test_merge_from_strings(base, a, b, result)
877
878
    def test_sync_on_deletion(self):
879
        """Specific case of merge where we can synchronize incorrectly.
880
        
881
        A previous version of the weave merge concluded that the two versions
882
        agreed on deleting line 2, and this could be a synchronization point.
883
        Line 1 was then considered in isolation, and thought to be deleted on 
884
        both sides.
885
886
        It's better to consider the whole thing as a disagreement region.
887
        """
888
        base = """\
889
            start context
890
            base line 1
891
            base line 2
892
            end context
893
            """
894
        a = """\
895
            start context
896
            base line 1
897
            a's replacement line 2
898
            end context
899
            """
900
        b = """\
901
            start context
902
            b replaces
903
            both lines
904
            end context
905
            """
906
        result = """\
907
            start context
908
<<<<<<< 
909
            base line 1
910
            a's replacement line 2
911
=======
912
            b replaces
913
            both lines
914
>>>>>>> 
915
            end context
916
            """
917
        self._test_merge_from_strings(base, a, b, result)
918
1393.1.48 by Martin Pool
- Add stub Weave.join() method
919
920
class JoinWeavesTests(TestBase):
1393.1.50 by Martin Pool
- more development of Weave.join()
921
    def setUp(self):
922
        super(JoinWeavesTests, self).setUp()
923
        self.weave1 = Weave()
924
        self.lines1 = ['hello\n']
925
        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.
926
        self.weave1.add_lines('v1', [], self.lines1)
927
        self.weave1.add_lines('v2', ['v1'], ['hello\n', 'world\n'])
928
        self.weave1.add_lines('v3', ['v2'], self.lines3)
1393.1.50 by Martin Pool
- more development of Weave.join()
929
        
1393.1.48 by Martin Pool
- Add stub Weave.join() method
930
    def test_join_empty(self):
931
        """Join two empty weaves."""
932
        eq = self.assertEqual
933
        w1 = Weave()
934
        w2 = Weave()
935
        w1.join(w2)
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
936
        eq(len(w1), 0)
1393.1.48 by Martin Pool
- Add stub Weave.join() method
937
        
1393.1.50 by Martin Pool
- more development of Weave.join()
938
    def test_join_empty_to_nonempty(self):
939
        """Join empty weave onto nonempty."""
940
        self.weave1.join(Weave())
941
        self.assertEqual(len(self.weave1), 3)
942
943
    def test_join_unrelated(self):
944
        """Join two weaves with no history in common."""
945
        wb = Weave()
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
946
        wb.add_lines('b1', [], ['line from b\n'])
1393.1.50 by Martin Pool
- more development of Weave.join()
947
        w1 = self.weave1
948
        w1.join(wb)
949
        eq = self.assertEqual
950
        eq(len(w1), 4)
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
951
        eq(sorted(w1.versions()),
1393.1.50 by Martin Pool
- more development of Weave.join()
952
           ['b1', 'v1', 'v2', 'v3'])
920 by Martin Pool
- add more test cases for weave_merge
953
1393.1.51 by Martin Pool
- new Weave.copy()
954
    def test_join_related(self):
955
        wa = self.weave1.copy()
956
        wb = self.weave1.copy()
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
957
        wa.add_lines('a1', ['v3'], ['hello\n', 'sweet\n', 'world\n'])
958
        wb.add_lines('b1', ['v3'], ['hello\n', 'pale blue\n', 'world\n'])
1393.1.51 by Martin Pool
- new Weave.copy()
959
        eq = self.assertEquals
960
        eq(len(wa), 4)
961
        eq(len(wb), 4)
962
        wa.join(wb)
963
        eq(len(wa), 5)
964
        eq(wa.get_lines('b1'),
965
           ['hello\n', 'pale blue\n', 'world\n'])
966
1393.1.67 by Martin Pool
- test that we cannot join weaves with different ancestry
967
    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.
968
        #join reconciles differening parents into a union.
1393.1.67 by Martin Pool
- test that we cannot join weaves with different ancestry
969
        wa = Weave()
970
        wb = Weave()
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
971
        wa.add_lines('v1', [], ['hello\n'])
972
        wb.add_lines('v0', [], [])
973
        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.
974
        wa.join(wb)
975
        self.assertEqual(['v0'], wa.get_parents('v1'))
1393.1.67 by Martin Pool
- test that we cannot join weaves with different ancestry
976
977
    def test_join_text_disagreement(self):
978
        """Cannot join weaves with different texts for a version."""
979
        wa = Weave()
980
        wb = Weave()
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
981
        wa.add_lines('v1', [], ['hello\n'])
982
        wb.add_lines('v1', [], ['not\n', 'hello\n'])
1393.1.67 by Martin Pool
- test that we cannot join weaves with different ancestry
983
        self.assertRaises(WeaveError,
984
                          wa.join, wb)
985
1393.1.66 by Martin Pool
- fix join of weaves where parents occur at different offsets
986
    def test_join_unordered(self):
987
        """Join weaves where indexes differ.
988
        
989
        The source weave contains a different version at index 0."""
990
        wa = self.weave1.copy()
991
        wb = Weave()
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
992
        wb.add_lines('x1', [], ['line from x1\n'])
993
        wb.add_lines('v1', [], ['hello\n'])
994
        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
995
        wa.join(wb)
996
        eq = self.assertEquals
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
997
        eq(sorted(wa.versions()), ['v1', 'v2', 'v3', 'x1',])
1393.1.66 by Martin Pool
- fix join of weaves where parents occur at different offsets
998
        eq(wa.get_text('x1'), 'line from x1\n')
1185.50.23 by John Arbash Meinel
Adding sha1 check when weave extracts a text.
999
1000
    def test_written_detection(self):
1185.50.29 by John Arbash Meinel
Whitespace and other formatting cleanups suggested by Robert.
1001
        # Test detection of weave file corruption.
1002
        #
1003
        # Make sure that we can detect if a weave file has
1004
        # been corrupted. This doesn't test all forms of corruption,
1005
        # 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.
1006
        from cStringIO import StringIO
1007
1008
        w = Weave()
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
1009
        w.add_lines('v1', [], ['hello\n'])
1010
        w.add_lines('v2', ['v1'], ['hello\n', 'there\n'])
1185.50.23 by John Arbash Meinel
Adding sha1 check when weave extracts a text.
1011
1012
        tmpf = StringIO()
1013
        write_weave(w, tmpf)
1014
1015
        # Because we are corrupting, we need to make sure we have the exact text
1016
        self.assertEquals('# bzr weave file v5\n'
1017
                          'i\n1 f572d396fae9206628714fb2ce00f72e94f2258f\nn v1\n\n'
1018
                          'i 0\n1 90f265c6e75f1c8f9ab76dcf85528352c5f215ef\nn v2\n\n'
1019
                          'w\n{ 0\n. hello\n}\n{ 1\n. there\n}\nW\n',
1020
                          tmpf.getvalue())
1021
1022
        # Change a single letter
1023
        tmpf = StringIO('# bzr weave file v5\n'
1024
                        'i\n1 f572d396fae9206628714fb2ce00f72e94f2258f\nn v1\n\n'
1025
                        'i 0\n1 90f265c6e75f1c8f9ab76dcf85528352c5f215ef\nn v2\n\n'
1026
                        'w\n{ 0\n. hello\n}\n{ 1\n. There\n}\nW\n')
1027
1028
        w = read_weave(tmpf)
1029
1030
        self.assertEqual('hello\n', w.get_text('v1'))
1031
        self.assertRaises(errors.WeaveInvalidChecksum, w.get_text, 'v2')
1032
        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.
1033
        self.assertRaises(errors.WeaveInvalidChecksum, w.check)
1185.50.23 by John Arbash Meinel
Adding sha1 check when weave extracts a text.
1034
1035
        # Change the sha checksum
1036
        tmpf = StringIO('# bzr weave file v5\n'
1037
                        'i\n1 f572d396fae9206628714fb2ce00f72e94f2258f\nn v1\n\n'
1038
                        'i 0\n1 f0f265c6e75f1c8f9ab76dcf85528352c5f215ef\nn v2\n\n'
1039
                        'w\n{ 0\n. hello\n}\n{ 1\n. there\n}\nW\n')
1040
1041
        w = read_weave(tmpf)
1042
1043
        self.assertEqual('hello\n', w.get_text('v1'))
1044
        self.assertRaises(errors.WeaveInvalidChecksum, w.get_text, 'v2')
1045
        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.
1046
        self.assertRaises(errors.WeaveInvalidChecksum, w.check)
1185.50.23 by John Arbash Meinel
Adding sha1 check when weave extracts a text.
1047
1048
1551.3.11 by Aaron Bentley
Merge from Robert
1049
class InstrumentedWeave(Weave):
1050
    """Keep track of how many times functions are called."""
1051
    
1052
    def __init__(self, weave_name=None):
1053
        self._extract_count = 0
1054
        Weave.__init__(self, weave_name=weave_name)
1055
1056
    def _extract(self, versions):
1057
        self._extract_count += 1
1058
        return Weave._extract(self, versions)
1059
1060
1061
class JoinOptimization(TestCase):
1062
    """Test that Weave.join() doesn't extract all texts, only what must be done."""
1063
1064
    def test_join(self):
1065
        w1 = InstrumentedWeave()
1066
        w2 = InstrumentedWeave()
1067
1068
        txt0 = ['a\n']
1069
        txt1 = ['a\n', 'b\n']
1070
        txt2 = ['a\n', 'c\n']
1071
        txt3 = ['a\n', 'b\n', 'c\n']
1072
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
1073
        w1.add_lines('txt0', [], txt0) # extract 1a
1074
        w2.add_lines('txt0', [], txt0) # extract 1b
1075
        w1.add_lines('txt1', ['txt0'], txt1)# extract 2a
1076
        w2.add_lines('txt2', ['txt0'], txt2)# extract 2b
1551.3.11 by Aaron Bentley
Merge from Robert
1077
        w1.join(w2) # extract 3a to add txt2 
1078
        w2.join(w1) # extract 3b to add txt1 
1079
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
1080
        w1.add_lines('txt3', ['txt1', 'txt2'], txt3) # extract 4a 
1081
        w2.add_lines('txt3', ['txt2', 'txt1'], txt3) # extract 4b
1551.3.11 by Aaron Bentley
Merge from Robert
1082
        # These secretly have inverted parents
1083
1084
        # This should not have to do any extractions
1085
        w1.join(w2) # NO extract, texts already present with same parents
1086
        w2.join(w1) # NO extract, texts already present with same parents
1087
1088
        self.assertEqual(4, w1._extract_count)
1089
        self.assertEqual(4, w2._extract_count)
1090
1091
    def test_double_parent(self):
1092
        # It should not be considered illegal to add
1093
        # a revision with the same parent twice
1094
        w1 = InstrumentedWeave()
1095
        w2 = InstrumentedWeave()
1096
1097
        txt0 = ['a\n']
1098
        txt1 = ['a\n', 'b\n']
1099
        txt2 = ['a\n', 'c\n']
1100
        txt3 = ['a\n', 'b\n', 'c\n']
1101
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
1102
        w1.add_lines('txt0', [], txt0)
1103
        w2.add_lines('txt0', [], txt0)
1104
        w1.add_lines('txt1', ['txt0'], txt1)
1105
        w2.add_lines('txt1', ['txt0', 'txt0'], txt1)
1551.3.11 by Aaron Bentley
Merge from Robert
1106
        # Same text, effectively the same, because the
1107
        # parent is only repeated
1108
        w1.join(w2) # extract 3a to add txt2 
1109
        w2.join(w1) # extract 3b to add txt1 
1110
1111
1616.1.18 by Martin Pool
(weave-merge) don't treat killed-both lines as points of agreement;
1112
class TestNeedsReweave(TestCase):
1563.2.24 by Robert Collins
Make join cheaper for compatibly inconsistent parents.
1113
    """Internal corner cases for when reweave is needed."""
1114
1115
    def test_compatible_parents(self):
1116
        w1 = Weave('a')
1117
        my_parents = set([1, 2, 3])
1118
        # subsets are ok
1119
        self.assertTrue(w1._compatible_parents(my_parents, set([3])))
1120
        # same sets
1121
        self.assertTrue(w1._compatible_parents(my_parents, set(my_parents)))
1122
        # same empty corner case
1123
        self.assertTrue(w1._compatible_parents(set(), set()))
1124
        # other cannot contain stuff my_parents does not
1125
        self.assertFalse(w1._compatible_parents(set(), set([1])))
1126
        self.assertFalse(w1._compatible_parents(my_parents, set([1, 2, 3, 4])))
1127
        self.assertFalse(w1._compatible_parents(my_parents, set([4])))