~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_weave.py

  • Committer: Erik Bågfors
  • Date: 2006-02-03 19:50:59 UTC
  • mto: (1185.50.77 bzr-jam-integration)
  • mto: This revision was merged to the branch mainline in revision 1554.
  • Revision ID: erik@bagfors.nu-20060203195059-1cf8ff5aa68de0ea
Support for plugins to register log formatters and set default formatter
Also, change one command line option for "log"

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
 
 
 
20
# TODO: tests regarding version names
 
21
# TODO: rbc 20050108 test that join does not leave an inconsistent weave 
 
22
#       if it fails.
21
23
 
22
24
"""test suite for weave algorithm"""
23
25
 
 
26
from pprint import pformat
24
27
 
25
 
import testsweet
26
 
from bzrlib.weave import Weave, WeaveFormatError
 
28
import bzrlib.errors as errors
 
29
from bzrlib.weave import Weave, WeaveFormatError, WeaveError, reweave
27
30
from bzrlib.weavefile import write_weave, read_weave
28
 
from pprint import pformat
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
 
 
 
31
from bzrlib.tests import TestCase
 
32
from bzrlib.osutils import sha_string
40
33
 
41
34
 
42
35
# texts for use in testing
45
38
          "A second line"]
46
39
 
47
40
 
48
 
 
49
 
class TestBase(testsweet.TestBase):
 
41
class TestBase(TestCase):
50
42
    def check_read_write(self, k):
51
43
        """Check the weave k can be written & re-read."""
52
44
        from tempfile import TemporaryFile
60
52
            tf.seek(0)
61
53
            self.log('serialized weave:')
62
54
            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('')
63
61
            self.fail('read/write check failed')
64
 
        
65
 
        
 
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)
66
71
 
67
72
 
68
73
class Easy(TestBase):
74
79
    """Store and retrieve a simple text."""
75
80
    def runTest(self):
76
81
        k = Weave()
77
 
        idx = k.add([], TEXT_0)
 
82
        idx = k.add('text0', [], TEXT_0)
78
83
        self.assertEqual(k.get(idx), TEXT_0)
79
84
        self.assertEqual(idx, 0)
80
85
 
81
86
 
82
 
 
83
87
class AnnotateOne(TestBase):
84
88
    def runTest(self):
85
89
        k = Weave()
86
 
        k.add([], TEXT_0)
 
90
        k.add('text0', [], TEXT_0)
87
91
        self.assertEqual(k.annotate(0),
88
92
                         [(0, TEXT_0[0])])
89
93
 
92
96
    def runTest(self):
93
97
        k = Weave()
94
98
 
95
 
        idx = k.add([], TEXT_0)
 
99
        idx = k.add('text0', [], TEXT_0)
96
100
        self.assertEqual(idx, 0)
97
101
 
98
 
        idx = k.add([], TEXT_1)
 
102
        idx = k.add('text1', [], TEXT_1)
99
103
        self.assertEqual(idx, 1)
100
104
 
101
105
        self.assertEqual(k.get(0), TEXT_0)
102
106
        self.assertEqual(k.get(1), TEXT_1)
103
107
 
104
 
        k.dump(self.TEST_LOG)
105
 
 
106
 
 
 
108
 
 
109
class AddWithGivenSha(TestBase):
 
110
    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
                        
107
129
 
108
130
class InvalidAdd(TestBase):
109
131
    """Try to use invalid version number during add."""
112
134
 
113
135
        self.assertRaises(IndexError,
114
136
                          k.add,
 
137
                          'text0',
115
138
                          [69],
116
139
                          ['new text!'])
117
140
 
118
141
 
 
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
 
