/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_weave.py

  • Committer: Robert Collins
  • Date: 2007-07-15 15:40:37 UTC
  • mto: (2592.3.33 repository)
  • mto: This revision was merged to the branch mainline in revision 2624.
  • Revision ID: robertc@robertcollins.net-20070715154037-3ar8g89decddc9su
Make GraphIndex accept nodes as key, value, references, so that the method
signature is closer to what a simple key->value index delivers. Also
change the behaviour when the reference list count is zero to accept
key, value as nodes, and emit key, value to make it identical in that case
to a simple key->value index. This may not be a good idea, but for now it
seems ok.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#! /usr/bin/python2.4
 
2
 
1
3
# Copyright (C) 2005 Canonical Ltd
2
4
#
3
5
# This program is free software; you can redistribute it and/or modify
12
14
#
13
15
# You should have received a copy of the GNU General Public License
14
16
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
17
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
18
 
17
19
 
18
20
# TODO: tests regarding version names
19
 
# TODO: rbc 20050108 test that join does not leave an inconsistent weave
 
21
# TODO: rbc 20050108 test that join does not leave an inconsistent weave 
20
22
#       if it fails.
21
23
 
22
24
"""test suite for weave algorithm"""
28
30
    )
29
31
from bzrlib.osutils import sha_string
30
32
from bzrlib.tests import TestCase, TestCaseInTempDir
31
 
from bzrlib.weave import Weave, WeaveFormatError, WeaveError
 
33
from bzrlib.weave import Weave, WeaveFormatError, WeaveError, reweave
32
34
from bzrlib.weavefile import write_weave, read_weave
33
35
 
34
36
 
39
41
 
40
42
 
41
43
class TestBase(TestCase):
42
 
 
43
44
    def check_read_write(self, k):
44
45
        """Check the weave k can be written & re-read."""
45
46
        from tempfile import TemporaryFile
65
66
class WeaveContains(TestBase):
66
67
    """Weave __contains__ operator"""
67
68
    def runTest(self):
68
 
        k = Weave(get_scope=lambda:None)
 
69
        k = Weave()
69
70
        self.assertFalse('foo' in k)
70
71
        k.add_lines('foo', [], TEXT_1)
71
72
        self.assertTrue('foo' in k)
76
77
        k = Weave()
77
78
 
78
79
 
 
80
class StoreText(TestBase):
 
81
    """Store and retrieve a simple text."""
 
82
 
 
83
    def test_storing_text(self):
 
84
        k = Weave()
 
85
        idx = k.add_lines('text0', [], TEXT_0)
 
86
        self.assertEqual(k.get_lines(idx), TEXT_0)
 
87
        self.assertEqual(idx, 0)
 
88
 
 
89
 
79
90
class AnnotateOne(TestBase):
80
91
    def runTest(self):
81
92
        k = Weave()
84
95
                         [('text0', TEXT_0[0])])
85
96
 
86
97
 
 
98
class StoreTwo(TestBase):
 
99
    def runTest(self):
 
100
        k = Weave()
 
101
 
 
102
        idx = k.add_lines('text0', [], TEXT_0)
 
103
        self.assertEqual(idx, 0)
 
104
 
 
105
        idx = k.add_lines('text1', [], TEXT_1)
 
106
        self.assertEqual(idx, 1)
 
107
 
 
108
        self.assertEqual(k.get_lines(0), TEXT_0)
 
109
        self.assertEqual(k.get_lines(1), TEXT_1)
 
110
 
 
111
 
 
112
class GetSha1(TestBase):
 
113
    def test_get_sha1(self):
 
114
        k = Weave()
 
115
        k.add_lines('text0', [], 'text0')
 
116
        self.assertEqual('34dc0e430c642a26c3dd1c2beb7a8b4f4445eb79',
 
117
                         k.get_sha1('text0'))
 
118
        self.assertRaises(errors.RevisionNotPresent,
 
119
                          k.get_sha1, 0)
 
