~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to testweave.py

  • Committer: Martin Pool
  • Date: 2005-07-01 02:36:27 UTC
  • mto: This revision was merged to the branch mainline in revision 852.
  • Revision ID: mbp@sourcefrog.net-20050701023627-d8422b67a4c1d6d1
Show profile when converting inventory too.

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
 
 
22
20
 
23
21
 
24
22
"""test suite for weave algorithm"""
25
23
 
26
24
 
27
25
import testsweet
28
 
from bzrlib.weave import Weave, WeaveFormatError, WeaveError
29
 
from bzrlib.weavefile import write_weave, read_weave
30
 
from bzrlib.selftest import TestCase
 
26
from weave import Weave, WeaveFormatError
31
27
from pprint import pformat
32
28
 
33
29
 
 
30
 
34
31
try:
35
32
    set
36
33
    frozenset
49
46
 
50
47
 
51
48
 
52
 
class TestBase(TestCase):
 
49
class TestBase(testsweet.TestBase):
53
50
    def check_read_write(self, k):
54
51
        """Check the weave k can be written & re-read."""
55
52
        from tempfile import TemporaryFile
 
53
        from weavefile import write_weave, read_weave
56
54
        tf = TemporaryFile()
57
55
 
58
56
        write_weave(k, tf)
63
61
            tf.seek(0)
64
62
            self.log('serialized weave:')
65
63
            self.log(tf.read())
66
 
 
67
 
            self.log('')
68
 
            self.log('parents: %s' % (k._parents == k2._parents))
69
 
            self.log('         %r' % k._parents)
70
 
            self.log('         %r' % k2._parents)
71
 
            self.log('')
72
 
 
73
 
            
74
64
            self.fail('read/write check failed')
75
65
        
76
66
        
85
75
    """Store and retrieve a simple text."""
86
76
    def runTest(self):
87
77
        k = Weave()
88
 
        idx = k.add('text0', [], TEXT_0)
 
78
        idx = k.add([], TEXT_0)
89
79
        self.assertEqual(k.get(idx), TEXT_0)
90
80
        self.assertEqual(idx, 0)
91
81
 
94
84
class AnnotateOne(TestBase):
95
85
    def runTest(self):
96
86
        k = Weave()
97
 
        k.add('text0', [], TEXT_0)
 
87
        k.add([], TEXT_0)
98
88
        self.assertEqual(k.annotate(0),
99
89
                         [(0, TEXT_0[0])])
100
90
 
103
93
    def runTest(self):
104
94
        k = Weave()
105
95
 
106
 
        idx = k.add('text0', [], TEXT_0)
 
96
        idx = k.add([], TEXT_0)
107
97
        self.assertEqual(idx, 0)
108
98
 
109
 
        idx = k.add('text1', [], TEXT_1)
 
99
        idx = k.add([], TEXT_1)
110
100
        self.assertEqual(idx, 1)
111
101
 
112
102
        self.assertEqual(k.get(0), TEXT_0)
113
103
        self.assertEqual(k.get(1), TEXT_1)
114
104
 
 
105
        k.dump(self.TEST_LOG)
 
106
 
 
107
 
 
108
 
 
109
class DeltaAdd(TestBase):
 
110
    """Detection of changes prior to inserting new revision."""
 
111
    def runTest(self):
 
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)
115
139
 
116
140
 
117
141
class InvalidAdd(TestBase):
121
145
 
122
146
        self.assertRaises(IndexError,
123
147
                          k.add,
124
 
                          'text0',
125
148
                          [69],
126
149
                          ['new text!'])
127
150
 
128
151
 
129
 
class RepeatedAdd(TestBase):
130
 
    """Add the same version twice; harmless."""
131
 
    def runTest(self):
132
 
        k = Weave()
133
 
        idx = k.add('text0', [], TEXT_0)
134
 
        idx2 = k.add('text0', [], TEXT_0)
135
 
        self.assertEqual(idx, idx2)
136
 
 
137
 
 
138
 
 
139
 
class InvalidRepeatedAdd(TestBase):
140
 
    def runTest(self):
141
 
        k = Weave()
142
 
        idx = k.add('text0', [], TEXT_0)
143
 
        self.assertRaises(WeaveError,
144
 
                          k.add,
145
 
                          'text0',
146
 
                          [],
147
 
                          ['not the same text'])
148
 
        self.assertRaises(WeaveError,
149
 
                          k.add,
150
 
                          'text0',
151
 
                          [12],         # not the right parents
152
 
                          TEXT_0)