119
167
class InsertLines(TestBase):
120
168
    """Store a revision that adds one line to the original.
121
169
 
124
172
    def runTest(self):
125
173
        k = Weave()
126
174
 
127
 
        k.add([], ['line 1'])
128
 
        k.add([0], ['line 1', 'line 2'])
 
175
        k.add('text0', [], ['line 1'])
 
176
        k.add('text1', [0], ['line 1', 'line 2'])
129
177
 
130
178
        self.assertEqual(k.annotate(0),
131
179
                         [(0, 'line 1')])
138
186
                         [(0, 'line 1'),
139
187
                          (1, 'line 2')])
140
188
 
141
 
        k.add([0], ['line 1', 'diverged line'])
 
189
        k.add('text2', [0], ['line 1', 'diverged line'])
142
190
 
143
191
        self.assertEqual(k.annotate(2),
144
192
                         [(0, 'line 1'),
145
193
                          (2, 'diverged line')])
146
194
 
147
195
        text3 = ['line 1', 'middle line', 'line 2']
148
 
        k.add([0, 1],
 
196
        k.add('text3',
 
197
              [0, 1],
149
198
              text3)
150
199
 
151
200
        # self.log("changes to text3: " + pformat(list(k._delta(set([0, 1]), text3))))
158
207
                          (1, 'line 2')])
159
208
 
160
209
        # now multiple insertions at different places
161
 
        k.add([0, 1, 3],
 
210
        k.add('text4',
 
211
              [0, 1, 3],
162
212
              ['line 1', 'aaa', 'middle line', 'bbb', 'line 2', 'ccc'])
163
213
 
164
214
        self.assertEqual(k.annotate(4), 
170
220
                          (4, 'ccc')])
171
221
 
172
222
 
173
 
 
174
223
class DeleteLines(TestBase):
175
224
    """Deletion of lines from existing text.
176
225
 
180
229
 
181
230
        base_text = ['one', 'two', 'three', 'four']
182
231
 
183
 
        k.add([], base_text)
 
232
        k.add('text0', [], base_text)
184
233
        
185
234
        texts = [['one', 'two', 'three'],
186
235
                 ['two', 'three', 'four'],
188
237
                 ['one', 'two', 'three', 'four'],
189
238
                 ]
190
239
 
 
240
        i = 1
191
241
        for t in texts:
192
 
            ver = k.add([0], t)
 
242
            ver = k.add('text%d' % i,
 
243
                        [0], t)
 
244
            i += 1
193
245
 
194
246
        self.log('final weave:')
195
247
        self.log('k._weave=' + pformat(k._weave))
197
249
        for i in range(len(texts)):
198
250
            self.assertEqual(k.get(i+1),
199
251
                             texts[i])
200
 
            
201
 
 
202
252
 
203
253
 
204
254
class SuicideDelete(TestBase):
224
274
                          0)        
225
275
 
226
276
 
227
 
 
228
277
class CannedDelete(TestBase):
229
278
    """Unpack canned weave with deleted lines."""
230
279
    def runTest(self):
241
290
                'last line',
242
291
                ('}', 0),
243
292
                ]
 
293
        k._sha1s = [sha_string('first lineline to be deletedlast line')
 
294
                  , sha_string('first linelast line')]
244
295
 
245
296
        self.assertEqual(k.get(0),
246
297
                         ['first line',
254
305
                          ])
255
306
 
256
307
 
257
 
 
258
308
class CannedReplacement(TestBase):
259
309
    """Unpack canned weave with deleted lines."""
260
310
    def runTest(self):
274
324
                'last line',
275
325
                ('}', 0),
276
326
                ]
 
327
        k._sha1s = [sha_string('first lineline to be deletedlast line')
 
328
                  , sha_string('first linereplacement linelast line')]
277
329
 
278
330
        self.assertEqual(k.get(0),
279
331
                         ['first line',
288
340
                          ])
289
341
 
290
342
 
291
 
 
292
343
class BadWeave(TestBase):
293
344
    """Test that we trap an insert which should not occur."""
294
345
    def runTest(self):
374
425
                '}',
375
426
                ('}', 0)]
376
427
 
 
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
 
377
434
        self.assertEqual(k.get(0),
378
435
                         ['foo {',
379
436
                          '}'])
397
454
                          '}'])
398
455
                         
399
456
 
