~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to tools/testweave.py

  • Committer: Martin Pool
  • Date: 2005-07-08 02:21:13 UTC
  • Revision ID: mbp@sourcefrog.net-20050708022113-940d11d7505b0ac8
- refactor hashcache to use just one dictionary

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
18
 
19
19
 
20
 
# TODO: tests regarding version names
21
 
# TODO: rbc 20050108 test that join does not leave an inconsistent weave 
22
 
#       if it fails.
 
20
 
23
21
 
24
22
"""test suite for weave algorithm"""
25
23
 
 
24
 
 
25
import testsweet
 
26
from weave import Weave, WeaveFormatError
26
27
from pprint import pformat
27
28
 
28
 
import bzrlib.errors as errors
29
 
from bzrlib.weave import Weave, WeaveFormatError, WeaveError, reweave
30
 
from bzrlib.weavefile import write_weave, read_weave
31
 
from bzrlib.tests import TestCase
32
 
from bzrlib.osutils import sha_string
 
29
 
 
30
 
 
31
try:
 
32
    set
 
33
    frozenset
 
34
except NameError:
 
35
    from sets import Set, ImmutableSet
 
36
    set = Set
 
37
    frozenset = ImmutableSet
 
38
    del Set, ImmutableSet
 
39
 
33
40
 
34
41
 
35
42
# texts for use in testing
38
45
          "A second line"]
39
46
 
40
47
 
41
 
class TestBase(TestCase):
 
48
 
 
49
class TestBase(testsweet.TestBase):
42
50
    def check_read_write(self, k):
43
51
        """Check the weave k can be written & re-read."""
44
52
        from tempfile import TemporaryFile
 
53
        from weavefile import write_weave, read_weave
45
54
        tf = TemporaryFile()
46
55
 
47
56
        write_weave(k, tf)
52
61
            tf.seek(0)
53
62
            self.log('serialized weave:')
54
63
            self.log(tf.read())
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('')
61
64
            self.fail('read/write check failed')
62
 
 
63
 
 
64
 
class WeaveContains(TestBase):
65
 
    """Weave __contains__ operator"""
66
 
    def runTest(self):
67
 
        k = Weave()
68
 
        self.assertFalse('foo' in k)
69
 
        k.add('foo', [], TEXT_1)
70
 
        self.assertTrue('foo' in k)
 
65
        
 
66
        
71
67
 
72
68
 
73
69
class Easy(TestBase):
79
75
    """Store and retrieve a simple text."""
80
76
    def runTest(self):
81
77
        k = Weave()
82
 
        idx = k.add('text0', [], TEXT_0)
 
78
        idx = k.add([], TEXT_0)
83
79
        self.assertEqual(k.get(idx), TEXT_0)
84
80
        self.assertEqual(idx, 0)
85
81
 
86
82
 
 
83
 
87
84
class AnnotateOne(TestBase):
88
85
    def runTest(self):
89
86
        k = Weave()
90
 
        k.add('text0', [], TEXT_0)
 
87
        k.add([], TEXT_0)
91
88
        self.assertEqual(k.annotate(0),
92
89
                         [(0, TEXT_0[0])])
93
90
 
96
93
    def runTest(self):
97
94
        k = Weave()
98
95
 
99
 
        idx = k.add('text0', [], TEXT_0)
 
96
        idx = k.add([], TEXT_0)
100
97
        self.assertEqual(idx, 0)
101
98
 
102
 
        idx = k.add('text1', [], TEXT_1)
 
99
        idx = k.add([], TEXT_1)
103
100
        self.assertEqual(idx, 1)
104
101
 
105
102
        self.assertEqual(k.get(0), TEXT_0)
106
103
        self.assertEqual(k.get(1), TEXT_1)
107
104
 
108
 
 
109
 
class AddWithGivenSha(TestBase):
 
105
        k.dump(self.TEST_LOG)
 
106
 
 
107
 
 
108
 
 
109
class DeltaAdd(TestBase):
 
110
    """Detection of changes prior to inserting new revision."""
110
111
    def runTest(self):
111
 
        """Add with caller-supplied SHA-1"""
112
 
        k = Weave()
113
 
 
114
 
        t = 'text0'
115
 
        k.add('text0', [], [t], sha1=sha_string(t))
116
 
 
117
 
 
118
 
class GetSha1(TestBase):
119
 
    def test_get_sha1(self):
120
 
        k = Weave()
121
 
        k.add('text0', [], 'text0')
122
 
        self.assertEqual('34dc0e430c642a26c3dd1c2beb7a8b4f4445eb79',
123
 
                         k.get_sha1('text0'))
