~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_weave.py

  • Committer: Aaron Bentley
  • Date: 2006-04-09 06:19:54 UTC
  • mto: This revision was merged to the branch mainline in revision 1649.
  • Revision ID: aaron.bentley@utoronto.ca-20060409061954-d0f04c8e0164a935
Implement single-file merge

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 --
648
682
        self.check_read_write(k)
649
683
 
650
684
 
 
685
class MergeCases(TestBase):
 
686
    def doMerge(self, base, a, b, mp):
 
687
        from cStringIO import StringIO
 
688
        from textwrap import dedent
 
689
 
 
690
        def addcrlf(x):
 
691
            return x + '\n'
 
692
        
 
693
        w = Weave()
 
694
        w.add_lines('text0', [], map(addcrlf, base))
 
695
        w.add_lines('text1', ['text0'], map(addcrlf, a))
 
696
        w.add_lines('text2', ['text0'], map(addcrlf, b))
 
697
 
 
698
        self.log('weave is:')
 
699
        tmpf = StringIO()
 
700
        write_weave(w, tmpf)
 
701
        self.log(tmpf.getvalue())
 
702
 
 
703
        self.log('merge plan:')
 
704
        p = list(w.plan_merge('text1', 'text2'))
 
705
        for state, line in p:
 
706
            if line:
 
707
                self.log('%12s | %s' % (state, line[:-1]))
 
708
 
 
709
        self.log('merge:')
 
710
        mt = StringIO()
 
711
        mt.writelines(w.weave_merge(p))
 
712
        mt.seek(0)
 
713
        self.log(mt.getvalue())
 
714
 
 
715
        mp = map(addcrlf, mp)
 
716
        self.assertEqual(mt.readlines(), mp)
 
717
        
 
718
        
 
719
    def testOneInsert(self):
 
720
        self.doMerge([],
 
721
                     ['aa'],
 
722
                     [],
 
723
                     ['aa'])
 
724
 
 
725
    def testSeparateInserts(self):
 
726
        self.doMerge(['aaa', 'bbb', 'ccc'],
 
727
                     ['aaa', 'xxx', 'bbb', 'ccc'],
 
728
                     ['aaa', 'bbb', 'yyy', 'ccc'],
 
729
                     ['aaa', 'xxx', 'bbb', 'yyy', 'ccc'])
 
730
 
 
731
    def testSameInsert(self):
 
732
        self.doMerge(['aaa', 'bbb', 'ccc'],
 
733
                     ['aaa', 'xxx', 'bbb', 'ccc'],
 
734
                     ['aaa', 'xxx', 'bbb', 'yyy', 'ccc'],
 
735
                     ['aaa', 'xxx', 'bbb', 'yyy', 'ccc'])
 
736
 
 
737
    def testOverlappedInsert(self):
 
738
        self.doMerge(['aaa', 'bbb'],
 
739
                     ['aaa', 'xxx', 'yyy', 'bbb'],
 
740
                     ['aaa', 'xxx', 'bbb'],
 
741
                     ['aaa', '<<<<<<< ', 'xxx', 'yyy', '=======', 'xxx', 
 
742
                      '>>>>>>> ', 'bbb'])
 
743
 
 
744
        # really it ought to reduce this to 
 
745
        # ['aaa', 'xxx', 'yyy', 'bbb']
 
746
 
 
747
 
 
748
    def testClashReplace(self):
 
749
        self.doMerge(['aaa'],
 
750
                     ['xxx'],
 
751
                     ['yyy', 'zzz'],
 
752
                     ['<<<<<<< ', 'xxx', '=======', 'yyy', 'zzz', 
 
753
                      '>>>>>>> '])
 
754
 
 
755
    def testNonClashInsert(self):
 
756
        self.doMerge(['aaa'],
 
757
                     ['xxx', 'aaa'],
 
758
                     ['yyy', 'zzz'],
 
759
                     ['<<<<<<< ', 'xxx', 'aaa', '=======', 'yyy', 'zzz', 
 
760
                      '>>>>>>> '])
 
761
 
 
762
        self.doMerge(['aaa'],
 
763
                     ['aaa'],
 
764
                     ['yyy', 'zzz'],
 
765
                     ['yyy', 'zzz'])
 