400
 
 
401
457
class DeleteLines2(TestBase):
402
458
    """Test recording revisions that delete lines.
403
459
 
406
462
    def runTest(self):
407
463
        k = Weave()
408
464
 
409
 
        k.add([], ["line the first",
 
465
        k.add('text0', [], ["line the first",
410
466
                   "line 2",
411
467
                   "line 3",
412
468
                   "fine"])
413
469
 
414
470
        self.assertEqual(len(k.get(0)), 4)
415
471
 
416
 
        k.add([0], ["line the first",
 
472
        k.add('text1', [0], ["line the first",
417
473
                   "fine"])
418
474
 
419
475
        self.assertEqual(k.get(1),
425
481
                          (0, "fine")])
426
482
 
427
483
 
428
 
 
429
484
class IncludeVersions(TestBase):
430
485
    """Check texts that are stored across multiple revisions.
431
486
 
447
502
                "second line",
448
503
                ('}', 1)]
449
504
 
 
505
        k._sha1s = [sha_string('first line')
 
506
                  , sha_string('first linesecond line')]
 
507
 
450
508
        self.assertEqual(k.get(1),
451
509
                         ["first line",
452
510
                          "second line"])
454
512
        self.assertEqual(k.get(0),
455
513
                         ["first line"])
456
514
 
457
 
        k.dump(self.TEST_LOG)
458
 
 
459
515
 
460
516
class DivergedIncludes(TestBase):
461
517
    """Weave with two diverged texts based on version 0.
478
534
                ('}', 2),                
479
535
                ]
480
536
 
 
537
        k._sha1s = [sha_string('first line')
 
538
                  , sha_string('first linesecond line')
 
539
                  , sha_string('first linealternative second line')]
 
540
 
481
541
        self.assertEqual(k.get(0),
482
542
                         ["first line"])
483
543
 
493
553
                         [0, 2])
494
554
 
495
555
 
496
 
 
497
556
class ReplaceLine(TestBase):
498
557
    def runTest(self):
499
558
        k = Weave()
501
560
        text0 = ['cheddar', 'stilton', 'gruyere']
502
561
        text1 = ['cheddar', 'blue vein', 'neufchatel', 'chevre']
503
562
        
504
 
        k.add([], text0)
505
 
        k.add([0], text1)
 
563
        k.add('text0', [], text0)
 
564
        k.add('text1', [0], text1)
506
565
 
507
566
        self.log('k._weave=' + pformat(k._weave))
508
567
 
510
569
        self.assertEqual(k.get(1), text1)
511
570
 
512
571
 
513
 
 
514
572
class Merge(TestBase):
515
573
    """Storage of versions that merge diverged parents"""
516
574
    def runTest(self):
522
580
                 ['header', '', 'line from 1', 'fixup line', 'line from 2'],
523
581
                 ]
524
582
 
525
 
        k.add([], texts[0])
526
 
        k.add([0], texts[1])
527
 
        k.add([0], texts[2])
528
 
        k.add([0, 1, 2], texts[3])
 
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])
529
587
 
530
588
        for i, t in enumerate(texts):
531
589
            self.assertEqual(k.get(i), t)
567
625
                           [['bbb']]])
568
626
 
569
627
 
570
 
 
571
628
class NonConflict(TestBase):
572
629
    """Two descendants insert compatible changes.
573
630
 
580
637
        k.add([0], ['111', 'aaa', 'ccc', 'bbb'])
581
638
        k.add([1], ['aaa', 'ccc', 'bbb', '222'])
582
639
 
583
 
    
584
 
    
585
 
 
586
640
 
587
641
class AutoMerge(TestBase):
588
642
    def runTest(self):
593
647
                 ['header', 'aaa', 'bbb', 'line from 2', 'more from 2'],
594
648
                 ]
595
649
 
596
 
        k.add([], texts[0])
597
 
        k.add([0], texts[1])
598
 
        k.add([0], texts[2])
 
650
        k.add('text0', [], texts[0])
 
651
        k.add('text1', [0], texts[1])
 
652
        k.add('text2', [0], texts[2])