153
 
        
154
 
 
155
 
 
156
152
class InsertLines(TestBase):
157
153
    """Store a revision that adds one line to the original.
158
154
 
161
157
    def runTest(self):
162
158
        k = Weave()
163
159
 
164
 
        k.add('text0', [], ['line 1'])
165
 
        k.add('text1', [0], ['line 1', 'line 2'])
 
160
        k.add([], ['line 1'])
 
161
        k.add([0], ['line 1', 'line 2'])
166
162
 
167
163
        self.assertEqual(k.annotate(0),
168
164
                         [(0, 'line 1')])
175
171
                         [(0, 'line 1'),
176
172
                          (1, 'line 2')])
177
173
 
178
 
        k.add('text2', [0], ['line 1', 'diverged line'])
 
174
        k.add([0], ['line 1', 'diverged line'])
179
175
 
180
176
        self.assertEqual(k.annotate(2),
181
177
                         [(0, 'line 1'),
182
178
                          (2, 'diverged line')])
183
179
 
184
180
        text3 = ['line 1', 'middle line', 'line 2']
185
 
        k.add('text3',
186
 
              [0, 1],
 
181
        k.add([0, 1],
187
182
              text3)
188
183
 
189
 
        # 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))))
190
185
 
191
 
        self.log("k._weave=" + pformat(k._weave))
 
186
        self.log("k._l=" + pformat(k._l))
192
187
 
193
188
        self.assertEqual(k.annotate(3),
194
189
                         [(0, 'line 1'),
196
191
                          (1, 'line 2')])
197
192
 
198
193
        # now multiple insertions at different places
199
 
        k.add('text4',
200
 
              [0, 1, 3],
 
194
        k.add([0, 1, 3],
201
195
              ['line 1', 'aaa', 'middle line', 'bbb', 'line 2', 'ccc'])
202
196
 
203
197
        self.assertEqual(k.annotate(4), 
219
213
 
220
214
        base_text = ['one', 'two', 'three', 'four']
221
215
 
222
 
        k.add('text0', [], base_text)
 
216
        k.add([], base_text)
223
217
        
224
218
        texts = [['one', 'two', 'three'],
225
219
                 ['two', 'three', 'four'],
227
221
                 ['one', 'two', 'three', 'four'],
228
222
                 ]
229
223
 
230
 
        i = 1
231
224
        for t in texts:
232
 
            ver = k.add('text%d' % i,
233
 
                        [0], t)
234
 
            i += 1
 
225
            ver = k.add([0], t)
235
226
 
236
227
        self.log('final weave:')
237
 
        self.log('k._weave=' + pformat(k._weave))
 
228
        self.log('k._l=' + pformat(k._l))
238
229
 
239
230
        for i in range(len(texts)):
240
231
            self.assertEqual(k.get(i+1),
248
239
    def runTest(self):
249
240
        k = Weave()
250
241
 
251
 
        k._parents = [(),
 
242
        k._v = [(),
252
243
                ]
253
 
        k._weave = [('{', 0),
 
244
        k._l = [('{', 0),
254
245
                'first line',
255
246
                ('[', 0),
256
247
                'deleted in 0',
257
248
                (']', 0),
258
249
                ('}', 0),
259
250
                ]
260
 
        ################################### SKIPPED
261
 
        # Weave.get doesn't trap this anymore
262
 
        return 
263
251
 
264
252
        self.assertRaises(WeaveFormatError,
265
253
                          k.get,
272
260
    def runTest(self):
273
261
        k = Weave()
274
262
 
275
 
        k._parents = [(),
 
263
        k._v = [(),
276
264
                frozenset([0]),
277
265
                ]
278
 
        k._weave = [('{', 0),
 
266
        k._l = [('{', 0),
279
267
                'first line',
280
268
                ('[', 1),
281
269
                'line to be deleted',
302
290
    def runTest(self):
303
291
        k = Weave()
304
292
 
305
 
        k._parents = [frozenset(),
 
293
        k._v = [frozenset(),
306
294
                frozenset([0]),
307
295
                ]
308
 
        k._weave = [('{', 0),
 
296
        k._l = [('{', 0),
309
297
                'first line',
310
298
                ('[', 1),
311
299
                'line to be deleted',
336
324
    def runTest(self):
337
325
        k = Weave()
338
326
 
339
 
        k._parents = [frozenset(),
 
327
        k._v = [frozenset(),
340
328
                ]
341
 
        k._weave = ['bad line',
 
329
        k._l = ['bad line',
342
330
                ('{', 0),
343
331
                'foo {',
344
332
                ('{', 1),
351
339
                '}',
352
340
                ('}', 0)]
353
341
 
354
 
        ################################### SKIPPED
355
 
        # Weave.get doesn't trap this anymore
356
 
        return 
357
 
 
358
 
 
359
342
        self.assertRaises(WeaveFormatError,
360
343
                          k.get,
361
344
                          0)
366
349
    def runTest(self):
367
350
        k = Weave()
368
351
 
369
 
        k._parents = [frozenset(),
 
352
        k._v = [frozenset(),
370
353
                frozenset([0]),
371
354
                frozenset([0]),
372
355
                frozenset([0,1,2]),
373
356
                ]
374
 
        k._weave = [('{', 0),
 
357
        k._l = [('{', 0),
375
358
                'foo {',
376
359
                ('{', 1),
377
360
                '  added in version 1',
381
364
                ('}', 1),
382
365
                ('}', 0)]
383
366
 
384
 
 
385
 
        # this is not currently enforced by get
386
 
        return  ##########################################
387
 
 
388
367
        self.assertRaises(WeaveFormatError,
389
368
                          k.get,
390
369
                          0)
399
378
    def runTest(self):
400
379
        k = Weave()
401
380
 
402
 
        k._parents = [frozenset(),
 
381
        k._v = [frozenset(),
403
382
                frozenset([0]),
404
383
                frozenset([0]),
405
384
                frozenset([0,1,2]),
406
385
                ]
407
 
        k._weave = [('{', 0),
 
386
        k._l = [('{', 0),
408
387
                'foo {',
409
388
                ('{', 1),
410
389
                '  added in version 1',
448
427
    def runTest(self):
449
428
        k = Weave()
450
429
 
451
 
        k.add('text0', [], ["line the first",
 
430
        k.add([], ["line the first",
452
431
                   "line 2",
453
432
                   "line 3",
454
433
                   "fine"])
455
434
 
456
435
        self.assertEqual(len(k.get(0)), 4)
457
436
 
458
 
        k.add('text1', [0], ["line the first",
 
437
        k.add([0], ["line the first",
459
438
                   "fine"])
460
439
 
461
440
        self.assertEqual(k.get(1),
481
460
    def runTest(self):
482
461
        k = Weave()
483
462
 
484
 
        k._parents = [frozenset(), frozenset([0])]
485
 
        k._weave = [('{', 0),
 
463
        k._v = [frozenset(), frozenset([0])]
 
464
        k._l = [('{', 0),
486
465
                "first line",
487
466
                ('}', 0),
488
467
                ('{', 1),
496
475
        self.assertEqual(k.get(0),
497
476
                         ["first line"])
498
477
 
 
478
        k.dump(self.TEST_LOG)
 
479
 
499
480
 
500
481
class DivergedIncludes(TestBase):
501
482
    """Weave with two diverged texts based on version 0.