766
 
 
767
 
 
768
    def testDeleteAndModify(self):
 
769
        """Clashing delete and modification.
 
770
 
 
771
        If one side modifies a region and the other deletes it then
 
772
        there should be a conflict with one side blank.
 
773
        """
 
774
 
 
775
        #######################################
 
776
        # skippd, not working yet
 
777
        return
 
778
        
 
779
        self.doMerge(['aaa', 'bbb', 'ccc'],
 
780
                     ['aaa', 'ddd', 'ccc'],
 
781
                     ['aaa', 'ccc'],
 
782
                     ['<<<<<<<< ', 'aaa', '=======', '>>>>>>> ', 'ccc'])
 
783
 
 
784
    def _test_merge_from_strings(self, base, a, b, expected):
 
785
        w = Weave()
 
786
        w.add_lines('text0', [], base.splitlines(True))
 
787
        w.add_lines('text1', ['text0'], a.splitlines(True))
 
788
        w.add_lines('text2', ['text0'], b.splitlines(True))
 
789
        self.log('merge plan:')
 
790
        p = list(w.plan_merge('text1', 'text2'))
 
791
        for state, line in p:
 
792
            if line:
 
793
                self.log('%12s | %s' % (state, line[:-1]))
 
794
        self.log('merge result:')
 
795
        result_text = ''.join(w.weave_merge(p))
 
796
        self.log(result_text)
 
797
        self.assertEqualDiff(result_text, expected)
 
798
 
 
799
    def test_deletion_extended(self):
 
800
        """One side deletes, the other deletes more.
 
801
        """
 
802
        base = """\
 
803
            line 1
 
804
            line 2
 
805
            line 3
 
806
            """
 
807
        a = """\
 
808
            line 1
 
809
            line 2
 
810
            """
 
811
        b = """\
 
812
            line 1
 
813
            """
 
814
        result = """\
 
815
            line 1
 
816
            """
 
817
        self._test_merge_from_strings(base, a, b, result)
 
818
 
 
819
    def test_deletion_overlap(self):
 
820
        """Delete overlapping regions with no other conflict.
 
821
 
 
822
        Arguably it'd be better to treat these as agreement, rather than 
 
823
        conflict, but for now conflict is safer.
 
824
        """
 
825
        base = """\
 
826
            start context
 
827
            int a() {}
 
828
            int b() {}
 
829
            int c() {}
 
830
            end context
 
831
            """
 
832
        a = """\
 
833
            start context
 
834
            int a() {}
 
835
            end context
 
836
            """
 
837
        b = """\
 
838
            start context
 
839
            int c() {}
 
840
            end context
 
841
            """
 
842
        result = """\
 
843
            start context
 
844
<<<<<<< 
 
845
            int a() {}
 
846
=======
 
847
            int c() {}
 
848
>>>>>>> 
 
849
            end context
 
850
            """
 
851
        self._test_merge_from_strings(base, a, b, result)
 
852
 
 
853
    def test_agreement_deletion(self):
 
854
        """Agree to delete some lines, without conflicts."""
 
855
        base = """\
 
856
            start context
 
857
            base line 1
 
858
            base line 2
 
859
            end context
 
860
            """
 
861
        a = """\
 
862
            start context
 
863
            base line 1
 
864
            end context
 
865
            """
 
866
        b = """\
 
867
            start context
 
868
            base line 1
 
869
            end context
 
870
            """
 
871
        result = """\
 
872
            start context
 
873
            base line 1
 
874
            end context
 
875
            """
 
876
        self._test_merge_from_strings(base, a, b, result)
 
877
 
 
878
    def test_sync_on_deletion(self):
 
879
        """Specific case of merge where we can synchronize incorrectly.
 
880
        
 
881
        A previous version of the weave merge concluded that the two versions
 
882
        agreed on deleting line 2, and this could be a synchronization point.
 
883
        Line 1 was then considered in isolation, and thought to be deleted on 
 
884
        both sides.
 
885
 
 
886
        It's better to consider the whole thing as a disagreement region.
 
887
        """
 