120
        self.assertRaises(errors.RevisionNotPresent,
 
121
                          k.get_sha1, 'text1')
 
122
                        
 
123
 
87
124
class InvalidAdd(TestBase):
88
125
    """Try to use invalid version number during add."""
89
126
    def runTest(self):
98
135
 
99
136
class RepeatedAdd(TestBase):
100
137
    """Add the same version twice; harmless."""
101
 
 
102
 
    def test_duplicate_add(self):
 
138
    def runTest(self):
103
139
        k = Weave()
104
140
        idx = k.add_lines('text0', [], TEXT_0)
105
141
        idx2 = k.add_lines('text0', [], TEXT_0)
121
157
                          'text0',
122
158
                          ['basis'],         # not the right parents
123
159
                          TEXT_0)
124
 
 
 
160
        
125
161
 
126
162
class InsertLines(TestBase):
127
163
    """Store a revision that adds one line to the original.
170
206
              ['text0', 'text1', 'text3'],
171
207
              ['line 1', 'aaa', 'middle line', 'bbb', 'line 2', 'ccc'])
172
208
 
173
 
        self.assertEqual(k.annotate('text4'),
 
209
        self.assertEqual(k.annotate('text4'), 
174
210
                         [('text0', 'line 1'),
175
211
                          ('text4', 'aaa'),
176
212
                          ('text3', 'middle line'),
189
225
        base_text = ['one', 'two', 'three', 'four']
190
226
 
191
227
        k.add_lines('text0', [], base_text)
192
 
 
 
228
        
193
229
        texts = [['one', 'two', 'three'],
194
230
                 ['two', 'three', 'four'],
195
231
                 ['one', 'four'],
226
262
                ]
227
263
        ################################### SKIPPED
228
264
        # Weave.get doesn't trap this anymore
229
 
        return
 
265
        return 
230
266
 
231
267
        self.assertRaises(WeaveFormatError,
232
268
                          k.get_lines,
233
 
                          0)
 
269
                          0)        
234
270
 
235
271
 
236
272
class CannedDelete(TestBase):
278
314
                'line to be deleted',
279
315
                (']', 1),
280
316
                ('{', 1),
281
 
                'replacement line',
 
317
                'replacement line',                
282
318
                ('}', 1),
283
319
                'last line',
284
320
                ('}', 0),
321
357
 
322
358
        ################################### SKIPPED
323
359
        # Weave.get doesn't trap this anymore
324
 
        return
 
360
        return 
325
361
 
326
362
 
327
363
        self.assertRaises(WeaveFormatError,
399
435
                          '  added in version 1',
400
436
                          '  also from v1',
401
437
                          '}'])
402
 
 
 
438
                       
403
439
        self.assertEqual(k.get_lines(2),
404
440
                         ['foo {',
405
441
                          '  added in v2',
411
447
                          '  added in v2',
412
448
                          '  also from v1',
413
449
                          '}'])
414
 
 
 
450
                         
415
451
 
416
452
class DeleteLines2(TestBase):
417
453
    """Test recording revisions that delete lines.
493
529
                ('}', 1),
494
530
                ('{', 2),
495
531
                "alternative second line",
496
 
                ('}', 2),
 
532
                ('}', 2),                
497
533
                ]
498
534
 