503
484
    def runTest(self):
504
485
        k = Weave()
505
486
 
506
 
        k._parents = [frozenset(),
 
487
        k._v = [frozenset(),
507
488
                frozenset([0]),
508
489
                frozenset([0]),
509
490
                ]
510
 
        k._weave = [('{', 0),
 
491
        k._l = [('{', 0),
511
492
                "first line",
512
493
                ('}', 0),
513
494
                ('{', 1),
529
510
                         ["first line",
530
511
                          "alternative second line"])
531
512
 
532
 
        self.assertEqual(list(k.inclusions([2])),
533
 
                         [0, 2])
 
513
        self.assertEqual(k.inclusions([2]),
 
514
                         set([0, 2]))
534
515
 
535
516
 
536
517
 
541
522
        text0 = ['cheddar', 'stilton', 'gruyere']
542
523
        text1 = ['cheddar', 'blue vein', 'neufchatel', 'chevre']
543
524
        
544
 
        k.add('text0', [], text0)
545
 
        k.add('text1', [0], text1)
 
525
        k.add([], text0)
 
526
        k.add([0], text1)
546
527
 
547
 
        self.log('k._weave=' + pformat(k._weave))
 
528
        self.log('k._l=' + pformat(k._l))
548
529
 
549
530
        self.assertEqual(k.get(0), text0)
550
531
        self.assertEqual(k.get(1), text1)
552
533
 
553
534
 
554
535
class Merge(TestBase):
555
 
    """Storage of versions that merge diverged parents"""
 
536
    """Versions that merge diverged parents"""
556
537
    def runTest(self):
557
538
        k = Weave()
558
539
 
562
543
                 ['header', '', 'line from 1', 'fixup line', 'line from 2'],
563
544
                 ]
564
545
 
565
 
        k.add('text0', [], texts[0])
566
 
        k.add('text1', [0], texts[1])
567
 
        k.add('text2', [0], texts[2])
568
 
        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])