888
        base = """\
 
889
            start context
 
890
            base line 1
 
891
            base line 2
 
892
            end context
 
893
            """
 
894
        a = """\
 
895
            start context
 
896
            base line 1
 
897
            a's replacement line 2
 
898
            end context
 
899
            """
 
900
        b = """\
 
901
            start context
 
902
            b replaces
 
903
            both lines
 
904
            end context
 
905
            """
 
906
        result = """\
 
907
            start context
 
908
<<<<<<< 
 
909
            base line 1
 
910
            a's replacement line 2
 
911
=======
 
912
            b replaces
 
913
            both lines
 
914
>>>>>>> 
 
915
            end context
 
916
            """
 
917
        self._test_merge_from_strings(base, a, b, result)
 
918
 
 
919
 
651
920
class JoinWeavesTests(TestBase):
652
921
    def setUp(self):
653
922
        super(JoinWeavesTests, self).setUp()
657
926
        self.weave1.add_lines('v1', [], self.lines1)
658
927
        self.weave1.add_lines('v2', ['v1'], ['hello\n', 'world\n'])
659
928
        self.weave1.add_lines('v3', ['v2'], self.lines3)
 
929
        
 
930
    def test_join_empty(self):
 
931
        """Join two empty weaves."""
 
932
        eq = self.assertEqual
 
933
        w1 = Weave()
 
934
        w2 = Weave()
 
935
        w1.join(w2)
 
936
        eq(len(w1), 0)
 
937
        
 
938
    def test_join_empty_to_nonempty(self):
 
939
        """Join empty weave onto nonempty."""
 
940
        self.weave1.join(Weave())
 
941
        self.assertEqual(len(self.weave1), 3)
 
942
 
 
943
    def test_join_unrelated(self):
 
944
        """Join two weaves with no history in common."""
 
945
        wb = Weave()
 
946
        wb.add_lines('b1', [], ['line from b\n'])
 
947
        w1 = self.weave1
 
948
        w1.join(wb)
 
949
        eq = self.assertEqual
 
950
        eq(len(w1), 4)
 
951
        eq(sorted(w1.versions()),
 
952
           ['b1', 'v1', 'v2', 'v3'])
 
953
 
 
954
    def test_join_related(self):
 
955
        wa = self.weave1.copy()
 
956
        wb = self.weave1.copy()
 
957
        wa.add_lines('a1', ['v3'], ['hello\n', 'sweet\n', 'world\n'])
 
958
        wb.add_lines('b1', ['v3'], ['hello\n', 'pale blue\n', 'world\n'])
 
959
        eq = self.assertEquals
 
960
        eq(len(wa), 4)
 
961
        eq(len(wb), 4)
 
962
        wa.join(wb)
 
963
        eq(len(wa), 5)
 
964
        eq(wa.get_lines('b1'),
 
965
           ['hello\n', 'pale blue\n', 'world\n'])
 
966
 
 
967
    def test_join_parent_disagreement(self):
 
968
        #join reconciles differening parents into a union.
 
969
        wa = Weave()
 
970
        wb = Weave()
 
971
        wa.add_lines('v1', [], ['hello\n'])
 
972
        wb.add_lines('v0', [], [])
 
973
        wb.add_lines('v1', ['v0'], ['hello\n'])
 
974
        wa.join(wb)
 
975
        self.assertEqual(['v0'], wa.get_parents('v1'))
 
976
 
 
977
    def test_join_text_disagreement(self):
 
978
        """Cannot join weaves with different texts for a version."""
 
979
        wa = Weave()
 
980
        wb = Weave()
 
981
        wa.add_lines('v1', [], ['hello\n'])
 
982
        wb.add_lines('v1', [], ['not\n', 'hello\n'])
 
983
        self.assertRaises(WeaveError,
 
984
                          wa.join, wb)
 
985
 
 
986
    def test_join_unordered(self):
 
987
        """Join weaves where indexes differ.
 
988
        
 
989
        The source weave contains a different version at index 0."""
 
990
        wa = self.weave1.copy()
 
991
        wb = Weave()
 
992
        wb.add_lines('x1', [], ['line from x1\n'])
 
993
        wb.add_lines('v1', [], ['hello\n'])
 
994
        wb.add_lines('v2', ['v1'], ['hello\n', 'world\n'])
 
995
        wa.join(wb)
 
996
        eq = self.assertEquals
 
997
        eq(sorted(wa.versions()), ['v1', 'v2', 'v3', 'x1',])
 
998
        eq(wa.get_text('x1'), 'line from x1\n')
660
999
 
661
1000
    def test_written_detection(self):
662
1001
        # Test detection of weave file corruption.
707
1046
        self.assertRaises(errors.WeaveInvalidChecksum, w.check)
708
1047
 
709
1048
 
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
1049
class InstrumentedWeave(Weave):
726
1050
    """Keep track of how many times functions are called."""
727
 
 
 
1051
    
728
1052
    def __init__(self, weave_name=None):
729
1053
        self._extract_count = 0
730
1054
        Weave.__init__(self, weave_name=weave_name)
734
1058
        return Weave._extract(self, versions)
735
1059
 
736
1060
 
 
1061
class JoinOptimization(TestCase):
 
1062
    """Test that Weave.join() doesn't extract all texts, only what must be done."""
 
1063
 
 
1064
    def test_join(self):
 
1065
        w1 = InstrumentedWeave()
 
1066
        w2 = InstrumentedWeave()
 
1067
 
 
1068
        txt0 = ['a\n']
 
1069
        txt1 = ['a\n', 'b\n']
 
1070
        txt2 = ['a\n', 'c\n']
 
1071
        txt3 = ['a\n', 'b\n', 'c\n']
 
1072
 
 
1073
        w1.add_lines('txt0', [], txt0) # extract 1a
 
1074
        w2.add_lines('txt0', [], txt0) # extract 1b
 
1075
        w1.add_lines('txt1', ['txt0'], txt1)# extract 2a
 
1076
        w2.add_lines('txt2', ['txt0'], txt2)# extract 2b
 
1077
        w1.join(w2) # extract 3a to add txt2 
 
1078
        w2.join(w1) # extract 3b to add txt1 
 
1079
 
 
1080
        w1.add_lines('txt3', ['txt1', 'txt2'], txt3) # extract 4a 
 
1081
        w2.add_lines('txt3', ['txt2', 'txt1'], txt3) # extract 4b
 
1082
        # These secretly have inverted parents
 
1083
 
 
1084
        # This should not have to do any extractions
 
1085
        w1.join(w2) # NO extract, texts already present with same parents
 
1086
        w2.join(w1) # NO extract, texts already present with same parents
 
1087
 
 
1088
        self.assertEqual(4, w1._extract_count)
 
1089
        self.assertEqual(4, w2._extract_count)
 
1090
 
 
1091
    def test_double_parent(self):
 
1092
        # It should not be considered illegal to add
 
1093
        # a revision with the same parent twice
 
1094
        w1 = InstrumentedWeave()
 
1095
        w2 = InstrumentedWeave()
 
1096
 
 
1097
        txt0 = ['a\n']
 
1098
        txt1 = ['a\n', 'b\n']
 
1099
        txt2 = ['a\n', 'c\n']
 
1100
        txt3 = ['a\n', 'b\n', 'c\n']
 
1101
 
 
1102
        w1.add_lines('txt0', [], txt0)
 
1103
        w2.add_lines('txt0', [], txt0)
 
1104
        w1.add_lines('txt1', ['txt0'], txt1)
 
1105
        w2.add_lines('txt1', ['txt0', 'txt0'], txt1)
 
1106
        # Same text, effectively the same, because the
 
1107
        # parent is only repeated
 
1108
        w1.join(w2) # extract 3a to add txt2 
 
1109
        w2.join(w1) # extract 3b to add txt1 
 
1110
 
 
1111
 
737
1112
class TestNeedsReweave(TestCase):
738
1113
    """Internal corner cases for when reweave is needed."""
739
1114
 
750
1125
        self.assertFalse(w1._compatible_parents(set(), set([1])))
751
1126
        self.assertFalse(w1._compatible_parents(my_parents, set([1, 2, 3, 4])))
752
1127
        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()