499
535
        k._sha1s = [sha_string('first line')
521
557
 
522
558
        text0 = ['cheddar', 'stilton', 'gruyere']
523
559
        text1 = ['cheddar', 'blue vein', 'neufchatel', 'chevre']
524
 
 
 
560
        
525
561
        k.add_lines('text0', [], text0)
526
562
        k.add_lines('text1', ['text0'], text1)
527
563
 
609
645
            A Jug of Wine, a Loaf of Bread, -- and Thou
610
646
            Beside me singing in the Wilderness --
611
647
            Oh, Wilderness were Paradise enow!""",
612
 
 
 
648
            
613
649
            """A Book of Verses underneath the Bough,
614
650
            A Jug of Wine, a Loaf of Bread, -- and Thou
615
651
            Beside me singing in the Wilderness --
657
693
        self.weave1.add_lines('v1', [], self.lines1)
658
694
        self.weave1.add_lines('v2', ['v1'], ['hello\n', 'world\n'])
659
695
        self.weave1.add_lines('v3', ['v2'], self.lines3)
 
696
        
 
697
    def test_join_empty(self):
 
698
        """Join two empty weaves."""
 
699
        eq = self.assertEqual
 
700
        w1 = Weave()
 
701
        w2 = Weave()
 
702
        w1.join(w2)
 
703
        eq(len(w1), 0)
 
704
        
 
705
    def test_join_empty_to_nonempty(self):
 
706
        """Join empty weave onto nonempty."""
 
707
        self.weave1.join(Weave())
 
708
        self.assertEqual(len(self.weave1), 3)
 
709
 
 
710
    def test_join_unrelated(self):
 
711
        """Join two weaves with no history in common."""
 
712
        wb = Weave()
 
713
        wb.add_lines('b1', [], ['line from b\n'])
 
714
        w1 = self.weave1
 
715
        w1.join(wb)
 
716
        eq = self.assertEqual
 
717
        eq(len(w1), 4)
 
718
        eq(sorted(w1.versions()),
 
719
           ['b1', 'v1', 'v2', 'v3'])
 
720
 
 
721
    def test_join_related(self):
 
722
        wa = self.weave1.copy()
 
723
        wb = self.weave1.copy()
 
724
        wa.add_lines('a1', ['v3'], ['hello\n', 'sweet\n', 'world\n'])
 
725
        wb.add_lines('b1', ['v3'], ['hello\n', 'pale blue\n', 'world\n'])
 
726
        eq = self.assertEquals
 
727
        eq(len(wa), 4)
 
728
        eq(len(wb), 4)
 
729
        wa.join(wb)
 
730
        eq(len(wa), 5)
 
731
        eq(wa.get_lines('b1'),
 
732
           ['hello\n', 'pale blue\n', 'world\n'])
 
733
 
 
734
    def test_join_parent_disagreement(self):
 
735
        #join reconciles differening parents into a union.
 
736
        wa = Weave()
 
737
        wb = Weave()
 
738
        wa.add_lines('v1', [], ['hello\n'])
 
739
        wb.add_lines('v0', [], [])
 
740
        wb.add_lines('v1', ['v0'], ['hello\n'])
 
741
        wa.join(wb)
 
742
        self.assertEqual(['v0'], wa.get_parents('v1'))
 
743
 
 
744
    def test_join_text_disagreement(self):
 
745
        """Cannot join weaves with different texts for a version."""
 
746
        wa = Weave()
 
747
        wb = Weave()
 
748
        wa.add_lines('v1', [], ['hello\n'])
 
749
        wb.add_lines('v1', [], ['not\n', 'hello\n'])
 
750
        self.assertRaises(WeaveError,
 
751
                          wa.join, wb)
 
752
 
 
753
    def test_join_unordered(self):
 
754
        """Join weaves where indexes differ.
 
755
        
 
756
        The source weave contains a different version at index 0."""
 
757
        wa = self.weave1.copy()
 
758
        wb = Weave()
 
759
        wb.add_lines('x1', [], ['line from x1\n'])
 
760
        wb.add_lines('v1', [], ['hello\n'])
 
761
        wb.add_lines('v2', ['v1'], ['hello\n', 'world\n'])
 
762
        wa.join(wb)
 
763
        eq = self.assertEquals
 
764
        eq(sorted(wa.versions()), ['v1', 'v2', 'v3', 'x1',])
 
765
        eq(wa.get_text('x1'), 'line from x1\n')
660
766
 
661
767
    def test_written_detection(self):
662
768
        # Test detection of weave file corruption.
707
813
        self.assertRaises(errors.WeaveInvalidChecksum, w.check)
708
814
 
709
815
 
710
 
class TestWeave(TestCase):
711
 
 
712
 
    def test_allow_reserved_false(self):
713
 
        w = Weave('name', allow_reserved=False)
714
 
        # Add lines is checked at the WeaveFile level, not at the Weave level
715
 
        w.add_lines('name:', [], TEXT_1)
716
 
        # But get_lines is checked at this level
717
 
        self.assertRaises(errors.ReservedId, w.get_lines, 'name:')
718
 
 
719
 
    def test_allow_reserved_true(self):
720
 
        w = Weave('name', allow_reserved=True)
721
 
        w.add_lines('name:', [], TEXT_1)
722
 
        self.assertEqual(TEXT_1, w.get_lines('name:'))
723
 
 
724
 
 
725
816
class InstrumentedWeave(Weave):
726
817
    """Keep track of how many times functions are called."""
727
 
 
 
818
    
728
819
    def __init__(self, weave_name=None):
729
820
        self._extract_count = 0
730
821
        Weave.__init__(self, weave_name=weave_name)
734
825
        return Weave._extract(self, versions)
735
826
 
736
827
 
 
828
class JoinOptimization(TestCase):
 
829
    """Test that Weave.join() doesn't extract all texts, only what must be done."""
 
830
 
 
831
    def test_join(self):
 
832
        w1 = InstrumentedWeave()
 
833
        w2 = InstrumentedWeave()
 
834
 
 
835
        txt0 = ['a\n']
 
836
        txt1 = ['a\n', 'b\n']
 
837
        txt2 = ['a\n', 'c\n']
 
838
        txt3 = ['a\n', 'b\n', 'c\n']
 
839
 
 
840
        w1.add_lines('txt0', [], txt0) # extract 1a
 
841
        w2.add_lines('txt0', [], txt0) # extract 1b
 
842
        w1.add_lines('txt1', ['txt0'], txt1)# extract 2a
 
843
        w2.add_lines('txt2', ['txt0'], txt2)# extract 2b
 
844
        w1.join(w2) # extract 3a to add txt2 
 
845
        w2.join(w1) # extract 3b to add txt1 
 
846
 
 
847
        w1.add_lines('txt3', ['txt1', 'txt2'], txt3) # extract 4a 
 
848
        w2.add_lines('txt3', ['txt2', 'txt1'], txt3) # extract 4b
 
849
        # These secretly have inverted parents
 
850
 
 
851
        # This should not have to do any extractions
 
852
        w1.join(w2) # NO extract, texts already present with same parents
 
853
        w2.join(w1) # NO extract, texts already present with same parents
 
854
 
 
855
        self.assertEqual(4, w1._extract_count)
 
856
        self.assertEqual(4, w2._extract_count)
 
857
 
 
858
    def test_double_parent(self):
 
859
        # It should not be considered illegal to add
 
860
        # a revision with the same parent twice
 
861
        w1 = InstrumentedWeave()
 
862
        w2 = InstrumentedWeave()
 
863
 
 
864
        txt0 = ['a\n']
 
865
        txt1 = ['a\n', 'b\n']
 
866
        txt2 = ['a\n', 'c\n']
 
867
        txt3 = ['a\n', 'b\n', 'c\n']
 
868
 
 
869
        w1.add_lines('txt0', [], txt0)
 
870
        w2.add_lines('txt0', [], txt0)
 
871
        w1.add_lines('txt1', ['txt0'], txt1)
 
872
        w2.add_lines('txt1', ['txt0', 'txt0'], txt1)
 
873
        # Same text, effectively the same, because the
 
874
        # parent is only repeated
 
875
        w1.join(w2) # extract 3a to add txt2 
 
876
        w2.join(w1) # extract 3b to add txt1 
 
877
 
 
878
 
737
879
class TestNeedsReweave(TestCase):
738
880
    """Internal corner cases for when reweave is needed."""
739
881
 
753
895
 
754
896
 
755
897
class TestWeaveFile(TestCaseInTempDir):
756
 
 
 
898
    
757
899
    def test_empty_file(self):
758
900
        f = open('empty.weave', 'wb+')
759
901
        try: