/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
1233 by Martin Pool
- fix up weave tests for new test framework
31
from bzrlib.selftest 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
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
41
1233 by Martin Pool
- fix up weave tests for new test framework
42
class TestBase(TestCase):
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
43
    def check_read_write(self, k):
44
        """Check the weave k can be written & re-read."""
45
        from tempfile import TemporaryFile
46
        tf = TemporaryFile()
47
48
        write_weave(k, tf)
49
        tf.seek(0)
50
        k2 = read_weave(tf)
51
52
        if k != k2:
53
            tf.seek(0)
54
            self.log('serialized weave:')
55
            self.log(tf.read())
1083 by Martin Pool
- add space to store revision-id in weave files
56
57
            self.log('')
58
            self.log('parents: %s' % (k._parents == k2._parents))
59
            self.log('         %r' % k._parents)
60
            self.log('         %r' % k2._parents)
61
            self.log('')
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
62
            self.fail('read/write check failed')
1185.16.125 by Martin Pool
Test for 'name in weave'
63
64
65
class WeaveContains(TestBase):
66
    """Weave __contains__ operator"""
67
    def runTest(self):
68
        k = Weave()
69
        self.assertFalse('foo' in k)
70
        k.add('foo', [], TEXT_1)
71
        self.assertTrue('foo' in k)
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
72
73
0.1.2 by Martin Pool
Import testsweet module adapted from bzr.
74
class Easy(TestBase):
75
    def runTest(self):
0.1.38 by Martin Pool
Rename knit to weave. (I don't think there's an existing module called weave.)
76
        k = Weave()
0.1.2 by Martin Pool
Import testsweet module adapted from bzr.
77
78
79
class StoreText(TestBase):
80
    """Store and retrieve a simple text."""
81
    def runTest(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()
1083 by Martin Pool
- add space to store revision-id in weave files
83
        idx = k.add('text0', [], TEXT_0)
0.1.4 by Martin Pool
Start indexing knits by both integer and version string.
84
        self.assertEqual(k.get(idx), TEXT_0)
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
89
class AnnotateOne(TestBase):
90
    def runTest(self):
0.1.38 by Martin Pool
Rename knit to weave. (I don't think there's an existing module called weave.)
91
        k = Weave()
1083 by Martin Pool
- add space to store revision-id in weave files
92
        k.add('text0', [], TEXT_0)
0.1.7 by Martin Pool
Add trivial annotate text
93
        self.assertEqual(k.annotate(0),
94
                         [(0, TEXT_0[0])])
95
96
0.1.5 by Martin Pool
Add test for storing two text versions.
97
class StoreTwo(TestBase):
98
    def runTest(self):
0.1.38 by Martin Pool
Rename knit to weave. (I don't think there's an existing module called weave.)
99
        k = Weave()
0.1.5 by Martin Pool
Add test for storing two text versions.
100
1083 by Martin Pool
- add space to store revision-id in weave files
101
        idx = k.add('text0', [], TEXT_0)
0.1.5 by Martin Pool
Add test for storing two text versions.
102
        self.assertEqual(idx, 0)
103
1083 by Martin Pool
- add space to store revision-id in weave files
104
        idx = k.add('text1', [], TEXT_1)
0.1.5 by Martin Pool
Add test for storing two text versions.
105
        self.assertEqual(idx, 1)
106
107
        self.assertEqual(k.get(0), TEXT_0)
108
        self.assertEqual(k.get(1), TEXT_1)
109
0.1.13 by Martin Pool
Knit structure now allows for versions to include the lines present in other
110
0.1.21 by Martin Pool
Start computing a delta to insert a new revision
111
1323 by Martin Pool
- caller can pass SHA-1 to Weave.add for efficiency
112
class AddWithGivenSha(TestBase):
113
    def runTest(self):
114
        """Add with caller-supplied SHA-1"""
115
        k = Weave()
116
117
        t = 'text0'
118
        k.add('text0', [], [t], sha1=sha_string(t))
119
120
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
937 by Martin Pool
- weave raises IndexError when an invalid revision is given
127
        self.assertRaises(IndexError,
0.1.27 by Martin Pool
Check that version numbers passed in are reasonable
128
                          k.add,
1083 by Martin Pool
- add space to store revision-id in weave files
129
                          'text0',
0.1.27 by Martin Pool
Check that version numbers passed in are reasonable
130
                          [69],
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()
138
        idx = k.add('text0', [], TEXT_0)
139
        idx2 = k.add('text0', [], TEXT_0)
140
        self.assertEqual(idx, idx2)
141
142
143
144
class InvalidRepeatedAdd(TestBase):
145
    def runTest(self):
146
        k = Weave()
147
        idx = k.add('text0', [], TEXT_0)
148
        self.assertRaises(WeaveError,
149
                          k.add,
150
                          'text0',
151
                          [],
152
                          ['not the same text'])
153
        self.assertRaises(WeaveError,
154
                          k.add,
155
                          'text0',
156
                          [12],         # not the right parents
157
                          TEXT_0)
158
        
159
160
0.1.26 by Martin Pool
Refactor parameters to add command
161
class InsertLines(TestBase):
0.1.13 by Martin Pool
Knit structure now allows for versions to include the lines present in other
162
    """Store a revision that adds one line to the original.
163
164
    Look at the annotations to make sure that the first line is matched
165
    and not stored repeatedly."""
166
    def runTest(self):
0.1.38 by Martin Pool
Rename knit to weave. (I don't think there's an existing module called weave.)
167
        k = Weave()
0.1.13 by Martin Pool
Knit structure now allows for versions to include the lines present in other
168
1083 by Martin Pool
- add space to store revision-id in weave files
169
        k.add('text0', [], ['line 1'])
170
        k.add('text1', [0], ['line 1', 'line 2'])
0.1.13 by Martin Pool
Knit structure now allows for versions to include the lines present in other
171
172
        self.assertEqual(k.annotate(0),
173
                         [(0, 'line 1')])
174
0.1.25 by Martin Pool
Handle insertion of new weave layers that insert text on top of the basis
175
        self.assertEqual(k.get(1),
176
                         ['line 1',
177
                          'line 2'])
178
0.1.13 by Martin Pool
Knit structure now allows for versions to include the lines present in other
179
        self.assertEqual(k.annotate(1),
180
                         [(0, 'line 1'),
181
                          (1, 'line 2')])
182
1083 by Martin Pool
- add space to store revision-id in weave files
183
        k.add('text2', [0], ['line 1', 'diverged line'])
0.1.28 by Martin Pool
More tests for insertion of lines in new versions.
184
185
        self.assertEqual(k.annotate(2),
186
                         [(0, 'line 1'),
187
                          (2, 'diverged line')])
188
0.1.54 by Martin Pool
Fix weave line calculation when making deltas
189
        text3 = ['line 1', 'middle line', 'line 2']
1083 by Martin Pool
- add space to store revision-id in weave files
190
        k.add('text3',
191
              [0, 1],
0.1.54 by Martin Pool
Fix weave line calculation when making deltas
192
              text3)
193
937 by Martin Pool
- weave raises IndexError when an invalid revision is given
194
        # 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
195
944 by Martin Pool
- refactor member names in Weave code
196
        self.log("k._weave=" + pformat(k._weave))
0.1.28 by Martin Pool
More tests for insertion of lines in new versions.
197
198
        self.assertEqual(k.annotate(3),
199
                         [(0, 'line 1'),
200
                          (3, 'middle line'),
201
                          (1, 'line 2')])
202
0.1.31 by Martin Pool
Fix insertion of multiple regions, calculating the right line offset as we go.
203
        # now multiple insertions at different places
1083 by Martin Pool
- add space to store revision-id in weave files
204
        k.add('text4',
205
              [0, 1, 3],
0.1.31 by Martin Pool
Fix insertion of multiple regions, calculating the right line offset as we go.
206
              ['line 1', 'aaa', 'middle line', 'bbb', 'line 2', 'ccc'])
207
208
        self.assertEqual(k.annotate(4), 
209
                         [(0, 'line 1'),
210
                          (4, 'aaa'),
211
                          (3, 'middle line'),
212
                          (4, 'bbb'),
213
                          (1, 'line 2'),
214
                          (4, 'ccc')])
0.1.13 by Martin Pool
Knit structure now allows for versions to include the lines present in other
215
0.1.40 by Martin Pool
Add test for extracting from weave with nested insertions
216
0.1.48 by Martin Pool
Basic parsing of delete instructions.
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
1083 by Martin Pool
- add space to store revision-id in weave files
227
        k.add('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:
1083 by Martin Pool
- add space to store revision-id in weave files
237
            ver = k.add('text%d' % i,
238
                        [0], t)
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)):
245
            self.assertEqual(k.get(i+1),
246
                             texts[i])
247
            
248
249
250
0.1.49 by Martin Pool
Add another constraint: revisions should not delete text that they
251
class SuicideDelete(TestBase):
0.1.55 by Martin Pool
doc
252
    """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
253
    def runTest(self):
254
        k = Weave()
255
944 by Martin Pool
- refactor member names in Weave code
256
        k._parents = [(),
0.1.49 by Martin Pool
Add another constraint: revisions should not delete text that they
257
                ]
944 by Martin Pool
- refactor member names in Weave code
258
        k._weave = [('{', 0),
0.1.49 by Martin Pool
Add another constraint: revisions should not delete text that they
259
                'first line',
260
                ('[', 0),
261
                'deleted in 0',
262
                (']', 0),
263
                ('}', 0),
264
                ]
891 by Martin Pool
- fix up refactoring of weave
265
        ################################### SKIPPED
266
        # Weave.get doesn't trap this anymore
267
        return 
0.1.49 by Martin Pool
Add another constraint: revisions should not delete text that they
268
269
        self.assertRaises(WeaveFormatError,
270
                          k.get,
271
                          0)        
272
273
274
0.1.48 by Martin Pool
Basic parsing of delete instructions.
275
class CannedDelete(TestBase):
276
    """Unpack canned weave with deleted lines."""
277
    def runTest(self):
278
        k = Weave()
279
944 by Martin Pool
- refactor member names in Weave code
280
        k._parents = [(),
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
281
                frozenset([0]),
0.1.48 by Martin Pool
Basic parsing of delete instructions.
282
                ]
944 by Martin Pool
- refactor member names in Weave code
283
        k._weave = [('{', 0),
0.1.48 by Martin Pool
Basic parsing of delete instructions.
284
                'first line',
285
                ('[', 1),
286
                'line to be deleted',
287
                (']', 1),
288
                'last line',
289
                ('}', 0),
290
                ]
291
292
        self.assertEqual(k.get(0),
293
                         ['first line',
294
                          'line to be deleted',
295
                          'last line',
296
                          ])
297
0.1.50 by Martin Pool
Basic implementation of deletion markers
298
        self.assertEqual(k.get(1),
299
                         ['first line',
300
                          'last line',
301
                          ])
302
0.1.48 by Martin Pool
Basic parsing of delete instructions.
303
304
0.1.51 by Martin Pool
Add test for replacement lines
305
class CannedReplacement(TestBase):
306
    """Unpack canned weave with deleted lines."""
307
    def runTest(self):
308
        k = Weave()
309
944 by Martin Pool
- refactor member names in Weave code
310
        k._parents = [frozenset(),
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
311
                frozenset([0]),
0.1.51 by Martin Pool
Add test for replacement lines
312
                ]
944 by Martin Pool
- refactor member names in Weave code
313
        k._weave = [('{', 0),
0.1.51 by Martin Pool
Add test for replacement lines
314
                'first line',
315
                ('[', 1),
316
                'line to be deleted',
317
                (']', 1),
318
                ('{', 1),
319
                'replacement line',                
320
                ('}', 1),
321
                'last line',
322
                ('}', 0),
323
                ]
324
325
        self.assertEqual(k.get(0),
326
                         ['first line',
327
                          'line to be deleted',
328
                          'last line',
329
                          ])
330
331
        self.assertEqual(k.get(1),
332
                         ['first line',
333
                          'replacement line',
334
                          'last line',
335
                          ])
336
337
338
0.1.46 by Martin Pool
More constraints on structure of weave, and checks that they work
339
class BadWeave(TestBase):
340
    """Test that we trap an insert which should not occur."""
341
    def runTest(self):
342
        k = Weave()
343
944 by Martin Pool
- refactor member names in Weave code
344
        k._parents = [frozenset(),
0.1.46 by Martin Pool
More constraints on structure of weave, and checks that they work
345
                ]
944 by Martin Pool
- refactor member names in Weave code
346
        k._weave = ['bad line',
0.1.46 by Martin Pool
More constraints on structure of weave, and checks that they work
347
                ('{', 0),
348
                'foo {',
349
                ('{', 1),
350
                '  added in version 1',
351
                ('{', 2),
352
                '  added in v2',
353
                ('}', 2),
354
                '  also from v1',
355
                ('}', 1),
356
                '}',
357
                ('}', 0)]
358
891 by Martin Pool
- fix up refactoring of weave
359
        ################################### SKIPPED
360
        # Weave.get doesn't trap this anymore
361
        return 
362
363
0.1.47 by Martin Pool
New WeaveError and WeaveFormatError rather than assertions.
364
        self.assertRaises(WeaveFormatError,
0.1.46 by Martin Pool
More constraints on structure of weave, and checks that they work
365
                          k.get,
366
                          0)
367
368
369
class BadInsert(TestBase):
370
    """Test that we trap an insert which should not occur."""
371
    def runTest(self):
372
        k = Weave()
373
944 by Martin Pool
- refactor member names in Weave code
374
        k._parents = [frozenset(),
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
375
                frozenset([0]),
376
                frozenset([0]),
377
                frozenset([0,1,2]),
0.1.46 by Martin Pool
More constraints on structure of weave, and checks that they work
378
                ]
944 by Martin Pool
- refactor member names in Weave code
379
        k._weave = [('{', 0),
0.1.46 by Martin Pool
More constraints on structure of weave, and checks that they work
380
                'foo {',
381
                ('{', 1),
382
                '  added in version 1',
383
                ('{', 1),
384
                '  more in 1',
385
                ('}', 1),
386
                ('}', 1),
387
                ('}', 0)]
388
891 by Martin Pool
- fix up refactoring of weave
389
390
        # this is not currently enforced by get
391
        return  ##########################################
392
0.1.47 by Martin Pool
New WeaveError and WeaveFormatError rather than assertions.
393
        self.assertRaises(WeaveFormatError,
0.1.46 by Martin Pool
More constraints on structure of weave, and checks that they work
394
                          k.get,
395
                          0)
396
0.1.47 by Martin Pool
New WeaveError and WeaveFormatError rather than assertions.
397
        self.assertRaises(WeaveFormatError,
0.1.46 by Martin Pool
More constraints on structure of weave, and checks that they work
398
                          k.get,
399
                          1)
400
0.1.40 by Martin Pool
Add test for extracting from weave with nested insertions
401
402
class InsertNested(TestBase):
403
    """Insertion with nested instructions."""
404
    def runTest(self):
405
        k = Weave()
406
944 by Martin Pool
- refactor member names in Weave code
407
        k._parents = [frozenset(),
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
408
                frozenset([0]),
409
                frozenset([0]),
410
                frozenset([0,1,2]),
0.1.40 by Martin Pool
Add test for extracting from weave with nested insertions
411
                ]
944 by Martin Pool
- refactor member names in Weave code
412
        k._weave = [('{', 0),
0.1.40 by Martin Pool
Add test for extracting from weave with nested insertions
413
                'foo {',
414
                ('{', 1),
415
                '  added in version 1',
0.1.42 by Martin Pool
More tests for nested insert instructions
416
                ('{', 2),
417
                '  added in v2',
418
                ('}', 2),
419
                '  also from v1',
0.1.40 by Martin Pool
Add test for extracting from weave with nested insertions
420
                ('}', 1),
421
                '}',
422
                ('}', 0)]
423
424
        self.assertEqual(k.get(0),
425
                         ['foo {',
426
                          '}'])
427
428
        self.assertEqual(k.get(1),
429
                         ['foo {',
430
                          '  added in version 1',
0.1.42 by Martin Pool
More tests for nested insert instructions
431
                          '  also from v1',
0.1.40 by Martin Pool
Add test for extracting from weave with nested insertions
432
                          '}'])
433
                       
0.1.44 by Martin Pool
More tests for nested insert instructions
434
        self.assertEqual(k.get(2),
435
                         ['foo {',
436
                          '  added in v2',
437
                          '}'])
438
439
        self.assertEqual(k.get(3),
440
                         ['foo {',
441
                          '  added in version 1',
442
                          '  added in v2',
443
                          '  also from v1',
444
                          '}'])
445
                         
0.1.45 by Martin Pool
doc
446
0.1.40 by Martin Pool
Add test for extracting from weave with nested insertions
447
0.1.56 by Martin Pool
Handle deletion of lines by marking the region with a deletion
448
class DeleteLines2(TestBase):
0.1.30 by Martin Pool
Start adding tests for line deletion
449
    """Test recording revisions that delete lines.
450
451
    This relies on the weave having a way to represent lines knocked
452
    out by a later revision."""
453
    def runTest(self):
0.1.38 by Martin Pool
Rename knit to weave. (I don't think there's an existing module called weave.)
454
        k = Weave()
0.1.30 by Martin Pool
Start adding tests for line deletion
455
1083 by Martin Pool
- add space to store revision-id in weave files
456
        k.add('text0', [], ["line the first",
0.1.30 by Martin Pool
Start adding tests for line deletion
457
                   "line 2",
458
                   "line 3",
459
                   "fine"])
460
461
        self.assertEqual(len(k.get(0)), 4)
462
1083 by Martin Pool
- add space to store revision-id in weave files
463
        k.add('text1', [0], ["line the first",
0.1.30 by Martin Pool
Start adding tests for line deletion
464
                   "fine"])
465
466
        self.assertEqual(k.get(1),
467
                         ["line the first",
468
                          "fine"])
469
0.1.56 by Martin Pool
Handle deletion of lines by marking the region with a deletion
470
        self.assertEqual(k.annotate(1),
471
                         [(0, "line the first"),
472
                          (0, "fine")])
473
0.1.30 by Martin Pool
Start adding tests for line deletion
474
0.1.26 by Martin Pool
Refactor parameters to add command
475
0.1.13 by Martin Pool
Knit structure now allows for versions to include the lines present in other
476
class IncludeVersions(TestBase):
477
    """Check texts that are stored across multiple revisions.
478
0.1.38 by Martin Pool
Rename knit to weave. (I don't think there's an existing module called weave.)
479
    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
480
    sure it unpacks properly.
481
482
    Text 0 includes nothing; text 1 includes text 0 and adds some
483
    lines.
484
    """
485
486
    def runTest(self):
0.1.38 by Martin Pool
Rename knit to weave. (I don't think there's an existing module called weave.)
487
        k = Weave()
0.1.13 by Martin Pool
Knit structure now allows for versions to include the lines present in other
488
944 by Martin Pool
- refactor member names in Weave code
489
        k._parents = [frozenset(), frozenset([0])]
490
        k._weave = [('{', 0),
0.1.39 by Martin Pool
Change to a more realistic weave structure which can represent insertions and
491
                "first line",
492
                ('}', 0),
493
                ('{', 1),
494
                "second line",
495
                ('}', 1)]
0.1.13 by Martin Pool
Knit structure now allows for versions to include the lines present in other
496
497
        self.assertEqual(k.get(1),
498
                         ["first line",
499
                          "second line"])
500
501
        self.assertEqual(k.get(0),
502
                         ["first line"])
503
0.1.5 by Martin Pool
Add test for storing two text versions.
504
0.1.14 by Martin Pool
Another test for version inclusion
505
class DivergedIncludes(TestBase):
0.1.38 by Martin Pool
Rename knit to weave. (I don't think there's an existing module called weave.)
506
    """Weave with two diverged texts based on version 0.
0.1.14 by Martin Pool
Another test for version inclusion
507
    """
508
    def runTest(self):
0.1.38 by Martin Pool
Rename knit to weave. (I don't think there's an existing module called weave.)
509
        k = Weave()
0.1.14 by Martin Pool
Another test for version inclusion
510
944 by Martin Pool
- refactor member names in Weave code
511
        k._parents = [frozenset(),
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
512
                frozenset([0]),
513
                frozenset([0]),
0.1.17 by Martin Pool
Use objects rather than tuples for tracking VerInfo for
514
                ]
944 by Martin Pool
- refactor member names in Weave code
515
        k._weave = [('{', 0),
0.1.39 by Martin Pool
Change to a more realistic weave structure which can represent insertions and
516
                "first line",
517
                ('}', 0),
518
                ('{', 1),
519
                "second line",
520
                ('}', 1),
521
                ('{', 2),
522
                "alternative second line",
523
                ('}', 2),                
524
                ]
0.1.14 by Martin Pool
Another test for version inclusion
525
526
        self.assertEqual(k.get(0),
527
                         ["first line"])
528
529
        self.assertEqual(k.get(1),
530
                         ["first line",
531
                          "second line"])
532
533
        self.assertEqual(k.get(2),
534
                         ["first line",
535
                          "alternative second line"])
536
924 by Martin Pool
- Add IntSet class
537
        self.assertEqual(list(k.inclusions([2])),
538
                         [0, 2])
0.1.77 by Martin Pool
New Weave.get_included() does transitive expansion
539
0.1.57 by Martin Pool
Fix bug in an update edit that both deletes and inserts -- previously
540
541
542
class ReplaceLine(TestBase):
543
    def runTest(self):
544
        k = Weave()
545
546
        text0 = ['cheddar', 'stilton', 'gruyere']
547
        text1 = ['cheddar', 'blue vein', 'neufchatel', 'chevre']
548
        
1083 by Martin Pool
- add space to store revision-id in weave files
549
        k.add('text0', [], text0)
550
        k.add('text1', [0], text1)
0.1.57 by Martin Pool
Fix bug in an update edit that both deletes and inserts -- previously
551
944 by Martin Pool
- refactor member names in Weave code
552
        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
553
0.1.59 by Martin Pool
More modification tests
554
        self.assertEqual(k.get(0), text0)
0.1.57 by Martin Pool
Fix bug in an update edit that both deletes and inserts -- previously
555
        self.assertEqual(k.get(1), text1)
556
0.1.64 by Martin Pool
Add test for merging versions
557
558
559
class Merge(TestBase):
0.1.95 by Martin Pool
- preliminary merge conflict detection
560
    """Storage of versions that merge diverged parents"""
0.1.64 by Martin Pool
Add test for merging versions
561
    def runTest(self):
562
        k = Weave()
563
564
        texts = [['header'],
565
                 ['header', '', 'line from 1'],
566
                 ['header', '', 'line from 2', 'more from 2'],
567
                 ['header', '', 'line from 1', 'fixup line', 'line from 2'],
568
                 ]
569
1083 by Martin Pool
- add space to store revision-id in weave files
570
        k.add('text0', [], texts[0])
571
        k.add('text1', [0], texts[1])
572
        k.add('text2', [0], texts[2])
573
        k.add('merge', [0, 1, 2], texts[3])
0.1.64 by Martin Pool
Add test for merging versions
574
575
        for i, t in enumerate(texts):
576
            self.assertEqual(k.get(i), t)
577
578
        self.assertEqual(k.annotate(3),
579
                         [(0, 'header'),
580
                          (1, ''),
581
                          (1, 'line from 1'),
582
                          (3, 'fixup line'),
583
                          (2, 'line from 2'),
584
                          ])
585
924 by Martin Pool
- Add IntSet class
586
        self.assertEqual(list(k.inclusions([3])),
587
                         [0, 1, 2, 3])
0.1.77 by Martin Pool
New Weave.get_included() does transitive expansion
588
944 by Martin Pool
- refactor member names in Weave code
589
        self.log('k._weave=' + pformat(k._weave))
0.1.64 by Martin Pool
Add test for merging versions
590
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
591
        self.check_read_write(k)
0.1.65 by Martin Pool
Add Weave.merge_iter to get automerged lines
592
593
0.1.95 by Martin Pool
- preliminary merge conflict detection
594
class Conflicts(TestBase):
595
    """Test detection of conflicting regions during a merge.
596
597
    A base version is inserted, then two descendents try to
598
    insert different lines in the same place.  These should be
599
    reported as a possible conflict and forwarded to the user."""
600
    def runTest(self):
601
        return  # NOT RUN
602
        k = Weave()
603
604
        k.add([], ['aaa', 'bbb'])
605
        k.add([0], ['aaa', '111', 'bbb'])
606
        k.add([1], ['aaa', '222', 'bbb'])
607
608
        merged = k.merge([1, 2])
609
610
        self.assertEquals([[['aaa']],
611
                           [['111'], ['222']],
612
                           [['bbb']]])
613
614
615
616
class NonConflict(TestBase):
617
    """Two descendants insert compatible changes.
618
619
    No conflict should be reported."""
620
    def runTest(self):
621
        return  # NOT RUN
622
        k = Weave()
623
624
        k.add([], ['aaa', 'bbb'])
625
        k.add([0], ['111', 'aaa', 'ccc', 'bbb'])
626
        k.add([1], ['aaa', 'ccc', 'bbb', '222'])
627
628
    
629
    
630
631
0.1.65 by Martin Pool
Add Weave.merge_iter to get automerged lines
632
class AutoMerge(TestBase):
633
    def runTest(self):
634
        k = Weave()
635
636
        texts = [['header', 'aaa', 'bbb'],
637
                 ['header', 'aaa', 'line from 1', 'bbb'],
638
                 ['header', 'aaa', 'bbb', 'line from 2', 'more from 2'],
639
                 ]
640
1083 by Martin Pool
- add space to store revision-id in weave files
641
        k.add('text0', [], texts[0])
642
        k.add('text1', [0], texts[1])
643
        k.add('text2', [0], texts[2])
0.1.65 by Martin Pool
Add Weave.merge_iter to get automerged lines
644
944 by Martin Pool
- refactor member names in Weave code
645
        self.log('k._weave=' + pformat(k._weave))
0.1.65 by Martin Pool
Add Weave.merge_iter to get automerged lines
646
0.1.95 by Martin Pool
- preliminary merge conflict detection
647
        m = list(k.mash_iter([0, 1, 2]))
0.1.65 by Martin Pool
Add Weave.merge_iter to get automerged lines
648
649
        self.assertEqual(m,
650
                         ['header', 'aaa',
651
                          'line from 1',
652
                          'bbb',
653
                          'line from 2', 'more from 2'])
0.1.57 by Martin Pool
Fix bug in an update edit that both deletes and inserts -- previously
654
        
655
656
657
class Khayyam(TestBase):
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
658
    """Test changes to multi-line texts, and read/write"""
0.1.57 by Martin Pool
Fix bug in an update edit that both deletes and inserts -- previously
659
    def runTest(self):
660
        rawtexts = [
661
            """A Book of Verses underneath the Bough,
662
            A Jug of Wine, a Loaf of Bread, -- and Thou
663
            Beside me singing in the Wilderness --
664
            Oh, Wilderness were Paradise enow!""",
665
            
666
            """A Book of Verses underneath the Bough,
667
            A Jug of Wine, a Loaf of Bread, -- and Thou
668
            Beside me singing in the Wilderness --
669
            Oh, Wilderness were Paradise now!""",
0.1.59 by Martin Pool
More modification tests
670
671
            """A Book of poems underneath the tree,
672
            A Jug of Wine, a Loaf of Bread,
673
            and Thou
674
            Beside me singing in the Wilderness --
675
            Oh, Wilderness were Paradise now!
676
677
            -- O. Khayyam""",
678
679
            """A Book of Verses underneath the Bough,
680
            A Jug of Wine, a Loaf of Bread,
681
            and Thou
682
            Beside me singing in the Wilderness --
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
683
            Oh, Wilderness were Paradise now!""",
0.1.57 by Martin Pool
Fix bug in an update edit that both deletes and inserts -- previously
684
            ]
685
        texts = [[l.strip() for l in t.split('\n')] for t in rawtexts]
686
687
        k = Weave()
688
        parents = set()
1083 by Martin Pool
- add space to store revision-id in weave files
689
        i = 0
0.1.57 by Martin Pool
Fix bug in an update edit that both deletes and inserts -- previously
690
        for t in texts:
1083 by Martin Pool
- add space to store revision-id in weave files
691
            ver = k.add('text%d' % i,
692
                        list(parents), t)
0.1.57 by Martin Pool
Fix bug in an update edit that both deletes and inserts -- previously
693
            parents.add(ver)
1083 by Martin Pool
- add space to store revision-id in weave files
694
            i += 1
0.1.57 by Martin Pool
Fix bug in an update edit that both deletes and inserts -- previously
695
944 by Martin Pool
- refactor member names in Weave code
696
        self.log("k._weave=" + pformat(k._weave))
0.1.59 by Martin Pool
More modification tests
697
0.1.57 by Martin Pool
Fix bug in an update edit that both deletes and inserts -- previously
698
        for i, t in enumerate(texts):
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
699
            self.assertEqual(k.get(i), t)
0.1.57 by Martin Pool
Fix bug in an update edit that both deletes and inserts -- previously
700
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
701
        self.check_read_write(k)
0.1.57 by Martin Pool
Fix bug in an update edit that both deletes and inserts -- previously
702
703
920 by Martin Pool
- add more test cases for weave_merge
704
705
class MergeCases(TestBase):
706
    def doMerge(self, base, a, b, mp):
707
        from cStringIO import StringIO
708
        from textwrap import dedent
709
710
        def addcrlf(x):
711
            return x + '\n'
712
        
713
        w = Weave()
1083 by Martin Pool
- add space to store revision-id in weave files
714
        w.add('text0', [], map(addcrlf, base))
715
        w.add('text1', [0], map(addcrlf, a))
716
        w.add('text2', [0], map(addcrlf, b))
920 by Martin Pool
- add more test cases for weave_merge
717
935 by Martin Pool
- log weave for merge tests to help debugging
718
        self.log('weave is:')
719
        tmpf = StringIO()
720
        write_weave(w, tmpf)
721
        self.log(tmpf.getvalue())
722
920 by Martin Pool
- add more test cases for weave_merge
723
        self.log('merge plan:')
724
        p = list(w.plan_merge(1, 2))
725
        for state, line in p:
726
            if line:
727
                self.log('%12s | %s' % (state, line[:-1]))
728
729
        self.log('merge:')
730
        mt = StringIO()
731
        mt.writelines(w.weave_merge(p))
732
        mt.seek(0)
733
        self.log(mt.getvalue())
734
735
        mp = map(addcrlf, mp)
736
        self.assertEqual(mt.readlines(), mp)
737
        
738
        
739
    def testOneInsert(self):
740
        self.doMerge([],
741
                     ['aa'],
742
                     [],
743
                     ['aa'])
744
745
    def testSeparateInserts(self):
746
        self.doMerge(['aaa', 'bbb', 'ccc'],
747
                     ['aaa', 'xxx', 'bbb', 'ccc'],
748
                     ['aaa', 'bbb', 'yyy', 'ccc'],
749
                     ['aaa', 'xxx', 'bbb', 'yyy', 'ccc'])
750
751
    def testSameInsert(self):
752
        self.doMerge(['aaa', 'bbb', 'ccc'],
753
                     ['aaa', 'xxx', 'bbb', 'ccc'],
754
                     ['aaa', 'xxx', 'bbb', 'yyy', 'ccc'],
755
                     ['aaa', 'xxx', 'bbb', 'yyy', 'ccc'])
756
757
    def testOverlappedInsert(self):
758
        self.doMerge(['aaa', 'bbb'],
759
                     ['aaa', 'xxx', 'yyy', 'bbb'],
760
                     ['aaa', 'xxx', 'bbb'],
1185.12.86 by Aaron Bentley
Switched to standard 7-char conflict markers
761
                     ['aaa', '<<<<<<<', 'xxx', 'yyy', '=======', 'xxx', 
762
                      '>>>>>>>', 'bbb'])
920 by Martin Pool
- add more test cases for weave_merge
763
764
        # really it ought to reduce this to 
765
        # ['aaa', 'xxx', 'yyy', 'bbb']
766
767
768
    def testClashReplace(self):
769
        self.doMerge(['aaa'],
770
                     ['xxx'],
771
                     ['yyy', 'zzz'],
1185.12.86 by Aaron Bentley
Switched to standard 7-char conflict markers
772
                     ['<<<<<<<', 'xxx', '=======', 'yyy', 'zzz', 
773
                      '>>>>>>>'])
920 by Martin Pool
- add more test cases for weave_merge
774
775
    def testNonClashInsert(self):
776
        self.doMerge(['aaa'],
777
                     ['xxx', 'aaa'],
778
                     ['yyy', 'zzz'],
1185.12.86 by Aaron Bentley
Switched to standard 7-char conflict markers
779
                     ['<<<<<<<', 'xxx', 'aaa', '=======', 'yyy', 'zzz', 
780
                      '>>>>>>>'])
920 by Martin Pool
- add more test cases for weave_merge
781
782
        self.doMerge(['aaa'],
783
                     ['aaa'],
784
                     ['yyy', 'zzz'],
785
                     ['yyy', 'zzz'])
945 by Martin Pool
- add stubbed-out test for clashing replace and delete
786
787
788
    def testDeleteAndModify(self):
789
        """Clashing delete and modification.
790
791
        If one side modifies a region and the other deletes it then
792
        there should be a conflict with one side blank.
793
        """
794
795
        #######################################
796
        # skippd, not working yet
797
        return
798
        
799
        self.doMerge(['aaa', 'bbb', 'ccc'],
800
                     ['aaa', 'ddd', 'ccc'],
801
                     ['aaa', 'ccc'],
1185.12.86 by Aaron Bentley
Switched to standard 7-char conflict markers
802
                     ['<<<<<<<<', 'aaa', '=======', '>>>>>>>', 'ccc'])
1393.1.48 by Martin Pool
- Add stub Weave.join() method
803
804
805
class JoinWeavesTests(TestBase):
1393.1.50 by Martin Pool
- more development of Weave.join()
806
    def setUp(self):
807
        super(JoinWeavesTests, self).setUp()
808
        self.weave1 = Weave()
809
        self.lines1 = ['hello\n']
810
        self.lines3 = ['hello\n', 'cruel\n', 'world\n']
811
        self.weave1.add('v1', [], self.lines1)
812
        self.weave1.add('v2', [0], ['hello\n', 'world\n'])
813
        self.weave1.add('v3', [1], self.lines3)
814
        
1393.1.48 by Martin Pool
- Add stub Weave.join() method
815
    def test_join_empty(self):
816
        """Join two empty weaves."""
817
        eq = self.assertEqual
818
        w1 = Weave()
819
        w2 = Weave()
820
        w1.join(w2)
821
        eq(w1.numversions(), 0)
822
        
1393.1.50 by Martin Pool
- more development of Weave.join()
823
    def test_join_empty_to_nonempty(self):
824
        """Join empty weave onto nonempty."""
825
        self.weave1.join(Weave())
826
        self.assertEqual(len(self.weave1), 3)
827
828
    def test_join_unrelated(self):
829
        """Join two weaves with no history in common."""
830
        wb = Weave()
831
        wb.add('b1', [], ['line from b\n'])
832
        w1 = self.weave1
833
        w1.join(wb)
834
        eq = self.assertEqual
835
        eq(len(w1), 4)
836
        eq(sorted(list(w1.iter_names())),
837
           ['b1', 'v1', 'v2', 'v3'])
920 by Martin Pool
- add more test cases for weave_merge
838
1393.1.51 by Martin Pool
- new Weave.copy()
839
    def test_join_related(self):
840
        wa = self.weave1.copy()
841
        wb = self.weave1.copy()
842
        wa.add('a1', ['v3'], ['hello\n', 'sweet\n', 'world\n'])
843
        wb.add('b1', ['v3'], ['hello\n', 'pale blue\n', 'world\n'])
844
        eq = self.assertEquals
845
        eq(len(wa), 4)
846
        eq(len(wb), 4)
847
        wa.join(wb)
848
        eq(len(wa), 5)
849
        eq(wa.get_lines('b1'),
850
           ['hello\n', 'pale blue\n', 'world\n'])
851
1393.1.67 by Martin Pool
- test that we cannot join weaves with different ancestry
852
    def test_join_parent_disagreement(self):
853
        """Cannot join weaves with different parents for a version."""
854
        wa = Weave()
855
        wb = Weave()
856
        wa.add('v1', [], ['hello\n'])
857
        wb.add('v0', [], [])
858
        wb.add('v1', ['v0'], ['hello\n'])
859
        self.assertRaises(WeaveError,
860
                          wa.join, wb)
861
862
    def test_join_text_disagreement(self):
863
        """Cannot join weaves with different texts for a version."""
864
        wa = Weave()
865
        wb = Weave()
866
        wa.add('v1', [], ['hello\n'])
867
        wb.add('v1', [], ['not\n', 'hello\n'])
868
        self.assertRaises(WeaveError,
869
                          wa.join, wb)
870
1393.1.66 by Martin Pool
- fix join of weaves where parents occur at different offsets
871
    def test_join_unordered(self):
872
        """Join weaves where indexes differ.
873
        
874
        The source weave contains a different version at index 0."""
875
        wa = self.weave1.copy()
876
        wb = Weave()
877
        wb.add('x1', [], ['line from x1\n'])
878
        wb.add('v1', [], ['hello\n'])
879
        wb.add('v2', ['v1'], ['hello\n', 'world\n'])
880
        wa.join(wb)
881
        eq = self.assertEquals
882
        eq(sorted(wa.iter_names()), ['v1', 'v2', 'v3', 'x1',])
883
        eq(wa.get_text('x1'), 'line from x1\n')