/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: Michael Ellerman
  • Date: 2006-05-31 08:44:29 UTC
  • mto: (1711.2.63 jam-integration)
  • mto: This revision was merged to the branch mainline in revision 1792.
  • Revision ID: michael@ellerman.id.au-20060531084429-35e5429abda9f560
Add optional location to ancestry and fix behaviour for checkouts.

This adds an optional location parameter to the ancestry command. It also
changes the behaviour of ancestry on checkouts such that if they have
been created with a subset of the branch history, only the subset is
shown by 'bzr ancestry'. Tests for all of that as well.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005 Canonical Ltd
2
 
#
 
1
#! /usr/bin/python2.4
 
2
 
 
3
# Copyright (C) 2005 by Canonical Ltd
 
4
 
3
5
# This program is free software; you can redistribute it and/or modify
4
6
# it under the terms of the GNU General Public License as published by
5
7
# the Free Software Foundation; either version 2 of the License, or
6
8
# (at your option) any later version.
7
 
#
 
9
 
8
10
# This program is distributed in the hope that it will be useful,
9
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
13
# GNU General Public License for more details.
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"""
23
25
 
24
26
from pprint import pformat
25
27
 
26
 
from bzrlib import (
27
 
    errors,
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
29
32
from bzrlib.osutils import sha_string
30
 
from bzrlib.tests import TestCase, TestCaseInTempDir
31
 
from bzrlib.weave import Weave, WeaveFormatError, WeaveError
32
 
from bzrlib.weavefile import write_weave, read_weave
33
33
 
34
34
 
35
35
# texts for use in testing
39
39
 
40
40
 
41
41
class TestBase(TestCase):
42
 
 
43
42
    def check_read_write(self, k):
44
43
        """Check the weave k can be written & re-read."""
45
44
        from tempfile import TemporaryFile
65
64
class WeaveContains(TestBase):
66
65
    """Weave __contains__ operator"""
67
66
    def runTest(self):
68
 
        k = Weave(get_scope=lambda:None)
 
67
        k = Weave()
69
68
        self.assertFalse('foo' in k)
70
69
        k.add_lines('foo', [], TEXT_1)
71
70
        self.assertTrue('foo' in k)
76
75
        k = Weave()
77
76
 
78
77
 
 
78
class StoreText(TestBase):
 
79
    """Store and retrieve a simple text."""
 
80
 
 
81
    def test_storing_text(self):
 
82
        k = Weave()
 
83
        idx = k.add_lines('text0', [], TEXT_0)
 
84
        self.assertEqual(k.get_lines(idx), TEXT_0)
 
85
        self.assertEqual(idx, 0)
 
86
 
 
87
 
79
88
class AnnotateOne(TestBase):
80
89
    def runTest(self):
81
90
        k = Weave()
84
93
                         [('text0', TEXT_0[0])])
85
94
 
86
95
 
 
96
class StoreTwo(TestBase):
 
97
    def runTest(self):
 
98
        k = Weave()
 
99
 
 
100
        idx = k.add_lines('text0', [], TEXT_0)
 
101
        self.assertEqual(idx, 0)
 
102
 
 
103
        idx = k.add_lines('text1', [], TEXT_1)
 
104
        self.assertEqual(idx, 1)
 
105
 
 
106
        self.assertEqual(k.get_lines(0), TEXT_0)
 
107
        self.assertEqual(k.get_lines(1), TEXT_1)
 
108
 
 
109
 
 
110
class GetSha1(TestBase):
 
111
    def test_get_sha1(self):
 
112
        k = Weave()
 
113
        k.add_lines('text0', [], 'text0')
 
114
        self.assertEqual('34dc0e430c642a26c3dd1c2beb7a8b4f4445eb79',
 
115
                         k.get_sha1('text0'))
 
116
        self.assertRaises(errors.RevisionNotPresent,
 
117
                          k.get_sha1, 0)
 
118
        self.assertRaises(errors.RevisionNotPresent,
 
119
                          k.get_sha1, 'text1')
 
120
                        
 
121
 
87
122
class InvalidAdd(TestBase):
88
123
    """Try to use invalid version number during add."""
89
124
    def runTest(self):
98
133
 
99
134
class RepeatedAdd(TestBase):
100
135
    """Add the same version twice; harmless."""
101
 
 
102
 
    def test_duplicate_add(self):
 
136
    def runTest(self):
103
137
        k = Weave()
104
138
        idx = k.add_lines('text0', [], TEXT_0)
105
139
        idx2 = k.add_lines('text0', [], TEXT_0)
121
155
                          'text0',
122
156
                          ['basis'],         # not the right parents
123
157
                          TEXT_0)
124
 
 
 
158
        
125
159
 
126
160
class InsertLines(TestBase):
127
161
    """Store a revision that adds one line to the original.