599
653
 
600
654
        self.log('k._weave=' + pformat(k._weave))
601
655
 
606
660
                          'line from 1',
607
661
                          'bbb',
608
662
                          'line from 2', 'more from 2'])
609
 
        
610
663
 
611
664
 
612
665
class Khayyam(TestBase):
641
694
 
642
695
        k = Weave()
643
696
        parents = set()
 
697
        i = 0
644
698
        for t in texts:
645
 
            ver = k.add(list(parents), t)
 
699
            ver = k.add('text%d' % i,
 
700
                        list(parents), t)
646
701
            parents.add(ver)
 
702
            i += 1
647
703
 
648
704
        self.log("k._weave=" + pformat(k._weave))
649
705
 
653
709
        self.check_read_write(k)
654
710
 
655
711
 
656
 
 
657
712
class MergeCases(TestBase):
658
713
    def doMerge(self, base, a, b, mp):
659
714
        from cStringIO import StringIO
663
718
            return x + '\n'
664
719
        
665
720
        w = Weave()
666
 
        w.add([], map(addcrlf, base))
667
 
        w.add([0], map(addcrlf, a))
668
 
        w.add([0], map(addcrlf, b))
 
721
        w.add('text0', [], map(addcrlf, base))
 
722
        w.add('text1', [0], map(addcrlf, a))
 
723
        w.add('text2', [0], map(addcrlf, b))
669
724
 
670
725
        self.log('weave is:')
671
726
        tmpf = StringIO()
710
765
        self.doMerge(['aaa', 'bbb'],
711
766
                     ['aaa', 'xxx', 'yyy', 'bbb'],
712
767
                     ['aaa', 'xxx', 'bbb'],
713
 
                     ['aaa', '<<<<', 'xxx', 'yyy', '====', 'xxx', '>>>>', 'bbb'])
 
768
                     ['aaa', '<<<<<<<', 'xxx', 'yyy', '=======', 'xxx', 
 
769
                      '>>>>>>>', 'bbb'])
714
770
 
715
771
        # really it ought to reduce this to 
716
772
        # ['aaa', 'xxx', 'yyy', 'bbb']
720
776
        self.doMerge(['aaa'],
721
777
                     ['xxx'],
722
778
                     ['yyy', 'zzz'],
723
 
                     ['<<<<', 'xxx', '====', 'yyy', 'zzz', '>>>>'])
 
779
                     ['<<<<<<<', 'xxx', '=======', 'yyy', 'zzz', 
 
780
                      '>>>>>>>'])
724
781
 
725
782
    def testNonClashInsert(self):
726
783
        self.doMerge(['aaa'],
727
784
                     ['xxx', 'aaa'],
728
785
                     ['yyy', 'zzz'],
729
 
                     ['<<<<', 'xxx', 'aaa', '====', 'yyy', 'zzz', '>>>>'])
 
786
                     ['<<<<<<<', 'xxx', 'aaa', '=======', 'yyy', 'zzz', 
 
787
                      '>>>>>>>'])
730
788
 
731
789
        self.doMerge(['aaa'],
732
790
                     ['aaa'],
748
806
        self.doMerge(['aaa', 'bbb', 'ccc'],
749
807
                     ['aaa', 'ddd', 'ccc'],
750
808
                     ['aaa', 'ccc'],
751
 
                     ['<<<<', 'aaa', '====', '>>>>', 'ccc'])
752
 
    
753
 
 
754
 
 
755
 
def testweave():
756
 
    import testsweet
757
 
    from unittest import TestSuite, TestLoader
758
 
    import testweave
759
 
 
760
 
    tl = TestLoader()
761
 
    suite = TestSuite()
762
 
    suite.addTest(tl.loadTestsFromModule(testweave))
763
 
    
764
 
    return int(not testsweet.run_suite(suite)) # for shell 0=true
765
 
 
766
 
 
767
 
if __name__ == '__main__':
768
 
    import sys
769
 
    sys.exit(testweave())
770
 
    
 
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