569
550
 
570
551
        for i, t in enumerate(texts):
571
552
            self.assertEqual(k.get(i), t)
578
559
                          (2, 'line from 2'),
579
560
                          ])
580
561
 
581
 
        self.assertEqual(list(k.inclusions([3])),
582
 
                         [0, 1, 2, 3])
 
562
        self.assertEqual(k.inclusions([3]),
 
563
                         set([0, 1, 2, 3]))
583
564
 
584
 
        self.log('k._weave=' + pformat(k._weave))
 
565
        self.log('k._l=' + pformat(k._l))
585
566
 
586
567
        self.check_read_write(k)
587
568
 
588
569
 
589
 
class Conflicts(TestBase):
590
 
    """Test detection of conflicting regions during a merge.
591
 
 
592
 
    A base version is inserted, then two descendents try to
593
 
    insert different lines in the same place.  These should be
594
 
    reported as a possible conflict and forwarded to the user."""
595
 
    def runTest(self):
596
 
        return  # NOT RUN
597
 
        k = Weave()
598
 
 
599
 
        k.add([], ['aaa', 'bbb'])
600
 
        k.add([0], ['aaa', '111', 'bbb'])
601
 
        k.add([1], ['aaa', '222', 'bbb'])
602
 
 
603
 
        merged = k.merge([1, 2])
604
 
 
605
 
        self.assertEquals([[['aaa']],
606
 
                           [['111'], ['222']],
607
 
                           [['bbb']]])
608
 
 
609
 
 
610
 
 
611
 
class NonConflict(TestBase):
612
 
    """Two descendants insert compatible changes.
613
 
 
614
 
    No conflict should be reported."""
615
 
    def runTest(self):
616
 
        return  # NOT RUN
617
 
        k = Weave()
618
 
 
619
 
        k.add([], ['aaa', 'bbb'])
620
 
        k.add([0], ['111', 'aaa', 'ccc', 'bbb'])
621
 
        k.add([1], ['aaa', 'ccc', 'bbb', '222'])
622
 
 
623
 
    
624
 
    
625
 
 
626
 
 
627
570
class AutoMerge(TestBase):
628
571
    def runTest(self):
629
572
        k = Weave()
633
576
                 ['header', 'aaa', 'bbb', 'line from 2', 'more from 2'],
634
577
                 ]
635
578
 
636
 
        k.add('text0', [], texts[0])
637
 
        k.add('text1', [0], texts[1])
638
 
        k.add('text2', [0], texts[2])
639
 
 
640
 
        self.log('k._weave=' + pformat(k._weave))
641
 
 
642
 
        m = list(k.mash_iter([0, 1, 2]))
 
579
        k.add([], texts[0])
 
580
        k.add([0], texts[1])
 
581
        k.add([0], texts[2])
 
582
 
 
583
        self.log('k._l=' + pformat(k._l))
 
584
 
 
585
        m = list(k.merge_iter([0, 1, 2]))
643
586
 