170
204
              ['text0', 'text1', 'text3'],
171
205
              ['line 1', 'aaa', 'middle line', 'bbb', 'line 2', 'ccc'])
172
206
 
173
 
        self.assertEqual(k.annotate('text4'),
 
207
        self.assertEqual(k.annotate('text4'), 
174
208
                         [('text0', 'line 1'),
175
209
                          ('text4', 'aaa'),
176
210
                          ('text3', 'middle line'),
189
223
        base_text = ['one', 'two', 'three', 'four']
190
224
 
191
225
        k.add_lines('text0', [], base_text)
192
 
 
 
226
        
193
227
        texts = [['one', 'two', 'three'],
194
228
                 ['two', 'three', 'four'],
195
229
                 ['one', 'four'],
226
260
                ]
227
261
        ################################### SKIPPED
228
262
        # Weave.get doesn't trap this anymore
229
 
        return
 
263
        return 
230
264
 
231
265
        self.assertRaises(WeaveFormatError,
232
266
                          k.get_lines,
233
 
                          0)
 
267
                          0)        
234
268
 
235
269
 
236
270
class CannedDelete(TestBase):
278
312
                'line to be deleted',
279
313
                (']', 1),
280
314
                ('{', 1),
281
 
                'replacement line',
 
315
                'replacement line',                
282
316
                ('}', 1),
283
317
                'last line',
284
318
                ('}', 0),
321
355
 
322
356
        ################################### SKIPPED
323
357
        # Weave.get doesn't trap this anymore
324
 
        return
 
358
        return 
325
359
 
326
360
 
327
361
        self.assertRaises(WeaveFormatError,
399
433
                          '  added in version 1',
400
434
                          '  also from v1',
401
435
                          '}'])
402
 
 
 
436
                       
403
437
        self.assertEqual(k.get_lines(2),
404
438
                         ['foo {',
405
439
                          '  added in v2',
411
445
                          '  added in v2',
412
446
                          '  also from v1',
413
447
                          '}'])
414
 
 
 
448
                         
415
449
 
416
450
class DeleteLines2(TestBase):
417
451
    """Test recording revisions that delete lines.
493
527
                ('}', 1),
494
528
                ('{', 2),
495
529
                "alternative second line",
496
 
                ('}', 2),
 
530
                ('}', 2),                
497
531
                ]
498
532
 
499
533
        k._sha1s = [sha_string('first line')
521
555
 
522
556
        text0 = ['cheddar', 'stilton', 'gruyere']
523
557
        text1 = ['cheddar', 'blue vein', 'neufchatel', 'chevre']
524
 
 
 
558
        
525
559
        k.add_lines('text0', [], text0)
526
560
        k.add_lines('text1', ['text0'], text1)
527
561
 
609
643
            A Jug of Wine, a Loaf of Bread, -- and Thou
610
644
            Beside me singing in the Wilderness --
611
645
            Oh, Wilderness were Paradise enow!""",
612
 
 
 
646
            
613
647
            """A Book of Verses underneath the Bough,
614
648
            A Jug of Wine, a Loaf of Bread, -- and Thou
615
649
            Beside me singing in the Wilderness --
657
691
        self.weave1.add_lines('v1', [], self.lines1)
658
692
        self.weave1.add_lines('v2', ['v1'], ['hello\n', 'world\n'])
659
693
        self.weave1.add_lines('v3', ['v2'], self.lines3)
 
694
        
 
695
    def test_join_empty(self):
 
696
        """Join two empty weaves."""
 
697
        eq = self.assertEqual
 
698
        w1 = Weave()
 
699
        w2 = Weave()
 
700
        w1.join(w2)
 
701
        eq(len(w1), 0)
 
702
        
 
703
    def test_join_empty_to_nonempty(self):
 
704
        """Join empty weave onto nonempty."""
 
705
        self.weave1.join(Weave())
 
706
        self.assertEqual(len(self.weave1), 3)
 
707
 
 
708
    def test_join_unrelated(self):
 
709
        """Join two weaves with no history in common."""
 
710
        wb = Weave()
 
711
        wb.add_lines('b1', [], ['line from b\n'])
 
712
        w1 = self.weave1
 
713
        w1.join(wb)
 
714
        eq = self.assertEqual
 
715
        eq(len(w1), 4)
 
716
        eq(sorted(w1.versions()),
 
717
           ['b1', 'v1', 'v2', 'v3'])
 
718
 
 
719
    def test_join_related(self):
 
720
        wa = self.weave1.copy()
 
721
        wb = self.weave1.copy()
 
722
        wa.add_lines('a1', ['v3'], ['hello\n', 'sweet\n', 'world\n'])
 
723
        wb.add_lines('b1', ['v3'], ['hello\n', 'pale blue\n', 'world\n'])
 
724
        eq = self.assertEquals
 
725
        eq(len(wa), 4)
 
726
        eq(len(wb), 4)
 
727
        wa.join(wb)
 
728
        eq(len(wa), 5)
 
729
        eq(wa.get_lines('b1'),
 
730
           ['hello\n', 'pale blue\n', 'world\n'])
 
731
 
 
732
    def test_join_parent_disagreement(self):
 
733
        #join reconciles differening parents into a union.
 
734
        wa = Weave()
 
735
        wb = Weave()
 
736
        wa.add_lines('v1', [], ['hello\n'])
 
737
        wb.add_lines('v0', [], [])
 
738
        wb.add_lines('v1', ['v0'], ['hello\n'])
 
739
        wa.join(wb)
 
740
        self.assertEqual(['v0'], wa.get_parents('v1'))
 
741
 
 
742
    def test_join_text_disagreement(self):
 
743
        """Cannot join weaves with different texts for a version."""
 
744
        wa = Weave()
 
745
        wb = Weave()
 
746
        wa.add_lines('v1', [], ['hello\n'])
 
747
        wb.add_lines('v1', [], ['not\n', 'hello\n'])
 
748
        self.assertRaises(WeaveError,
 
749
                          wa.join, wb)
 
750
 
 
751
    def test_join_unordered(self):
 
752
        """Join weaves where indexes differ.
 
753
        
 
754
        The source weave contains a different version at index 0."""
 
755
        wa = self.weave1.copy()
 
756
        wb = Weave()
 
757
        wb.add_lines('x1', [], ['line from x1\n'])
 
758
        wb.add_lines('v1', [], ['hello\n'])
 
759
        wb.add_lines('v2', ['v1'], ['hello\n', 'world\n'])
 
760
        wa.join(wb)
 
761
        eq = self.assertEquals
 
762
        eq(sorted(wa.versions()), ['v1', 'v2', 'v3', 'x1',])
 
763
        eq(wa.get_text('x1'), 'line from x1\n')
660
764
 
661
765
    def test_written_detection(self):
662
766
        # Test detection of weave file corruption.
707
811
        self.assertRaises(errors.WeaveInvalidChecksum, w.check)
708
812
 
709
813
 
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
814
class InstrumentedWeave(Weave):
726
815
    """Keep track of how many times functions are called."""
727
 
 
 
816
    
728
817
    def __init__(self, weave_name=None):
729
818
        self._extract_count = 0
730
819
        Weave.__init__(self, weave_name=weave_name)
734
823
        return Weave._extract(self, versions)
735
824
 
736
825
 
 
826
class JoinOptimization(TestCase):
 
827
    """Test that Weave.join() doesn't extract all texts, only what must be done."""
 
828
 
 
829
    def test_join(self):
 
830
        w1 = InstrumentedWeave()
 
831
        w2 = InstrumentedWeave()
 
832
 
 
833
        txt0 = ['a\n']
 
834
        txt1 = ['a\n', 'b\n']
 
835
        txt2 = ['a\n', 'c\n']
 
836
        txt3 = ['a\n', 'b\n', 'c\n']
 
837
 
 
838
        w1.add_lines('txt0', [], txt0) # extract 1a
 
839
        w2.add_lines('txt0', [], txt0) # extract 1b
 
840
        w1.add_lines('txt1', ['txt0'], txt1)# extract 2a
 
841
        w2.add_lines('txt2', ['txt0'], txt2)# extract 2b
 
842
        w1.join(w2) # extract 3a to add txt2 
 
843
        w2.join(w1) # extract 3b to add txt1 
 
844
 
 
845
        w1.add_lines('txt3', ['txt1', 'txt2'], txt3) # extract 4a 
 
846
        w2.add_lines('txt3', ['txt2', 'txt1'], txt3) # extract 4b
 
847
        # These secretly have inverted parents
 
848
 
 
849
        # This should not have to do any extractions
 
850
        w1.join(w2) # NO extract, texts already present with same parents
 
851
        w2.join(w1) # NO extract, texts already present with same parents
 
852
 
 
853
        self.assertEqual(4, w1._extract_count)
 
854
        self.assertEqual(4, w2._extract_count)
 
855
 
 
856
    def test_double_parent(self):
 
857
        # It should not be considered illegal to add
 
858
        # a revision with the same parent twice
 
859
        w1 = InstrumentedWeave()
 
860
        w2 = InstrumentedWeave()
 
861
 
 
862
        txt0 = ['a\n']
 
863
        txt1 = ['a\n', 'b\n']
 
864
        txt2 = ['a\n', 'c\n']
 
865
        txt3 = ['a\n', 'b\n', 'c\n']
 
866
 
 
867
        w1.add_lines('txt0', [], txt0)
 
868
        w2.add_lines('txt0', [], txt0)
 
869
        w1.add_lines('txt1', ['txt0'], txt1)
 
870
        w2.add_lines('txt1', ['txt0', 'txt0'], txt1)
 
871
        # Same text, effectively the same, because the
 
872
        # parent is only repeated
 
873
        w1.join(w2) # extract 3a to add txt2 
 
874
        w2.join(w1) # extract 3b to add txt1 
 
875
 
 
876
 
737
877
class TestNeedsReweave(TestCase):
738
878
    """Internal corner cases for when reweave is needed."""
739
879
 
750
890
        self.assertFalse(w1._compatible_parents(set(), set([1])))
751
891
        self.assertFalse(w1._compatible_parents(my_parents, set([1, 2, 3, 4])))
752
892
        self.assertFalse(w1._compatible_parents(my_parents, set([4])))
753
 
 
754
 
 
755
 
class TestWeaveFile(TestCaseInTempDir):
756
 
 
757
 
    def test_empty_file(self):
758
 
        f = open('empty.weave', 'wb+')
759
 
        try:
760
 
            self.assertRaises(errors.WeaveFormatError,
761
 
                              read_weave, f)
762
 
        finally:
763
 
            f.close()