124
 
        self.assertRaises(errors.WeaveRevisionNotPresent,
125
 
                          k.get_sha1, 0)
126
 
        self.assertRaises(errors.WeaveRevisionNotPresent,
127
 
                          k.get_sha1, 'text1')
128
 
                        
 
112
        k = Weave()
 
113
        k.add([], ['line 1'])
 
114
 
 
115
        self.assertEqual(k._l,
 
116
                         [('{', 0),
 
117
                          'line 1',
 
118
                          ('}', 0),
 
119
                          ])
 
120
 
 
121
        changes = list(k._delta(set([0]),
 
122
                                ['line 1',
 
123
                                 'new line']))
 
124
 
 
125
        self.log('raw changes: ' + pformat(changes))
 
126
 
 
127
        # currently there are 3 lines in the weave, and we insert after them
 
128
        self.assertEquals(changes,
 
129
                          [(3, 3, ['new line'])])
 
130
 
 
131
        changes = k._delta(set([0]),
 
132
                           ['top line',
 
133
                            'line 1'])
 
134
        
 
135
        self.assertEquals(list(changes),
 
136
                          [(1, 1, ['top line'])])
 
137
 
 
138
        self.check_read_write(k)
 
139
 
129
140
 
130
141
class InvalidAdd(TestBase):
131
142
    """Try to use invalid version number during add."""
134
145
 
135
146
        self.assertRaises(IndexError,
136
147
                          k.add,
137
 
                          'text0',
138
148
                          [69],
139
149
                          ['new text!'])
140
150
 
141
151
 
142
 
class RepeatedAdd(TestBase):
143
 
    """Add the same version twice; harmless."""
144
 
    def runTest(self):
145
 
        k = Weave()
146
 
        idx = k.add('text0', [], TEXT_0)
147
 
        idx2 = k.add('text0', [], TEXT_0)
148
 
        self.assertEqual(idx, idx2)
149
 
 
150
 
 
151
 
class InvalidRepeatedAdd(TestBase):
152
 
    def runTest(self):
153
 
        k = Weave()
154
 
        idx = k.add('text0', [], TEXT_0)
155
 
        self.assertRaises(WeaveError,
156
 
                          k.add,
157
 
                          'text0',
158
 
                          [],
159
 
                          ['not the same text'])
160
 
        self.assertRaises(WeaveError,
161
 
                          k.add,
162
 
                          'text0',
163
 
                          [12],         # not the right parents
164
 
                          TEXT_0)
165
 
        
166
 
 
167
152
class InsertLines(TestBase):
168
153
    """Store a revision that adds one line to the original.
169
154
 
172
157
    def runTest(self):
173
158
        k = Weave()
174
159
 
175
 
        k.add('text0', [], ['line 1'])
176
 
        k.add('text1', [0], ['line 1', 'line 2'])
 
160
        k.add([], ['line 1'])
 
161
        k.add([0], ['line 1', 'line 2'])
177
162
 
178
163
        self.assertEqual(k.annotate(0),
179
164
                         [(0, 'line 1')])
186
171
                         [(0, 'line 1'),
187
172
                          (1, 'line 2')])
188
173
 
189
 
        k.add('text2', [0], ['line 1', 'diverged line'])
 
174
        k.add([0], ['line 1', 'diverged line'])
190
175
 
191
176
        self.assertEqual(k.annotate(2),
192
177
                         [(0, 'line 1'),
193
178
                          (2, 'diverged line')])
194
179
 
195
180
        text3 = ['line 1', 'middle line', 'line 2']
196
 
        k.add('text3',
197
 
              [0, 1],
 
181
        k.add([0, 1],
198
182
              text3)
199
183
 
200
 
        # self.log("changes to text3: " + pformat(list(k._delta(set([0, 1]), text3))))
 
184
        self.log("changes to text3: " + pformat(list(k._delta(set([0, 1]), text3))))
201
185
 
202
 
        self.log("k._weave=" + pformat(k._weave))
 
186
        self.log("k._l=" + pformat(k._l))
203
187
 
204
188
        self.assertEqual(k.annotate(3),
205
189
                         [(0, 'line 1'),
207
191
                          (1, 'line 2')])
208
192
 
209
193
        # now multiple insertions at different places
210
 
        k.add('text4',
211
 
              [0, 1, 3],
 
194
        k.add([0, 1, 3],
212
195
              ['line 1', 'aaa', 'middle line', 'bbb', 'line 2', 'ccc'])
213
196
 
214
197
        self.assertEqual(k.annotate(4), 
220
203
                          (4, 'ccc')])
221
204
 
222
205
 
 
206
 
223
207
class DeleteLines(TestBase):
224
208
    """Deletion of lines from existing text.
225
209
 
229
213
 
230
214
        base_text = ['one', 'two', 'three', 'four']
231
215
 
232
 
        k.add('text0', [], base_text)
 
216
        k.add([], base_text)
233
217
        
234
218
        texts = [['one', 'two', 'three'],
235
219
                 ['two', 'three', 'four'],
237
221
                 ['one', 'two', 'three', 'four'],
238
222
                 ]
239
223
 
240
 
        i = 1
241
224
        for t in texts:
242
 
            ver = k.add('text%d' % i,
243
 
                        [0], t)
244
 
            i += 1
 
225
            ver = k.add([0], t)
245
226
 
246
227
        self.log('final weave:')
247
 
        self.log('k._weave=' + pformat(k._weave))
 
228
        self.log('k._l=' + pformat(k._l))
248
229
 
249
230
        for i in range(len(texts)):
250
231
            self.assertEqual(k.get(i+1),
251
232
                             texts[i])
 
233
            
 
234
 
252
235
 
253
236
 
254
237
class SuicideDelete(TestBase):
256
239
    def runTest(self):
257
240
        k = Weave()
258
241
 
259
 
        k._parents = [(),
 
242
        k._v = [(),
260
243
                ]
261
 
        k._weave = [('{', 0),
 
244
        k._l = [('{', 0),
262
245
                'first line',
263
246
                ('[', 0),
264
247
                'deleted in 0',
265
248
                (']', 0),
266
249
                ('}', 0),
267
250
                ]
268
 
        ################################### SKIPPED
269
 
        # Weave.get doesn't trap this anymore
270
 
        return 
271
251
 
272
252
        self.assertRaises(WeaveFormatError,
273
253
                          k.get,
274
254
                          0)        
275
255
 
276
256
 
 
257
 
277
258
class CannedDelete(TestBase):
278
259
    """Unpack canned weave with deleted lines."""
279
260
    def runTest(self):
280
261
        k = Weave()
281
262
 
282
 
        k._parents = [(),
 
263
        k._v = [(),
283
264
                frozenset([0]),
284
265
                ]
285
 
        k._weave = [('{', 0),
 
266
        k._l = [('{', 0),
286
267
                'first line',
287
268
                ('[', 1),
288
269
                'line to be deleted',
290
271
                'last line',
291
272
                ('}', 0),
292
273
                ]
293
 
        k._sha1s = [sha_string('first lineline to be deletedlast line')
294
 
                  , sha_string('first linelast line')]
295
274
 
296
275
        self.assertEqual(k.get(0),
297
276
                         ['first line',
305
284
                          ])
306
285
 
307
286
 
 
287
 
308
288
class CannedReplacement(TestBase):
309
289
    """Unpack canned weave with deleted lines."""
310
290
    def runTest(self):
311
291
        k = Weave()
312
292
 
313
 
        k._parents = [frozenset(),
 
293
        k._v = [frozenset(),
314
294
                frozenset([0]),
315
295
                ]
316
 
        k._weave = [('{', 0),
 
296
        k._l = [('{', 0),
317
297
                'first line',
318
298
                ('[', 1),
319
299
                'line to be deleted',
324
304
                'last line',
325
305
                ('}', 0),
326
306
                ]
327
 
        k._sha1s = [sha_string('first lineline to be deletedlast line')
328
 
                  , sha_string('first linereplacement linelast line')]
329
307
 
330
308
        self.assertEqual(k.get(0),
331
309
                         ['first line',
340
318
                          ])
341
319
 
342
320
 
 
321
 
343
322
class BadWeave(TestBase):
344
323
    """Test that we trap an insert which should not occur."""
345
324
    def runTest(self):
346
325
        k = Weave()
347
326
 
348
 
        k._parents = [frozenset(),
 
327
        k._v = [frozenset(),
349
328
                ]
350
 
        k._weave = ['bad line',
 
329
        k._l = ['bad line',
351
330
                ('{', 0),
352
331
                'foo {',
353
332
                ('{', 1),
360
339
                '}',
361
340
                ('}', 0)]
362
341
 
363
 
        ################################### SKIPPED
364
 
        # Weave.get doesn't trap this anymore
365
 
        return 
366
 
 
367
 
 
368
342
        self.assertRaises(WeaveFormatError,
369
343
                          k.get,
370
344
                          0)
375
349
    def runTest(self):
376
350
        k = Weave()
377
351
 
378
 
        k._parents = [frozenset(),
 
352
        k._v = [frozenset(),
379
353
                frozenset([0]),
380
354
                frozenset([0]),
381
355
                frozenset([0,1,2]),
382
356
                ]
383
 
        k._weave = [('{', 0),
 
357
        k._l = [('{', 0),
384
358
                'foo {',
385
359
                ('{', 1),
386
360
                '  added in version 1',
390
364
                ('}', 1),
391
365
                ('}', 0)]
392
366
 
393
 
 
394
 
        # this is not currently enforced by get
395
 
        return  ##########################################
396
 
 
397
367
        self.assertRaises(WeaveFormatError,
398
368
                          k.get,
399
369
                          0)
408
378
    def runTest(self):
409
379
        k = Weave()
410
380
 
411
 
        k._parents = [frozenset(),
 
381
        k._v = [frozenset(),
412
382
                frozenset([0]),
413
383
                frozenset([0]),
414
384
                frozenset([0,1,2]),
415
385
                ]
416
 
        k._weave = [('{', 0),
 
386
        k._l = [('{', 0),
417
387
                'foo {',
418
388
                ('{', 1),
419
389
                '  added in version 1',
425
395
                '}',
426
396
                ('}', 0)]
427
397
 
428
 
        k._sha1s = [sha_string('foo {}')
429
 
                  , sha_string('foo {  added in version 1  also from v1}')
430
 
                  , sha_string('foo {  added in v2}')
431
 
                  , sha_string('foo {  added in version 1  added in v2  also from v1}')
432
 
                  ]
433
 
 
434
398
        self.assertEqual(k.get(0),
435
399
                         ['foo {',
436
400
                          '}'])
454
418
                          '}'])
455
419
                         
456
420
 
 
421
 
457
422
class DeleteLines2(TestBase):
458
423
    """Test recording revisions that delete lines.
459
424
 
462
427
    def runTest(self):
463
428
        k = Weave()
464
429
 
465
 
        k.add('text0', [], ["line the first",
 
430
        k.add([], ["line the first",
466
431
                   "line 2",
467
432
                   "line 3",
468
433
                   "fine"])
469
434
 
470
435
        self.assertEqual(len(k.get(0)), 4)
471
436
 
472
 
        k.add('text1', [0], ["line the first",
 
437
        k.add([0], ["line the first",
473
438
                   "fine"])
474
439
 
475
440
        self.assertEqual(k.get(1),
481
446
                          (0, "fine")])
482
447
 
483
448
 
 
449
 
484
450
class IncludeVersions(TestBase):
485
451
    """Check texts that are stored across multiple revisions.
486
452
 
494
460
    def runTest(self):
495
461
        k = Weave()
496
462
 
497
 
        k._parents = [frozenset(), frozenset([0])]
498
 
        k._weave = [('{', 0),
 
463
        k._v = [frozenset(), frozenset([0])]
 
464
        k._l = [('{', 0),
499
465
                "first line",
500
466
                ('}', 0),
501
467
                ('{', 1),
502
468
                "second line",
503
469
                ('}', 1)]
504
470
 
505
 
        k._sha1s = [sha_string('first line')
506
 
                  , sha_string('first linesecond line')]
507
 
 
508
471
        self.assertEqual(k.get(1),
509
472
                         ["first line",
510
473
                          "second line"])
512
475
        self.assertEqual(k.get(0),
513
476
                         ["first line"])
514
477
 
 
478
        k.dump(self.TEST_LOG)
 
479
 
515
480
 
516
481
class DivergedIncludes(TestBase):
517
482
    """Weave with two diverged texts based on version 0.
519
484
    def runTest(self):
520
485
        k = Weave()
521
486
 
522
 
        k._parents = [frozenset(),
 
487
        k._v = [frozenset(),
523
488
                frozenset([0]),
524
489
                frozenset([0]),
525
490
                ]
526
 
        k._weave = [('{', 0),
 
491
        k._l = [('{', 0),
527
492
                "first line",
528
493
                ('}', 0),
529
494
                ('{', 1),
534
499
                ('}', 2),                
535
500
                ]
536
501
 
537
 
        k._sha1s = [sha_string('first line')
538
 
                  , sha_string('first linesecond line')
539
 
                  , sha_string('first linealternative second line')]
540
 
 
541
502
        self.assertEqual(k.get(0),
542
503
                         ["first line"])
543
504
 
549
510
                         ["first line",
550
511
                          "alternative second line"])
551
512
 
552
 
        self.assertEqual(list(k.inclusions([2])),
553
 
                         [0, 2])
 
513
        self.assertEqual(k.inclusions([2]),
 
514
                         set([0, 2]))
 
515
 
554
516
 
555
517
 
556
518
class ReplaceLine(TestBase):
560
522
        text0 = ['cheddar', 'stilton', 'gruyere']
561
523
        text1 = ['cheddar', 'blue vein', 'neufchatel', 'chevre']
562
524
        
563
 
        k.add('text0', [], text0)
564
 
        k.add('text1', [0], text1)
 
525
        k.add([], text0)
 
526
        k.add([0], text1)
565
527
 
566
 
        self.log('k._weave=' + pformat(k._weave))
 
528
        self.log('k._l=' + pformat(k._l))
567
529
 
568
530
        self.assertEqual(k.get(0), text0)
569
531
        self.assertEqual(k.get(1), text1)
570
532
 
571
533
 
 
534
 
572
535
class Merge(TestBase):
573
536
    """Storage of versions that merge diverged parents"""
574
537
    def runTest(self):
580
543
                 ['header', '', 'line from 1', 'fixup line', 'line from 2'],
581
544
                 ]
582
545
 
583
 
        k.add('text0', [], texts[0])
584
 
        k.add('text1', [0], texts[1])
585
 
        k.add('text2', [0], texts[2])
586
 
        k.add('merge', [0, 1, 2], texts[3])
 
546
        k.add([], texts[0])
 
547
        k.add([0], texts[1])
 
548
        k.add([0], texts[2])
 
549
        k.add([0, 1, 2], texts[3])
587
550
 
588
551
        for i, t in enumerate(texts):
589
552
            self.assertEqual(k.get(i), t)
596
559
                          (2, 'line from 2'),
597
560
                          ])
598
561
 
599
 
        self.assertEqual(list(k.inclusions([3])),
600
 
                         [0, 1, 2, 3])
 
562
        self.assertEqual(k.inclusions([3]),
 
563
                         set([0, 1, 2, 3]))
601
564
 
602
 
        self.log('k._weave=' + pformat(k._weave))
 
565
        self.log('k._l=' + pformat(k._l))
603
566
 
604
567
        self.check_read_write(k)
605
568
 
625
588
                           [['bbb']]])
626
589
 
627
590
 
 
591
 
628
592
class NonConflict(TestBase):
629
593
    """Two descendants insert compatible changes.
630
594
 
637
601
        k.add([0], ['111', 'aaa', 'ccc', 'bbb'])
638
602
        k.add([1], ['aaa', 'ccc', 'bbb', '222'])
639
603
 
 
604
    
 
605
    
 
606
 
640
607
 
641
608
class AutoMerge(TestBase):
642
609
    def runTest(self):
647
614
                 ['header', 'aaa', 'bbb', 'line from 2', 'more from 2'],
648
615
                 ]
649
616
 
650
 
        k.add('text0', [], texts[0])
651
 
        k.add('text1', [0], texts[1])
652
 
        k.add('text2', [0], texts[2])
 
617
        k.add([], texts[0])
 
618
        k.add([0], texts[1])
 
619
        k.add([0], texts[2])
653
620
 
654
 
        self.log('k._weave=' + pformat(k._weave))
 
621
        self.log('k._l=' + pformat(k._l))
655
622
 
656
623
        m = list(k.mash_iter([0, 1, 2]))
657
624
 
660
627
                          'line from 1',
661
628
                          'bbb',
662
629
                          'line from 2', 'more from 2'])
 
630
        
663
631
 
664
632
 
665
633
class Khayyam(TestBase):
694
662
 
695
663
        k = Weave()
696
664
        parents = set()
697
 
        i = 0
698
665
        for t in texts:
699
 
            ver = k.add('text%d' % i,
700
 
                        list(parents), t)
 
666
            ver = k.add(list(parents), t)
701
667
            parents.add(ver)
702
 
            i += 1
703
668
 
704
 
        self.log("k._weave=" + pformat(k._weave))
 
669
        self.log("k._l=" + pformat(k._l))
705
670
 
706
671
        for i, t in enumerate(texts):
707
672
            self.assertEqual(k.get(i), t)
709
674
        self.check_read_write(k)
710
675
 
711
676
 
712
 
class MergeCases(TestBase):
713
 
    def doMerge(self, base, a, b, mp):
714
 
        from cStringIO import StringIO
715
 
        from textwrap import dedent
716
 
 
717
 
        def addcrlf(x):
718
 
            return x + '\n'
719
 
        
720
 
        w = Weave()
721
 
        w.add('text0', [], map(addcrlf, base))
722
 
        w.add('text1', [0], map(addcrlf, a))
723
 
        w.add('text2', [0], map(addcrlf, b))
724
 
 
725
 
        self.log('weave is:')
726
 
        tmpf = StringIO()
727
 
        write_weave(w, tmpf)
728
 
        self.log(tmpf.getvalue())
729
 
 
730
 
        self.log('merge plan:')
731
 
        p = list(w.plan_merge(1, 2))
732
 
        for state, line in p:
733
 
            if line:
734
 
                self.log('%12s | %s' % (state, line[:-1]))
735
 
 
736
 
        self.log('merge:')
737
 
        mt = StringIO()
738
 
        mt.writelines(w.weave_merge(p))
739
 
        mt.seek(0)
740
 
        self.log(mt.getvalue())
741
 
 
742
 
        mp = map(addcrlf, mp)
743
 
        self.assertEqual(mt.readlines(), mp)
744
 
        
745
 
        
746
 
    def testOneInsert(self):
747
 
        self.doMerge([],
748
 
                     ['aa'],
749
 
                     [],
750
 
                     ['aa'])
751
 
 
752
 
    def testSeparateInserts(self):
753
 
        self.doMerge(['aaa', 'bbb', 'ccc'],
754
 
                     ['aaa', 'xxx', 'bbb', 'ccc'],
755
 
                     ['aaa', 'bbb', 'yyy', 'ccc'],
756
 
                     ['aaa', 'xxx', 'bbb', 'yyy', 'ccc'])
757
 
 
758
 
    def testSameInsert(self):
759
 
        self.doMerge(['aaa', 'bbb', 'ccc'],
760
 
                     ['aaa', 'xxx', 'bbb', 'ccc'],
761
 
                     ['aaa', 'xxx', 'bbb', 'yyy', 'ccc'],
762
 
                     ['aaa', 'xxx', 'bbb', 'yyy', 'ccc'])
763
 
 
764
 
    def testOverlappedInsert(self):
765
 
        self.doMerge(['aaa', 'bbb'],
766
 
                     ['aaa', 'xxx', 'yyy', 'bbb'],
767
 
                     ['aaa', 'xxx', 'bbb'],
768
 
                     ['aaa', '<<<<<<<', 'xxx', 'yyy', '=======', 'xxx', 
769
 
                      '>>>>>>>', 'bbb'])
770
 
 
771
 
        # really it ought to reduce this to 
772
 
        # ['aaa', 'xxx', 'yyy', 'bbb']
773
 
 
774
 
 
775
 
    def testClashReplace(self):
776
 
        self.doMerge(['aaa'],
777
 
                     ['xxx'],
778
 
                     ['yyy', 'zzz'],
779
 
                     ['<<<<<<<', 'xxx', '=======', 'yyy', 'zzz', 
780
 
                      '>>>>>>>'])
781
 
 
782
 
    def testNonClashInsert(self):
783
 
        self.doMerge(['aaa'],
784
 
                     ['xxx', 'aaa'],
785
 
                     ['yyy', 'zzz'],
786
 
                     ['<<<<<<<', 'xxx', 'aaa', '=======', 'yyy', 'zzz', 
787
 
                      '>>>>>>>'])
788
 
 
789
 
        self.doMerge(['aaa'],
790
 
                     ['aaa'],
791
 
                     ['yyy', 'zzz'],
792
 
                     ['yyy', 'zzz'])
793
 
 
794
 
 
795
 
    def testDeleteAndModify(self):
796
 
        """Clashing delete and modification.
797
 
 
798
 
        If one side modifies a region and the other deletes it then
799
 
        there should be a conflict with one side blank.
800
 
        """
801
 
 
802
 
        #######################################
803
 
        # skippd, not working yet
804
 
        return
805
 
        
806
 
        self.doMerge(['aaa', 'bbb', 'ccc'],
807
 
                     ['aaa', 'ddd', 'ccc'],
808
 
                     ['aaa', 'ccc'],
809
 
                     ['<<<<<<<<', 'aaa', '=======', '>>>>>>>', 'ccc'])
810
 
 
811
 
 
812
 
class JoinWeavesTests(TestBase):
813
 
    def setUp(self):
814
 
        super(JoinWeavesTests, self).setUp()
815
 
        self.weave1 = Weave()
816
 
        self.lines1 = ['hello\n']
817
 
        self.lines3 = ['hello\n', 'cruel\n', 'world\n']
818
 
        self.weave1.add('v1', [], self.lines1)
819
 
        self.weave1.add('v2', [0], ['hello\n', 'world\n'])
820
 
        self.weave1.add('v3', [1], self.lines3)
821
 
        
822
 
    def test_join_empty(self):
823
 
        """Join two empty weaves."""
824
 
        eq = self.assertEqual
825
 
        w1 = Weave()
826
 
        w2 = Weave()
827
 
        w1.join(w2)
828
 
        eq(w1.numversions(), 0)
829
 
        
830
 
    def test_join_empty_to_nonempty(self):
831
 
        """Join empty weave onto nonempty."""
832
 
        self.weave1.join(Weave())
833
 
        self.assertEqual(len(self.weave1), 3)
834
 
 
835
 
    def test_join_unrelated(self):
836
 
        """Join two weaves with no history in common."""
837
 
        wb = Weave()
838
 
        wb.add('b1', [], ['line from b\n'])
839
 
        w1 = self.weave1
840
 
        w1.join(wb)
841
 
        eq = self.assertEqual
842
 
        eq(len(w1), 4)
843
 
        eq(sorted(list(w1.iter_names())),
844
 
           ['b1', 'v1', 'v2', 'v3'])
845
 
 
846
 
    def test_join_related(self):
847
 
        wa = self.weave1.copy()
848
 
        wb = self.weave1.copy()
849
 
        wa.add('a1', ['v3'], ['hello\n', 'sweet\n', 'world\n'])
850
 
        wb.add('b1', ['v3'], ['hello\n', 'pale blue\n', 'world\n'])
851
 
        eq = self.assertEquals
852
 
        eq(len(wa), 4)
853
 
        eq(len(wb), 4)
854
 
        wa.join(wb)
855
 
        eq(len(wa), 5)
856
 
        eq(wa.get_lines('b1'),
857
 
           ['hello\n', 'pale blue\n', 'world\n'])
858
 
 
859
 
    def test_join_parent_disagreement(self):
860
 
        """Cannot join weaves with different parents for a version."""
861
 
        wa = Weave()
862
 
        wb = Weave()
863
 
        wa.add('v1', [], ['hello\n'])
864
 
        wb.add('v0', [], [])
865
 
        wb.add('v1', ['v0'], ['hello\n'])
866
 
        self.assertRaises(WeaveError,
867
 
                          wa.join, wb)
868
 
 
869
 
    def test_join_text_disagreement(self):
870
 
        """Cannot join weaves with different texts for a version."""
871
 
        wa = Weave()
872
 
        wb = Weave()
873
 
        wa.add('v1', [], ['hello\n'])
874
 
        wb.add('v1', [], ['not\n', 'hello\n'])
875
 
        self.assertRaises(WeaveError,
876
 
                          wa.join, wb)
877
 
 
878
 
    def test_join_unordered(self):
879
 
        """Join weaves where indexes differ.
880
 
        
881
 
        The source weave contains a different version at index 0."""
882
 
        wa = self.weave1.copy()
883
 
        wb = Weave()
884
 
        wb.add('x1', [], ['line from x1\n'])
885
 
        wb.add('v1', [], ['hello\n'])
886
 
        wb.add('v2', ['v1'], ['hello\n', 'world\n'])
887
 
        wa.join(wb)
888
 
        eq = self.assertEquals
889
 
        eq(sorted(wa.iter_names()), ['v1', 'v2', 'v3', 'x1',])
890
 
        eq(wa.get_text('x1'), 'line from x1\n')
891
 
 
892
 
 
893
 
class Corruption(TestCase):
894
 
 
895
 
    def test_detection(self):
896
 
        # Test weaves detect corruption.
897
 
        #
898
 
        # Weaves contain a checksum of their texts.
899
 
        # When a text is extracted, this checksum should be
900
 
        # verified.
901
 
 
902
 
        w = Weave()
903
 
        w.add('v1', [], ['hello\n'])
904
 
        w.add('v2', ['v1'], ['hello\n', 'there\n'])
905
 
 
906
 
        # We are going to invasively corrupt the text
907
 
        # Make sure the internals of weave are the same
908
 
        self.assertEqual([('{', 0)
909
 
                        , 'hello\n'
910
 
                        , ('}', None)
911
 
                        , ('{', 1)
912
 
                        , 'there\n'
913
 
                        , ('}', None)
914
 
                        ], w._weave)
915
 
 
916
 
        self.assertEqual(['f572d396fae9206628714fb2ce00f72e94f2258f'
917
 
                        , '90f265c6e75f1c8f9ab76dcf85528352c5f215ef'
918
 
                        ], w._sha1s)
919
 
        w.check()
920
 
 
921
 
        # Corrupted
922
 
        w._weave[4] = 'There\n'
923
 
 
924
 
        self.assertEqual('hello\n', w.get_text('v1'))
925
 
        self.assertRaises(errors.WeaveInvalidChecksum, w.get_text, 'v2')
926
 
        self.assertRaises(errors.WeaveInvalidChecksum, w.get_lines, 'v2')
927
 
        self.assertRaises(errors.WeaveInvalidChecksum, list, w.get_iter('v2'))
928
 
        self.assertRaises(errors.WeaveInvalidChecksum, w.check)
929
 
 
930
 
        # Corrected
931
 
        w._weave[4] = 'there\n'
932
 
        self.assertEqual('hello\nthere\n', w.get_text('v2'))
933
 
 
934
 
        #Invalid checksum, first digit changed
935
 
        w._sha1s[1] =  'f0f265c6e75f1c8f9ab76dcf85528352c5f215ef'
936
 
 
937
 
        self.assertEqual('hello\n', w.get_text('v1'))
938
 
        self.assertRaises(errors.WeaveInvalidChecksum, w.get_text, 'v2')
939
 
        self.assertRaises(errors.WeaveInvalidChecksum, w.get_lines, 'v2')
940
 
        self.assertRaises(errors.WeaveInvalidChecksum, list, w.get_iter('v2'))
941
 
        self.assertRaises(errors.WeaveInvalidChecksum, w.check)
942
 
 
943
 
    def test_written_detection(self):
944
 
        # Test detection of weave file corruption.
945
 
        #
946
 
        # Make sure that we can detect if a weave file has
947
 
        # been corrupted. This doesn't test all forms of corruption,
948
 
        # but it at least helps verify the data you get, is what you want.
949
 
        from cStringIO import StringIO
950
 
 
951
 
        w = Weave()
952
 
        w.add('v1', [], ['hello\n'])
953
 
        w.add('v2', ['v1'], ['hello\n', 'there\n'])
954
 
 
955
 
        tmpf = StringIO()
956
 
        write_weave(w, tmpf)
957
 
 
958
 
        # Because we are corrupting, we need to make sure we have the exact text
959
 
        self.assertEquals('# bzr weave file v5\n'
960
 
                          'i\n1 f572d396fae9206628714fb2ce00f72e94f2258f\nn v1\n\n'
961
 
                          'i 0\n1 90f265c6e75f1c8f9ab76dcf85528352c5f215ef\nn v2\n\n'
962
 
                          'w\n{ 0\n. hello\n}\n{ 1\n. there\n}\nW\n',
963
 
                          tmpf.getvalue())
964
 
 
965
 
        # Change a single letter
966
 
        tmpf = StringIO('# bzr weave file v5\n'
967
 
                        'i\n1 f572d396fae9206628714fb2ce00f72e94f2258f\nn v1\n\n'
968
 
                        'i 0\n1 90f265c6e75f1c8f9ab76dcf85528352c5f215ef\nn v2\n\n'
969
 
                        'w\n{ 0\n. hello\n}\n{ 1\n. There\n}\nW\n')
970
 
 
971
 
        w = read_weave(tmpf)
972
 
 
973
 
        self.assertEqual('hello\n', w.get_text('v1'))
974
 
        self.assertRaises(errors.WeaveInvalidChecksum, w.get_text, 'v2')
975
 
        self.assertRaises(errors.WeaveInvalidChecksum, w.get_lines, 'v2')
976
 
        self.assertRaises(errors.WeaveInvalidChecksum, list, w.get_iter('v2'))
977
 
        self.assertRaises(errors.WeaveInvalidChecksum, w.check)
978
 
 
979
 
        # Change the sha checksum
980
 
        tmpf = StringIO('# bzr weave file v5\n'
981
 
                        'i\n1 f572d396fae9206628714fb2ce00f72e94f2258f\nn v1\n\n'
982
 
                        'i 0\n1 f0f265c6e75f1c8f9ab76dcf85528352c5f215ef\nn v2\n\n'
983
 
                        'w\n{ 0\n. hello\n}\n{ 1\n. there\n}\nW\n')
984
 
 
985
 
        w = read_weave(tmpf)
986
 
 
987
 
        self.assertEqual('hello\n', w.get_text('v1'))
988
 
        self.assertRaises(errors.WeaveInvalidChecksum, w.get_text, 'v2')
989
 
        self.assertRaises(errors.WeaveInvalidChecksum, w.get_lines, 'v2')
990
 
        self.assertRaises(errors.WeaveInvalidChecksum, list, w.get_iter('v2'))
991
 
        self.assertRaises(errors.WeaveInvalidChecksum, w.check)
992
 
 
993
 
 
 
677
def testweave():
 
678
    import testsweet
 
679
    from unittest import TestSuite, TestLoader
 
680
    import testweave
 
681
 
 
682
    tl = TestLoader()
 
683
    suite = TestSuite()
 
684
    suite.addTest(tl.loadTestsFromModule(testweave))
 
685
    
 
686
    return int(not testsweet.run_suite(suite)) # for shell 0=true
 
687
 
 
688
 
 
689
if __name__ == '__main__':
 
690
    import sys
 
691
    sys.exit(testweave())
 
692