644
587
        self.assertEqual(m,
645
588
                         ['header', 'aaa',
681
624
 
682
625
        k = Weave()
683
626
        parents = set()
684
 
        i = 0
685
627
        for t in texts:
686
 
            ver = k.add('text%d' % i,
687
 
                        list(parents), t)
 
628
            ver = k.add(list(parents), t)
688
629
            parents.add(ver)
689
 
            i += 1
690
630
 
691
 
        self.log("k._weave=" + pformat(k._weave))
 
631
        self.log("k._l=" + pformat(k._l))
692
632
 
693
633
        for i, t in enumerate(texts):
694
634
            self.assertEqual(k.get(i), t)
696
636
        self.check_read_write(k)
697
637
 
698
638
 
699
 
 
700
 
class MergeCases(TestBase):
701
 
    def doMerge(self, base, a, b, mp):
702
 
        from cStringIO import StringIO
703
 
        from textwrap import dedent
704
 
 
705
 
        def addcrlf(x):
706
 
            return x + '\n'
707
 
        
708
 
        w = Weave()
709
 
        w.add('text0', [], map(addcrlf, base))
710
 
        w.add('text1', [0], map(addcrlf, a))
711
 
        w.add('text2', [0], map(addcrlf, b))
712
 
 
713
 
        self.log('weave is:')
714
 
        tmpf = StringIO()
715
 
        write_weave(w, tmpf)
716
 
        self.log(tmpf.getvalue())
717
 
 
718
 
        self.log('merge plan:')
719
 
        p = list(w.plan_merge(1, 2))
720
 
        for state, line in p:
721
 
            if line:
722
 
                self.log('%12s | %s' % (state, line[:-1]))
723
 
 
724
 
        self.log('merge:')
725
 
        mt = StringIO()
726
 
        mt.writelines(w.weave_merge(p))
727
 
        mt.seek(0)
728
 
        self.log(mt.getvalue())
729
 
 
730
 
        mp = map(addcrlf, mp)
731
 
        self.assertEqual(mt.readlines(), mp)
732
 
        
733
 
        
734
 
    def testOneInsert(self):
735
 
        self.doMerge([],
736
 
                     ['aa'],
737
 
                     [],
738
 
                     ['aa'])
739
 
 
740
 
    def testSeparateInserts(self):
741
 
        self.doMerge(['aaa', 'bbb', 'ccc'],
742
 
                     ['aaa', 'xxx', 'bbb', 'ccc'],
743
 
                     ['aaa', 'bbb', 'yyy', 'ccc'],
744
 
                     ['aaa', 'xxx', 'bbb', 'yyy', 'ccc'])
745
 
 
746
 
    def testSameInsert(self):
747
 
        self.doMerge(['aaa', 'bbb', 'ccc'],
748
 
                     ['aaa', 'xxx', 'bbb', 'ccc'],
749
 
                     ['aaa', 'xxx', 'bbb', 'yyy', 'ccc'],
750
 
                     ['aaa', 'xxx', 'bbb', 'yyy', 'ccc'])
751
 
 
752
 
    def testOverlappedInsert(self):
753
 
        self.doMerge(['aaa', 'bbb'],
754
 
                     ['aaa', 'xxx', 'yyy', 'bbb'],
755
 
                     ['aaa', 'xxx', 'bbb'],
756
 
                     ['aaa', '<<<<', 'xxx', 'yyy', '====', 'xxx', '>>>>', 'bbb'])
757
 
 
758
 
        # really it ought to reduce this to 
759
 
        # ['aaa', 'xxx', 'yyy', 'bbb']
760
 
 
761
 
 
762
 
    def testClashReplace(self):
763
 
        self.doMerge(['aaa'],
764
 
                     ['xxx'],
765
 
                     ['yyy', 'zzz'],
766
 
                     ['<<<<', 'xxx', '====', 'yyy', 'zzz', '>>>>'])
767
 
 
768
 
    def testNonClashInsert(self):
769
 
        self.doMerge(['aaa'],
770
 
                     ['xxx', 'aaa'],
771
 
                     ['yyy', 'zzz'],
772
 
                     ['<<<<', 'xxx', 'aaa', '====', 'yyy', 'zzz', '>>>>'])
773
 
 
774
 
        self.doMerge(['aaa'],
775
 
                     ['aaa'],
776
 
                     ['yyy', 'zzz'],
777
 
                     ['yyy', 'zzz'])
778
 
 
779
 
 
780
 
    def testDeleteAndModify(self):
781
 
        """Clashing delete and modification.
782
 
 
783
 
        If one side modifies a region and the other deletes it then
784
 
        there should be a conflict with one side blank.
785
 
        """
786
 
 
787
 
        #######################################
788
 
        # skippd, not working yet
789
 
        return
790
 
        
791
 
        self.doMerge(['aaa', 'bbb', 'ccc'],
792
 
                     ['aaa', 'ddd', 'ccc'],
793
 
                     ['aaa', 'ccc'],
794
 
                     ['<<<<', 'aaa', '====', '>>>>', 'ccc'])
 
639
def testweave():
 
640
    import testsweet
 
641
    from unittest import TestSuite, TestLoader
 
642
    import testweave
 
643
 
 
644
    tl = TestLoader()
 
645
    suite = TestSuite()
 
646
    suite.addTest(tl.loadTestsFromModule(testweave))
795
647
    
 
648
    return int(not testsweet.run_suite(suite)) # for shell 0=true
796
649
 
797
650
 
798
651
if __name__ == '__main__':
799
652
    import sys
800
 
    import unittest
801
 
    sys.exit(unittest.main())
 
653
    sys.exit(testweave())
802
654